changeset 759:d3eb054172f9

Added copy of druntime from DMD 2.020 modified for LDC.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 11 Nov 2008 01:52:37 +0100
parents f04dde6e882c
children 6f33b427bfd1
files bin/ldc2.conf druntime/import/ldc/cstdarg.di druntime/import/ldc/intrinsics.di druntime/license.txt druntime/readme.txt druntime/src/build-dmd.bat druntime/src/build-dmd.sh druntime/src/build-ldc.sh druntime/src/common/core/bitmanip.d druntime/src/common/core/exception.d druntime/src/common/core/memory.d druntime/src/common/core/runtime.d druntime/src/common/core/thread.d druntime/src/common/ldc.mak druntime/src/common/posix.mak druntime/src/common/stdc/errno.c druntime/src/common/win32.mak druntime/src/compiler/dmd/aApply.d druntime/src/compiler/dmd/aApplyR.d druntime/src/compiler/dmd/aaA.d druntime/src/compiler/dmd/adi.d druntime/src/compiler/dmd/alloca.d druntime/src/compiler/dmd/arrayassign.d druntime/src/compiler/dmd/arraybyte.d druntime/src/compiler/dmd/arraycast.d druntime/src/compiler/dmd/arraycat.d druntime/src/compiler/dmd/arraydouble.d druntime/src/compiler/dmd/arrayfloat.d druntime/src/compiler/dmd/arrayint.d druntime/src/compiler/dmd/arrayreal.d druntime/src/compiler/dmd/arrayshort.d druntime/src/compiler/dmd/cast_.d druntime/src/compiler/dmd/cmath2.d druntime/src/compiler/dmd/compiler.d druntime/src/compiler/dmd/complex.c druntime/src/compiler/dmd/cover.d druntime/src/compiler/dmd/critical.c druntime/src/compiler/dmd/deh.c druntime/src/compiler/dmd/deh2.d druntime/src/compiler/dmd/dmain2.d druntime/src/compiler/dmd/invariant.d druntime/src/compiler/dmd/invariant_.d druntime/src/compiler/dmd/lifetime.d druntime/src/compiler/dmd/llmath.d druntime/src/compiler/dmd/mars.h druntime/src/compiler/dmd/memory.d druntime/src/compiler/dmd/memset.d druntime/src/compiler/dmd/minit.asm druntime/src/compiler/dmd/minit.obj druntime/src/compiler/dmd/monitor.c druntime/src/compiler/dmd/obj.d druntime/src/compiler/dmd/object_.d druntime/src/compiler/dmd/posix.mak druntime/src/compiler/dmd/qsort.d druntime/src/compiler/dmd/qsort2.d druntime/src/compiler/dmd/switch_.d druntime/src/compiler/dmd/trace.d druntime/src/compiler/dmd/typeinfo/ti_AC.d druntime/src/compiler/dmd/typeinfo/ti_Acdouble.d druntime/src/compiler/dmd/typeinfo/ti_Acfloat.d druntime/src/compiler/dmd/typeinfo/ti_Acreal.d druntime/src/compiler/dmd/typeinfo/ti_Adouble.d druntime/src/compiler/dmd/typeinfo/ti_Afloat.d druntime/src/compiler/dmd/typeinfo/ti_Ag.d druntime/src/compiler/dmd/typeinfo/ti_Aint.d druntime/src/compiler/dmd/typeinfo/ti_Along.d druntime/src/compiler/dmd/typeinfo/ti_Areal.d druntime/src/compiler/dmd/typeinfo/ti_Ashort.d druntime/src/compiler/dmd/typeinfo/ti_C.d druntime/src/compiler/dmd/typeinfo/ti_byte.d druntime/src/compiler/dmd/typeinfo/ti_cdouble.d druntime/src/compiler/dmd/typeinfo/ti_cfloat.d druntime/src/compiler/dmd/typeinfo/ti_char.d druntime/src/compiler/dmd/typeinfo/ti_creal.d druntime/src/compiler/dmd/typeinfo/ti_dchar.d druntime/src/compiler/dmd/typeinfo/ti_delegate.d druntime/src/compiler/dmd/typeinfo/ti_double.d druntime/src/compiler/dmd/typeinfo/ti_float.d druntime/src/compiler/dmd/typeinfo/ti_idouble.d druntime/src/compiler/dmd/typeinfo/ti_ifloat.d druntime/src/compiler/dmd/typeinfo/ti_int.d druntime/src/compiler/dmd/typeinfo/ti_ireal.d druntime/src/compiler/dmd/typeinfo/ti_long.d druntime/src/compiler/dmd/typeinfo/ti_ptr.d druntime/src/compiler/dmd/typeinfo/ti_real.d druntime/src/compiler/dmd/typeinfo/ti_short.d druntime/src/compiler/dmd/typeinfo/ti_ubyte.d druntime/src/compiler/dmd/typeinfo/ti_uint.d druntime/src/compiler/dmd/typeinfo/ti_ulong.d druntime/src/compiler/dmd/typeinfo/ti_ushort.d druntime/src/compiler/dmd/typeinfo/ti_void.d druntime/src/compiler/dmd/typeinfo/ti_wchar.d druntime/src/compiler/dmd/util/console.d druntime/src/compiler/dmd/util/cpuid.d druntime/src/compiler/dmd/util/ctype.d druntime/src/compiler/dmd/util/string.d druntime/src/compiler/dmd/util/utf.d druntime/src/compiler/dmd/win32.mak druntime/src/compiler/ldc/aApply.d druntime/src/compiler/ldc/aApplyR.d druntime/src/compiler/ldc/aaA.d druntime/src/compiler/ldc/adi.d druntime/src/compiler/ldc/arrayInit.d druntime/src/compiler/ldc/cast.d druntime/src/compiler/ldc/critical.c druntime/src/compiler/ldc/dmain2.d druntime/src/compiler/ldc/eh.d druntime/src/compiler/ldc/genobj.d druntime/src/compiler/ldc/invariant.d druntime/src/compiler/ldc/ldc.mak druntime/src/compiler/ldc/ldc/bitmanip.d druntime/src/compiler/ldc/ldc/vararg.d druntime/src/compiler/ldc/lifetime.d druntime/src/compiler/ldc/mars.h druntime/src/compiler/ldc/memory.d druntime/src/compiler/ldc/monitor.c druntime/src/compiler/ldc/qsort2.d druntime/src/compiler/ldc/switch.d druntime/src/compiler/ldc/typeinfo/ti_AC.d druntime/src/compiler/ldc/typeinfo/ti_Acdouble.d druntime/src/compiler/ldc/typeinfo/ti_Acfloat.d druntime/src/compiler/ldc/typeinfo/ti_Acreal.d druntime/src/compiler/ldc/typeinfo/ti_Adouble.d druntime/src/compiler/ldc/typeinfo/ti_Afloat.d druntime/src/compiler/ldc/typeinfo/ti_Ag.d druntime/src/compiler/ldc/typeinfo/ti_Aint.d druntime/src/compiler/ldc/typeinfo/ti_Along.d druntime/src/compiler/ldc/typeinfo/ti_Areal.d druntime/src/compiler/ldc/typeinfo/ti_Ashort.d druntime/src/compiler/ldc/typeinfo/ti_C.d druntime/src/compiler/ldc/typeinfo/ti_byte.d druntime/src/compiler/ldc/typeinfo/ti_cdouble.d druntime/src/compiler/ldc/typeinfo/ti_cfloat.d druntime/src/compiler/ldc/typeinfo/ti_char.d druntime/src/compiler/ldc/typeinfo/ti_creal.d druntime/src/compiler/ldc/typeinfo/ti_dchar.d druntime/src/compiler/ldc/typeinfo/ti_delegate.d druntime/src/compiler/ldc/typeinfo/ti_double.d druntime/src/compiler/ldc/typeinfo/ti_float.d druntime/src/compiler/ldc/typeinfo/ti_idouble.d druntime/src/compiler/ldc/typeinfo/ti_ifloat.d druntime/src/compiler/ldc/typeinfo/ti_int.d druntime/src/compiler/ldc/typeinfo/ti_ireal.d druntime/src/compiler/ldc/typeinfo/ti_long.d druntime/src/compiler/ldc/typeinfo/ti_ptr.d druntime/src/compiler/ldc/typeinfo/ti_real.d druntime/src/compiler/ldc/typeinfo/ti_short.d druntime/src/compiler/ldc/typeinfo/ti_ubyte.d druntime/src/compiler/ldc/typeinfo/ti_uint.d druntime/src/compiler/ldc/typeinfo/ti_ulong.d druntime/src/compiler/ldc/typeinfo/ti_ushort.d druntime/src/compiler/ldc/typeinfo/ti_void.d druntime/src/compiler/ldc/typeinfo/ti_wchar.d druntime/src/compiler/ldc/util/console.d druntime/src/compiler/ldc/util/ctype.d druntime/src/compiler/ldc/util/string.d druntime/src/compiler/ldc/util/utf.d druntime/src/dmd-posix.mak druntime/src/dmd-win32.mak druntime/src/dmd.conf druntime/src/gc/basic/gc.d druntime/src/gc/basic/gcalloc.d druntime/src/gc/basic/gcbits.d druntime/src/gc/basic/gcstats.d druntime/src/gc/basic/gcx.d druntime/src/gc/basic/ldc.mak druntime/src/gc/basic/posix.mak druntime/src/gc/basic/win32.mak druntime/src/gc/stub/gc.d druntime/src/gc/stub/ldc.mak druntime/src/gc/stub/posix.mak druntime/src/gc/stub/win32.mak druntime/src/ldc-gcc.mak druntime/src/ldc2.conf druntime/src/sc.ini
diffstat 175 files changed, 48069 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/ldc2.conf	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,4 @@
+
+[Environment]
+
+DFLAGS=-I%@P%/../druntime/import -L-L%@P%/../druntime/lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/import/ldc/cstdarg.di	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,29 @@
+/*
+ * vararg support for extern(C) functions
+ */
+
+module ldc.cstdarg;
+
+// Check for the right compiler
+version(LDC)
+{
+    // OK
+}
+else
+{
+    static assert(false, "This module is only valid for LDC");
+}
+
+alias void* va_list;
+
+pragma(va_start)
+    void va_start(T)(va_list ap, ref T);
+
+pragma(va_arg)
+    T va_arg(T)(va_list ap);
+
+pragma(va_end)
+    void va_end(va_list args);
+
+pragma(va_copy)
+    void va_copy(va_list dst, va_list src);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/import/ldc/intrinsics.di	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,343 @@
+/*
+ * This module holds declarations to LLVM intrinsics.
+ *
+ * See the LLVM language reference for more information:
+ *
+ * - http://llvm.org/docs/LangRef.html#intrinsics
+ *
+ */
+
+module ldc.intrinsics;
+
+// Check for the right compiler
+version(LDC)
+{
+    // OK
+}
+else
+{
+    static assert(false, "This module is only valid for LDC");
+}
+
+//
+// CODE GENERATOR INTRINSICS
+//
+
+
+// The 'llvm.returnaddress' intrinsic attempts to compute a target-specific value indicating the return address of the current function or one of its callers. 
+
+pragma(intrinsic, "llvm.returnaddress")
+    void* llvm_returnaddress(uint level);
+
+
+// The 'llvm.frameaddress' intrinsic attempts to return the target-specific frame pointer value for the specified stack frame. 
+
+pragma(intrinsic, "llvm.frameaddress")
+    void* llvm_frameaddress(uint level);
+
+
+// The 'llvm.stacksave' intrinsic is used to remember the current state of the function stack, for use with llvm.stackrestore. This is useful for implementing language features like scoped automatic variable sized arrays in C99. 
+
+pragma(intrinsic, "llvm.stacksave")
+    void* llvm_stacksave();
+
+
+// The 'llvm.stackrestore' intrinsic is used to restore the state of the function stack to the state it was in when the corresponding llvm.stacksave intrinsic executed. This is useful for implementing language features like scoped automatic variable sized arrays in C99. 
+
+pragma(intrinsic, "llvm.stackrestore")
+    void llvm_stackrestore(void* ptr);
+
+
+// The 'llvm.prefetch' intrinsic is a hint to the code generator to insert a prefetch instruction if supported; otherwise, it is a noop. Prefetches have no effect on the behavior of the program but can change its performance characteristics.
+
+pragma(intrinsic, "llvm.prefetch")
+    void llvm_prefetch(void* ptr, uint rw, uint locality);
+
+
+// The 'llvm.pcmarker' intrinsic is a method to export a Program Counter (PC) in a region of code to simulators and other tools. The method is target specific, but it is expected that the marker will use exported symbols to transmit the PC of the marker. The marker makes no guarantees that it will remain with any specific instruction after optimizations. It is possible that the presence of a marker will inhibit optimizations. The intended use is to be inserted after optimizations to allow correlations of simulation runs. 
+
+pragma(intrinsic, "llvm.pcmarker")
+    void llvm_pcmarker(uint id);
+
+
+// The 'llvm.readcyclecounter' intrinsic provides access to the cycle counter register (or similar low latency, high accuracy clocks) on those targets that support it. On X86, it should map to RDTSC. On Alpha, it should map to RPCC. As the backing counters overflow quickly (on the order of 9 seconds on alpha), this should only be used for small timings. 
+
+pragma(intrinsic, "llvm.readcyclecounter")
+    ulong readcyclecounter();
+
+
+
+
+//
+// STANDARD C LIBRARY INTRINSICS
+//
+
+
+// The 'llvm.memcpy.*' intrinsics copy a block of memory from the source location to the destination location.
+// Note that, unlike the standard libc function, the llvm.memcpy.* intrinsics do not return a value, and takes an extra alignment argument.
+
+pragma(intrinsic, "llvm.memcpy.i32")
+    void llvm_memcpy_i32(void* dst, void* src, uint len, uint alignment);
+pragma(intrinsic, "llvm.memcpy.i64")
+    void llvm_memcpy_i64(void* dst, void* src, ulong len, uint alignment);
+
+
+// The 'llvm.memmove.*' intrinsics move a block of memory from the source location to the destination location. It is similar to the 'llvm.memcpy' intrinsic but allows the two memory locations to overlap.
+// Note that, unlike the standard libc function, the llvm.memmove.* intrinsics do not return a value, and takes an extra alignment argument.
+
+pragma(intrinsic, "llvm.memmove.i32")
+    void llvm_memmove_i32(void* dst, void* src, uint len, uint alignment);
+pragma(intrinsic, "llvm.memmove.i64")
+    void llvm_memmove_i64(void* dst, void* src, ulong len, int alignment);
+
+
+// The 'llvm.memset.*' intrinsics fill a block of memory with a particular byte value.
+// Note that, unlike the standard libc function, the llvm.memset intrinsic does not return a value, and takes an extra alignment argument.
+
+pragma(intrinsic, "llvm.memset.i32")
+    void llvm_memset_i32(void* dst, ubyte val, uint len, uint alignment);
+pragma(intrinsic, "llvm.memset.i64")
+    void llvm_memset_i64(void* dst, ubyte val, ulong len, uint alignment);
+
+
+// The 'llvm.sqrt' intrinsics return the sqrt of the specified operand, returning the same value as the libm 'sqrt' functions would. Unlike sqrt in libm, however, llvm.sqrt has undefined behavior for negative numbers other than -0.0 (which allows for better optimization, because there is no need to worry about errno being set). llvm.sqrt(-0.0) is defined to return -0.0 like IEEE sqrt. 
+
+pragma(intrinsic, "llvm.sqrt.f32")
+    float llvm_sqrt_f32(float val);
+pragma(intrinsic, "llvm.sqrt.f64")
+    double llvm_sqrt_f64(double val);
+version(X86)
+{
+pragma(intrinsic, "llvm.sqrt.f80")
+    real llvm_sqrt_f80(real val);
+}
+
+version(X86_64)
+{
+pragma(intrinsic, "llvm.sqrt.f80")
+    real llvm_sqrt_f80(real val);
+}
+
+
+// The 'llvm.sin.*' intrinsics return the sine of the operand. 
+
+pragma(intrinsic, "llvm.sin.f32")
+    float llvm_sin_f32(float val);
+pragma(intrinsic, "llvm.sin.f64")
+    double llvm_sin_f64(double val);
+version(X86)
+{
+pragma(intrinsic, "llvm.sin.f80")
+    real llvm_sin_f80(real val);
+}
+
+version(X86_64)
+{
+pragma(intrinsic, "llvm.sin.f80")
+    real llvm_sin_f80(real val);
+}
+
+
+// The 'llvm.cos.*' intrinsics return the cosine of the operand. 
+
+pragma(intrinsic, "llvm.cos.f32")
+    float llvm_cos_f32(float val);
+pragma(intrinsic, "llvm.cos.f64")
+    double llvm_cos_f64(double val);
+version(X86)
+{
+pragma(intrinsic, "llvm.cos.f80")
+    real llvm_cos_f80(real val);
+}
+
+version(X86_64)
+{
+pragma(intrinsic, "llvm.cos.f80")
+    real llvm_cos_f80(real val);
+}
+
+
+// The 'llvm.powi.*' intrinsics return the first operand raised to the specified (positive or negative) power. The order of evaluation of multiplications is not defined. When a vector of floating point type is used, the second argument remains a scalar integer value. 
+
+pragma(intrinsic, "llvm.powi.f32")
+    float llvm_powi_f32(float val, int power);
+
+pragma(intrinsic, "llvm.powi.f64")
+    double llvm_powi_f64(double val, int power);
+version(X86)
+{
+pragma(intrinsic, "llvm.powi.f80")
+    real llvm_powi_f80(real val, int power);
+}
+
+version(X86_64)
+{
+pragma(intrinsic, "llvm.powi.f80")
+    real llvm_powi_f80(real val, int power);
+}
+
+// The 'llvm.pow.*' intrinsics return the first operand raised to the specified (positive or negative) power. 
+
+pragma(intrinsic, "llvm.pow.f32")
+    float llvm_pow_f32(float val, float power);
+
+pragma(intrinsic, "llvm.pow.f64")
+    double llvm_pow_f64(double val, double power);
+version(X86)
+{
+pragma(intrinsic, "llvm.pow.f80")
+    real llvm_pow_f80(real val, real power);
+}
+
+version(X86_64)
+{
+pragma(intrinsic, "llvm.pow.f80")
+    real llvm_pow_f80(real val, real power);
+}
+
+
+//
+// BIT MANIPULATION INTRINSICS
+//
+
+// The 'llvm.bswap' family of intrinsics is used to byte swap integer values with an even number of bytes (positive multiple of 16 bits). These are useful for performing operations on data that is not in the target's native byte order. 
+
+pragma(intrinsic, "llvm.bswap.i16.i16")
+    ushort llvm_bswap_i16(ushort val);
+
+pragma(intrinsic, "llvm.bswap.i32.i32")
+    uint llvm_bswap_i32(uint val);
+
+pragma(intrinsic, "llvm.bswap.i64.i64")
+    ulong llvm_bswap_i64(ulong val);
+
+
+// The 'llvm.ctpop' family of intrinsics counts the number of bits set in a value. 
+
+pragma(intrinsic, "llvm.ctpop.i8")
+    ubyte llvm_ctpop_i8(ubyte src);
+
+pragma(intrinsic, "llvm.ctpop.i16")
+    ushort llvm_ctpop_i16(ushort src);
+
+pragma(intrinsic, "llvm.ctpop.i32")
+    uint llvm_ctpop_i32(uint src);
+
+pragma(intrinsic, "llvm.ctpop.i64")
+    ulong llvm_ctpop_i64(ulong src);
+
+
+// The 'llvm.ctlz' family of intrinsic functions counts the number of leading zeros in a variable. 
+
+pragma(intrinsic, "llvm.ctlz.i8")
+    ubyte llvm_ctlz_i8(ubyte src);
+
+pragma(intrinsic, "llvm.ctlz.i16")
+    ushort llvm_ctlz_i16(ushort src);
+
+pragma(intrinsic, "llvm.ctlz.i32")
+    uint llvm_ctlz_i32(uint src);
+
+pragma(intrinsic, "llvm.ctlz.i64")
+    ulong llvm_ctlz_i64(ulong src);
+
+
+// The 'llvm.cttz' family of intrinsic functions counts the number of trailing zeros. 
+
+pragma(intrinsic, "llvm.cttz.i8")
+    ubyte llvm_cttz_i8(ubyte src);
+
+pragma(intrinsic, "llvm.cttz.i16")
+    ushort llvm_cttz_i16(ushort src);
+
+pragma(intrinsic, "llvm.cttz.i32")
+    uint llvm_cttz_i32(uint src);
+
+pragma(intrinsic, "llvm.cttz.i64")
+    ulong llvm_cttz_i64(ulong src);
+
+
+// The 'llvm.part.select' family of intrinsic functions selects a range of bits from an integer value and returns them in the same bit width as the original value.
+
+pragma(intrinsic, "llvm.part.select.i8")
+    ubyte llvm_part_select_i(ubyte val, uint loBit, uint hiBit);
+
+pragma(intrinsic, "llvm.part.select.i16")
+    ushort llvm_part_select_i(ushort val, uint loBit, uint hiBit);
+
+pragma(intrinsic, "llvm.part.select.i32")
+    uint llvm_part_select_i(uint val, uint loBit, uint hiBit);
+
+pragma(intrinsic, "llvm.part.select.i64")
+    ulong llvm_part_select_i(ulong val, uint loBit, uint hiBit);
+
+
+// The 'llvm.part.set' family of intrinsic functions replaces a range of bits in an integer value with another integer value. It returns the integer with the replaced bits.
+
+// TODO
+// declare i17 @llvm.part.set.i17.i9 (i17 %val, i9 %repl, i32 %lo, i32 %hi)
+// declare i29 @llvm.part.set.i29.i9 (i29 %val, i9 %repl, i32 %lo, i32 %hi)
+
+
+
+
+//
+// ATOMIC OPERATIONS AND SYNCHRONIZATION INTRINSICS
+//
+
+// The llvm.memory.barrier intrinsic guarantees ordering between specific pairs of memory access types.
+
+pragma(intrinsic, "llvm.memory.barrier")
+    void llvm_memory_barrier(bool ll, bool ls, bool sl, bool ss, bool device);
+
+// This loads a value in memory and compares it to a given value. If they are equal, it stores a new value into the memory.
+
+pragma(intrinsic, "llvm.atomic.cmp.swap.i#.p0i#")
+    T llvm_atomic_cmp_swap(T)(T* ptr, T cmp, T val);
+
+// This intrinsic loads the value stored in memory at ptr and yields the value from memory. It then stores the value in val in the memory at ptr.
+
+pragma(intrinsic, "llvm.atomic.swap.i#.p0i#")
+    T llvm_atomic_swap(T)(T* ptr, T val);
+
+// This intrinsic adds delta to the value stored in memory at ptr. It yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.add.i#.p0i#")
+    T llvm_atomic_load_add(T)(T* ptr, T val);
+
+// This intrinsic subtracts delta to the value stored in memory at ptr. It yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.sub.i#.p0i#")
+    T llvm_atomic_load_sub(T)(T* ptr, T val);
+
+// These intrinsics bitwise the operation (and, nand, or, xor) delta to the value stored in memory at ptr. It yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.and.i#.p0i#")
+    T llvm_atomic_load_and(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.nand.i#.p0i#")
+    T llvm_atomic_load_nand(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.or.i#.p0i#")
+    T llvm_atomic_load_or(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.xor.i#.p0i#")
+    T llvm_atomic_load_xor(T)(T* ptr, T val);
+
+// These intrinsics takes the signed or unsigned minimum or maximum of delta and the value stored in memory at ptr. It yields the original value at ptr. 
+
+pragma(intrinsic, "llvm.atomic.load.max.i#.p0i#")
+    T llvm_atomic_load_max(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.min.i#.p0i#")
+    T llvm_atomic_load_min(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.umax.i#.p0i#")
+    T llvm_atomic_load_umax(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.umin.i#.p0i#")
+    T llvm_atomic_load_umin(T)(T* ptr, T val);
+
+//
+// GENERAL INTRINSICS
+//
+
+
+// This intrinsics is lowered to the target dependent trap instruction. If the target does not have a trap instruction, this intrinsic will be lowered to the call of the abort() function. 
+
+pragma(intrinsic, "llvm.trap")
+    void llvm_trap();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/license.txt	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,10 @@
+Copyright (c) 2008, The D Runtime Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/readme.txt	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,10 @@
+	Druntime
+
+The source code repository for druntime is: http://dsource.org/projects/druntime
+
+Druntime is the minimum library required to support the D programming
+language. It includes the system code required to support the garbage collector,
+associative arrays, exception handling, array vector operations,
+startup/shutdown, etc.
+
+Druntime forms a common layer underlying the Phobos and Tango user libraries.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/build-dmd.bat	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,7 @@
+@echo off
+set OLDHOME=%HOME%
+set HOME=%CD%
+make clean -fdmd-win32.mak
+make lib install -fdmd-win32.mak
+make clean -fdmd-win32.mak
+set HOME=%OLDHOME%
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/build-dmd.sh	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+OLDHOME=$HOME
+export HOME=`pwd`
+
+goerror(){
+    export HOME=$OLDHOME
+    echo "="
+    echo "= *** Error ***"
+    echo "="
+    exit 1
+}
+
+make clean -fdmd-posix.mak           || goerror
+make lib doc install -fdmd-posix.mak || goerror
+make clean -fdmd-posix.mak           || goerror
+chmod 644 ../import/*.di             || goerror
+
+export HOME=$OLDHOME
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/build-ldc.sh	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+OLDHOME=$HOME
+export HOME=`pwd`
+
+goerror(){
+    export HOME=$OLDHOME
+    echo "="
+    echo "= *** Error ***"
+    echo "="
+    exit 1
+}
+
+make clean -fldc-gcc.mak           || goerror
+make lib doc install -fldc-gcc.mak || goerror
+make clean -fldc-gcc.mak           || goerror
+chmod 644 ../import/*.di           || goerror
+
+export HOME=$OLDHOME
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/core/bitmanip.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,290 @@
+/**
+ * This module contains a collection of bit-level operations.
+ *
+ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
+ * License:   BSD Style, see LICENSE
+ * Authors:   Walter Bright, Don Clugston, Sean Kelly
+ */
+module core.bitmanip;
+
+
+version( DDoc )
+{
+    /**
+     * Scans the bits in v starting with bit 0, looking
+     * for the first set bit.
+     * Returns:
+     *  The bit number of the first bit set.
+     *  The return value is undefined if v is zero.
+     */
+    int bsf( uint v );
+
+
+    /**
+     * Scans the bits in v from the most significant bit
+     * to the least significant bit, looking
+     * for the first set bit.
+     * Returns:
+     *  The bit number of the first bit set.
+     *  The return value is undefined if v is zero.
+     * Example:
+     * ---
+     * import core.bitmanip;
+     *
+     * int main()
+     * {
+     *     uint v;
+     *     int x;
+     *
+     *     v = 0x21;
+     *     x = bsf(v);
+     *     printf("bsf(x%x) = %d\n", v, x);
+     *     x = bsr(v);
+     *     printf("bsr(x%x) = %d\n", v, x);
+     *     return 0;
+     * }
+     * ---
+     * Output:
+     *  bsf(x21) = 0<br>
+     *  bsr(x21) = 5
+     */
+    int bsr( uint v );
+
+
+    /**
+     * Tests the bit.
+     */
+    int bt( uint* p, uint bitnum );
+
+
+    /**
+     * Tests and complements the bit.
+     */
+    int btc( uint* p, uint bitnum );
+
+
+    /**
+     * Tests and resets (sets to 0) the bit.
+     */
+    int btr( uint* p, uint bitnum );
+
+
+    /**
+     * Tests and sets the bit.
+     * Params:
+     * p = a non-NULL pointer to an array of uints.
+     * index = a bit number, starting with bit 0 of p[0],
+     * and progressing. It addresses bits like the expression:
+    ---
+    p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)))
+    ---
+     * Returns:
+     *  A non-zero value if the bit was set, and a zero
+     *  if it was clear.
+     *
+     * Example:
+     * ---
+    import core.bitmanip;
+
+    int main()
+    {
+        uint array[2];
+
+        array[0] = 2;
+        array[1] = 0x100;
+
+        printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
+        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+        printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
+        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+        printf("bts(array, 35) = %d\n", <b>bts</b>(array, 35));
+        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+        printf("btr(array, 35) = %d\n", <b>btr</b>(array, 35));
+        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+        printf("bt(array, 1) = %d\n", <b>bt</b>(array, 1));
+        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+        return 0;
+    }
+     * ---
+     * Output:
+    <pre>
+    btc(array, 35) = 0
+    array = [0]:x2, [1]:x108
+    btc(array, 35) = -1
+    array = [0]:x2, [1]:x100
+    bts(array, 35) = 0
+    array = [0]:x2, [1]:x108
+    btr(array, 35) = -1
+    array = [0]:x2, [1]:x100
+    bt(array, 1) = -1
+    array = [0]:x2, [1]:x100
+    </pre>
+     */
+    int bts( uint* p, uint bitnum );
+
+
+    /**
+     * Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
+     * byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
+     * becomes byte 0.
+     */
+    uint bswap( uint v );
+
+
+    /**
+     * Reads I/O port at port_address.
+     */
+    ubyte inp( uint port_address );
+
+
+    /**
+     * ditto
+     */
+    ushort inpw( uint port_address );
+
+
+    /**
+     * ditto
+     */
+    uint inpl( uint port_address );
+
+
+    /**
+     * Writes and returns value to I/O port at port_address.
+     */
+    ubyte outp( uint port_address, ubyte value );
+
+
+    /**
+     * ditto
+     */
+    ushort outpw( uint port_address, ushort value );
+
+
+    /**
+     * ditto
+     */
+    uint outpl( uint port_address, uint value );
+}
+else version( LDC )
+{
+    public import ldc.bitmanip;
+}
+else
+{
+    public import std.intrinsic;
+}
+
+
+/**
+ *  Calculates the number of set bits in a 32-bit integer.
+ */
+int popcnt( uint x )
+{
+    // Avoid branches, and the potential for cache misses which
+    // could be incurred with a table lookup.
+
+    // We need to mask alternate bits to prevent the
+    // sum from overflowing.
+    // add neighbouring bits. Each bit is 0 or 1.
+    x = x - ((x>>1) & 0x5555_5555);
+    // now each two bits of x is a number 00,01 or 10.
+    // now add neighbouring pairs
+    x = ((x&0xCCCC_CCCC)>>2) + (x&0x3333_3333);
+    // now each nibble holds 0000-0100. Adding them won't
+    // overflow any more, so we don't need to mask any more
+
+    // Now add the nibbles, then the bytes, then the words
+    // We still need to mask to prevent double-counting.
+    // Note that if we used a rotate instead of a shift, we
+    // wouldn't need the masks, and could just divide the sum
+    // by 8 to account for the double-counting.
+    // On some CPUs, it may be faster to perform a multiply.
+
+    x += (x>>4);
+    x &= 0x0F0F_0F0F;
+    x += (x>>8);
+    x &= 0x00FF_00FF;
+    x += (x>>16);
+    x &= 0xFFFF;
+    return x;
+}
+
+
+debug( UnitTest )
+{
+    unittest
+    {
+      assert( popcnt( 0 ) == 0 );
+      assert( popcnt( 7 ) == 3 );
+      assert( popcnt( 0xAA )== 4 );
+      assert( popcnt( 0x8421_1248 ) == 8 );
+      assert( popcnt( 0xFFFF_FFFF ) == 32 );
+      assert( popcnt( 0xCCCC_CCCC ) == 16 );
+      assert( popcnt( 0x7777_7777 ) == 24 );
+    }
+}
+
+
+/**
+ * Reverses the order of bits in a 32-bit integer.
+ */
+uint bitswap( uint x )
+{
+
+    version( D_InlineAsm_X86 )
+    {
+        asm
+        {
+            // Author: Tiago Gasiba.
+            mov EDX, EAX;
+            shr EAX, 1;
+            and EDX, 0x5555_5555;
+            and EAX, 0x5555_5555;
+            shl EDX, 1;
+            or  EAX, EDX;
+            mov EDX, EAX;
+            shr EAX, 2;
+            and EDX, 0x3333_3333;
+            and EAX, 0x3333_3333;
+            shl EDX, 2;
+            or  EAX, EDX;
+            mov EDX, EAX;
+            shr EAX, 4;
+            and EDX, 0x0f0f_0f0f;
+            and EAX, 0x0f0f_0f0f;
+            shl EDX, 4;
+            or  EAX, EDX;
+            bswap EAX;
+        }
+    }
+    else
+    {
+        // swap odd and even bits
+        x = ((x >> 1) & 0x5555_5555) | ((x & 0x5555_5555) << 1);
+        // swap consecutive pairs
+        x = ((x >> 2) & 0x3333_3333) | ((x & 0x3333_3333) << 2);
+        // swap nibbles
+        x = ((x >> 4) & 0x0F0F_0F0F) | ((x & 0x0F0F_0F0F) << 4);
+        // swap bytes
+        x = ((x >> 8) & 0x00FF_00FF) | ((x & 0x00FF_00FF) << 8);
+        // swap 2-byte long pairs
+        x = ( x >> 16              ) | ( x               << 16);
+        return x;
+
+    }
+}
+
+
+debug( UnitTest )
+{
+    unittest
+    {
+        assert( bitswap( 0x8000_0100 ) == 0x0080_0001 );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/core/exception.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,276 @@
+/**
+ * The exception module defines all system-level exceptions and provides a
+ * mechanism to alter system-level error handling.
+ *
+ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
+ * License:   BSD Style, see LICENSE
+ * Authors:   Sean Kelly
+ */
+module core.exception;
+
+
+private
+{
+    alias void  function( string file, size_t line, string msg = null ) assertHandlerType;
+
+    assertHandlerType   assertHandler   = null;
+}
+
+
+/**
+ * Thrown on an array bounds error.
+ */
+class ArrayBoundsException : Exception
+{
+    this( string file, size_t line )
+    {
+        super( "Array index out of bounds", file, line );
+    }
+}
+
+
+/**
+ * Thrown on an assert error.
+ */
+class AssertException : Exception
+{
+    this( string file, size_t line )
+    {
+        super( "Assertion failure", file, line );
+    }
+
+    this( string msg, string file, size_t line )
+    {
+        super( msg, file, line );
+    }
+}
+
+
+/**
+ * Thrown on finalize error.
+ */
+class FinalizeException : Exception
+{
+    ClassInfo   info;
+
+    this( ClassInfo c, Exception e = null )
+    {
+        super( "Finalization error", e );
+        info = c;
+    }
+
+    override string toString()
+    {
+        return "An exception was thrown while finalizing an instance of class " ~ info.name;
+    }
+}
+
+
+/**
+ * Thrown on hidden function error.
+ */
+class HiddenFuncException : Exception
+{
+    this( ClassInfo ci )
+    {
+        super( "Hidden method called for " ~ ci.name );
+    }
+}
+
+
+/**
+ * Thrown on an out of memory error.
+ */
+class OutOfMemoryException : Exception
+{
+    this( string file, size_t line )
+    {
+        super( "Memory allocation failed", file, line );
+    }
+
+    override string toString()
+    {
+        return msg ? super.toString() : "Memory allocation failed";
+    }
+}
+
+
+/**
+ * Thrown on a switch error.
+ */
+class SwitchException : Exception
+{
+    this( string file, size_t line )
+    {
+        super( "No appropriate switch clause found", file, line );
+    }
+}
+
+
+/**
+ * Thrown on a unicode conversion error.
+ */
+class UnicodeException : Exception
+{
+    size_t idx;
+
+    this( string msg, size_t idx )
+    {
+        super( msg );
+        this.idx = idx;
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Overrides
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Overrides the default assert hander with a user-supplied version.
+ *
+ * Params:
+ *  h = The new assert handler.  Set to null to use the default handler.
+ */
+void setAssertHandler( assertHandlerType h )
+{
+    assertHandler = h;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Overridable Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * A callback for assert errors in D.  The user-supplied assert handler will
+ * be called if one has been supplied, otherwise an AssertException will be
+ * thrown.
+ *
+ * Params:
+ *  file = The name of the file that signaled this error.
+ *  line = The line number on which this error occurred.
+ */
+extern (C) void onAssertError( string file, size_t line )
+{
+    if( assertHandler is null )
+        throw new AssertException( file, line );
+    assertHandler( file, line );
+}
+
+
+/**
+ * A callback for assert errors in D.  The user-supplied assert handler will
+ * be called if one has been supplied, otherwise an AssertException will be
+ * thrown.
+ *
+ * Params:
+ *  file = The name of the file that signaled this error.
+ *  line = The line number on which this error occurred.
+ *  msg  = An error message supplied by the user.
+ */
+extern (C) void onAssertErrorMsg( string file, size_t line, string msg )
+{
+    if( assertHandler is null )
+        throw new AssertException( msg, file, line );
+    assertHandler( file, line, msg );
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Internal Error Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * A callback for array bounds errors in D.  An ArrayBoundsException will be
+ * thrown.
+ *
+ * Params:
+ *  file = The name of the file that signaled this error.
+ *  line = The line number on which this error occurred.
+ *
+ * Throws:
+ *  ArrayBoundsException.
+ */
+extern (C) void onArrayBoundsError( string file, size_t line )
+{
+    throw new ArrayBoundsException( file, line );
+}
+
+
+/**
+ * A callback for finalize errors in D.  A FinalizeException will be thrown.
+ *
+ * Params:
+ *  e = The exception thrown during finalization.
+ *
+ * Throws:
+ *  FinalizeException.
+ */
+extern (C) void onFinalizeError( ClassInfo info, Exception ex )
+{
+    throw new FinalizeException( info, ex );
+}
+
+
+/**
+ * A callback for hidden function errors in D.  A HiddenFuncException will be
+ * thrown.
+ *
+ * Throws:
+ *  HiddenFuncException.
+ */
+extern (C) void onHiddenFuncError( Object o )
+{
+    throw new HiddenFuncException( o.classinfo );
+}
+
+
+/**
+ * A callback for out of memory errors in D.  An OutOfMemoryException will be
+ * thrown.
+ *
+ * Throws:
+ *  OutOfMemoryException.
+ */
+extern (C) void onOutOfMemoryError()
+{
+    // NOTE: Since an out of memory condition exists, no allocation must occur
+    //       while generating this object.
+    throw cast(OutOfMemoryException) cast(void*) OutOfMemoryException.classinfo.init;
+}
+
+
+/**
+ * A callback for switch errors in D.  A SwitchException will be thrown.
+ *
+ * Params:
+ *  file = The name of the file that signaled this error.
+ *  line = The line number on which this error occurred.
+ *
+ * Throws:
+ *  SwitchException.
+ */
+extern (C) void onSwitchError( string file, size_t line )
+{
+    throw new SwitchException( file, line );
+}
+
+
+/**
+ * A callback for unicode errors in D.  A UnicodeException will be thrown.
+ *
+ * Params:
+ *  msg = Information about the error.
+ *  idx = String index where this error was detected.
+ *
+ * Throws:
+ *  UnicodeException.
+ */
+extern (C) void onUnicodeError( string msg, size_t idx )
+{
+    throw new UnicodeException( msg, idx );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/core/memory.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,484 @@
+/**
+ * The memory module provides an interface to the garbage collector and to
+ * any other OS or API-level memory management facilities.
+ *
+ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
+ * License:   BSD Style, see LICENSE
+ * Authors:   Sean Kelly
+ */
+module core.memory;
+
+
+private
+{
+    extern (C) void gc_init();
+    extern (C) void gc_term();
+
+    extern (C) void gc_enable();
+    extern (C) void gc_disable();
+    extern (C) void gc_collect();
+    extern (C) void gc_minimize();
+
+    extern (C) uint gc_getAttr( void* p );
+    extern (C) uint gc_setAttr( void* p, uint a );
+    extern (C) uint gc_clrAttr( void* p, uint a );
+
+    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) void*  gc_realloc( void* p, size_t sz, uint ba = 0 );
+    extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
+    extern (C) size_t gc_reserve( size_t sz );
+    extern (C) void   gc_free( void* p );
+
+    extern (C) void*   gc_addrOf( void* p );
+    extern (C) size_t  gc_sizeOf( void* p );
+
+    struct BlkInfo_
+    {
+        void*  base;
+        size_t size;
+        uint   attr;
+    }
+
+    extern (C) BlkInfo_ gc_query( void* p );
+
+    extern (C) void gc_addRoot( void* p );
+    extern (C) void gc_addRange( void* p, size_t sz );
+
+    extern (C) void gc_removeRoot( void* p );
+    extern (C) void gc_removeRange( void* p );
+
+    extern (C) void* gc_getHandle();
+    extern (C) void gc_setHandle( void* p );
+    extern (C) void gc_endHandle();
+}
+
+
+/**
+ * This struct encapsulates all garbage collection functionality for the D
+ * programming language.
+ */
+struct GC
+{
+    /**
+     * Enables the garbage collector if collections have previously been
+     * suspended by a call to disable.  This function is reentrant, and
+     * must be called once for every call to disable before the garbage
+     * collector is enabled.
+     */
+    static void enable()
+    {
+        gc_enable();
+    }
+
+
+    /**
+     * Disables the garbage collector.  This function is reentrant, but
+     * enable must be called once for each call to disable.
+     */
+    static void disable()
+    {
+        gc_disable();
+    }
+
+
+    /**
+     * Begins a full collection.  While the meaning of this may change based
+     * on the garbage collector implementation, typical behavior is to scan
+     * all stack segments for roots, mark accessible memory blocks as alive,
+     * and then to reclaim free space.  This action may need to suspend all
+     * running threads for at least part of the collection process.
+     */
+    static void collect()
+    {
+        gc_collect();
+    }
+
+    /**
+     * Indicates that the managed memory space be minimized by returning free
+     * physical memory to the operating system.  The amount of free memory
+     * returned depends on the allocator design and on program behavior.
+     */
+    static void minimize()
+    {
+        gc_minimize();
+    }
+
+
+    /**
+     * Elements for a bit field representing memory block attributes.  These
+     * are manipulated via the getAttr, setAttr, clrAttr functions.
+     */
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001, /// Finalize the data in this block on collect.
+        NO_SCAN  = 0b0000_0010, /// Do not scan through this block on collect.
+        NO_MOVE  = 0b0000_0100  /// Do not move this memory block on collect.
+    }
+
+
+    /**
+     * Contains aggregate information about a block of managed memory.  The
+     * purpose of this struct is to support a more efficient query style in
+     * instances where detailed information is needed.
+     *
+     * base = A pointer to the base of the block in question.
+     * size = The size of the block, calculated from base.
+     * attr = Attribute bits set on the memory block.
+     */
+    alias BlkInfo_ BlkInfo;
+
+
+    /**
+     * Returns a bit field representing all block attributes set for the memory
+     * referenced by p.  If p references memory not originally allocated by
+     * this garbage collector, points to the interior of a memory block, or if
+     * p is null, zero will be returned.
+     *
+     * Params:
+     *  p = A pointer to the root of a valid memory block or to null.
+     *
+     * Returns:
+     *  A bit field containing any bits set for the memory block referenced by
+     *  p or zero on error.
+     */
+    static uint getAttr( void* p )
+    {
+        return gc_getAttr( p );
+    }
+
+
+    /**
+     * Sets the specified bits for the memory references by p.  If p references
+     * memory not originally allocated by this garbage collector, points to the
+     * interior of a memory block, or if p is null, no action will be
+     * performed.
+     *
+     * Params:
+     *  p = A pointer to the root of a valid memory block or to null.
+     *  a = A bit field containing any bits to set for this memory block.
+     *
+     *  The result of a call to getAttr after the specified bits have been
+     *  set.
+     */
+    static uint setAttr( void* p, uint a )
+    {
+        return gc_setAttr( p, a );
+    }
+
+
+    /**
+     * Clears the specified bits for the memory references by p.  If p
+     * references memory not originally allocated by this garbage collector,
+     * points to the interior of a memory block, or if p is null, no action
+     * will be performed.
+     *
+     * Params:
+     *  p = A pointer to the root of a valid memory block or to null.
+     *  a = A bit field containing any bits to clear for this memory block.
+     *
+     * Returns:
+     *  The result of a call to getAttr after the specified bits have been
+     *  cleared.
+     */
+    static uint clrAttr( void* p, uint a )
+    {
+        return gc_clrAttr( p, a );
+    }
+
+
+    /**
+     * Requests an aligned block of managed memory from the garbage collector.
+     * This memory may be deleted at will with a call to free, or it may be
+     * discarded and cleaned up automatically during a collection run.  If
+     * allocation fails, this function will call onOutOfMemory which is
+     * expected to throw an OutOfMemoryException.
+     *
+     * Params:
+     *  sz = The desired allocation size in bytes.
+     *  ba = A bitmask of the attributes to set on this block.
+     *
+     * Returns:
+     *  A reference to the allocated memory or null if insufficient memory
+     *  is available.
+     *
+     * Throws:
+     *  OutOfMemoryException on allocation failure.
+     */
+    static void* malloc( size_t sz, uint ba = 0 )
+    {
+        return gc_malloc( sz, ba );
+    }
+
+
+    /**
+     * Requests an aligned block of managed memory from the garbage collector,
+     * which is initialized with all bits set to zero.  This memory may be
+     * deleted at will with a call to free, or it may be discarded and cleaned
+     * up automatically during a collection run.  If allocation fails, this
+     * function will call onOutOfMemory which is expected to throw an
+     * OutOfMemoryException.
+     *
+     * Params:
+     *  sz = The desired allocation size in bytes.
+     *  ba = A bitmask of the attributes to set on this block.
+     *
+     * Returns:
+     *  A reference to the allocated memory or null if insufficient memory
+     *  is available.
+     *
+     * Throws:
+     *  OutOfMemoryException on allocation failure.
+     */
+    static void* calloc( size_t sz, uint ba = 0 )
+    {
+        return gc_calloc( sz, ba );
+    }
+
+
+    /**
+     * If sz is zero, the memory referenced by p will be deallocated as if
+     * by a call to free.  A new memory block of size sz will then be
+     * allocated as if by a call to malloc, or the implementation may instead
+     * resize the memory block in place.  The contents of the new memory block
+     * will be the same as the contents of the old memory block, up to the
+     * lesser of the new and old sizes.  Note that existing memory will only
+     * be freed by realloc if sz is equal to zero.  The garbage collector is
+     * otherwise expected to later reclaim the memory block if it is unused.
+     * If allocation fails, this function will call onOutOfMemory which is
+     * expected to throw an OutOfMemoryException.  If p references memory not
+     * originally allocated by this garbage collector, or if it points to the
+     * interior of a memory block, no action will be taken.  If ba is zero
+     * (the default) and p references the head of a valid, known memory block
+     * then any bits set on the current block will be set on the new block if a
+     * reallocation is required.  If ba is not zero and p references the head
+     * of a valid, known memory block then the bits in ba will replace those on
+     * the current memory block and will also be set on the new block if a
+     * reallocation is required.
+     *
+     * Params:
+     *  p  = A pointer to the root of a valid memory block or to null.
+     *  sz = The desired allocation size in bytes.
+     *  ba = A bitmask of the attributes to set on this block.
+     *
+     * Returns:
+     *  A reference to the allocated memory on success or null if sz is
+     *  zero.  On failure, the original value of p is returned.
+     *
+     * Throws:
+     *  OutOfMemoryException on allocation failure.
+     */
+    static void* realloc( void* p, size_t sz, uint ba = 0 )
+    {
+        return gc_realloc( p, sz, ba );
+    }
+
+
+    /**
+     * Requests that the managed memory block referenced by p be extended in
+     * place by at least mx bytes, with a desired extension of sz bytes.  If an
+     * extension of the required size is not possible, if p references memory
+     * not originally allocated by this garbage collector, or if p points to
+     * the interior of a memory block, no action will be taken.
+     *
+     * Params:
+     *  mx = The minimum extension size in bytes.
+     *  sz = The  desired extension size in bytes.
+     *
+     * Returns:
+     *  The size in bytes of the extended memory block referenced by p or zero
+     *  if no extension occurred.
+     */
+    static size_t extend( void* p, size_t mx, size_t sz )
+    {
+        return gc_extend( p, mx, sz );
+    }
+
+
+    /**
+     * Requests that at least sz bytes of memory be obtained from the operating
+     * system and marked as free.
+     *
+     * Params:
+     *  sz = The desired size in bytes.
+     *
+     * Returns:
+     *  The actual number of bytes reserved or zero on error.
+     */
+    static size_t reserve( size_t sz )
+    {
+        return gc_reserve( sz );
+    }
+
+
+    /**
+     * Deallocates the memory referenced by p.  If p is null, no action
+     * occurs.  If p references memory not originally allocated by this
+     * garbage collector, or if it points to the interior of a memory block,
+     * no action will be taken.  The block will not be finalized regardless
+     * of whether the FINALIZE attribute is set.  If finalization is desired,
+     * use delete instead.
+     *
+     * Params:
+     *  p = A pointer to the root of a valid memory block or to null.
+     */
+    static void free( void* p )
+    {
+        gc_free( p );
+    }
+
+
+    /**
+     * Returns the base address of the memory block containing p.  This value
+     * is useful to determine whether p is an interior pointer, and the result
+     * may be passed to routines such as sizeOf which may otherwise fail.  If p
+     * references memory not originally allocated by this garbage collector, if
+     * p is null, or if the garbage collector does not support this operation,
+     * null will be returned.
+     *
+     * Params:
+     *  p = A pointer to the root or the interior of a valid memory block or to
+     *      null.
+     *
+     * Returns:
+     *  The base address of the memory block referenced by p or null on error.
+     */
+    static void* addrOf( void* p )
+    {
+        return gc_addrOf( p );
+    }
+
+
+    /**
+     * Returns the true size of the memory block referenced by p.  This value
+     * represents the maximum number of bytes for which a call to realloc may
+     * resize the existing block in place.  If p references memory not
+     * originally allocated by this garbage collector, points to the interior
+     * of a memory block, or if p is null, zero will be returned.
+     *
+     * Params:
+     *  p = A pointer to the root of a valid memory block or to null.
+     *
+     * Returns:
+     *  The size in bytes of the memory block referenced by p or zero on error.
+     */
+    static size_t sizeOf( void* p )
+    {
+        return gc_sizeOf( p );
+    }
+
+
+    /**
+     * Returns aggregate information about the memory block containing p.  If p
+     * references memory not originally allocated by this garbage collector, if
+     * p is null, or if the garbage collector does not support this operation,
+     * BlkInfo.init will be returned.  Typically, support for this operation
+     * is dependent on support for addrOf.
+     *
+     * Params:
+     *  p = A pointer to the root or the interior of a valid memory block or to
+     *      null.
+     *
+     * Returns:
+     *  Information regarding the memory block referenced by p or BlkInfo.init
+     *  on error.
+     */
+    static BlkInfo query( void* p )
+    {
+        return gc_query( p );
+    }
+
+
+    /**
+     * Adds the memory address referenced by p to an internal list of roots to
+     * be scanned during a collection.  If p is null, no operation is
+     * performed.
+     *
+     * Params:
+     *  p = A pointer to a valid memory address or to null.
+     */
+    static void addRoot( void* p )
+    {
+        gc_addRoot( p );
+    }
+
+
+    /**
+     * Adds the memory block referenced by p and of size sz to an internal list
+     * of ranges to be scanned during a collection.  If p is null, no operation
+     * is performed.
+     *
+     * Params:
+     *  p  = A pointer to a valid memory address or to null.
+     *  sz = The size in bytes of the block to add.  If sz is zero then the
+     *       no operation will occur.  If p is null then sz must be zero.
+     */
+    static void addRange( void* p, size_t sz )
+    {
+        gc_addRange( p, sz );
+    }
+
+
+    /**
+     * Removes the memory block referenced by p from an internal list of roots
+     * to be scanned during a collection.  If p is null or does not represent
+     * a value previously passed to add(void*) then no operation is performed.
+     *
+     *  p  = A pointer to a valid memory address or to null.
+     */
+    static void removeRoot( void* p )
+    {
+        gc_removeRoot( p );
+    }
+
+
+    /**
+     * Removes the memory block referenced by p from an internal list of ranges
+     * to be scanned during a collection.  If p is null or does not represent
+     * a value previously passed to add(void*, size_t) then no operation is
+     * performed.
+     *
+     * Params:
+     *  p  = A pointer to a valid memory address or to null.
+     */
+    static void removeRange( void* p )
+    {
+        gc_removeRange( p );
+    }
+
+    /**
+     * Get handle to the collector.
+     * The only thing that can be done with this handle is pass it to
+     * setHandle(). getHandle/setHandle/endHandle work together so that
+     * if there are multiple instances of the gc running, only one instance
+     * can be set to run.
+     * The most common case of this is under Windows where a D application
+     * calls functions in a DLL that is implemented in D.
+     */
+
+    static void* getHandle()
+    {
+	return gc_getHandle();
+    }
+
+    /**
+     * Set handle to the collector.
+     * The handle p is an opaque handle, acquired by a call to
+     * getHandle().
+     */
+
+    static void setHandle(void* p)
+    {
+	gc_setHandle(p);
+    }
+
+    /**
+     * Call when done using the collector specified by the
+     * call to setHandle().
+     */
+
+    static void endHandle()
+    {
+	gc_endHandle();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/core/runtime.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,171 @@
+/**
+ * The runtime module exposes information specific to the D runtime code.
+ *
+ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
+ * License:   BSD Style, see LICENSE
+ * Authors:   Sean Kelly
+ */
+module core.runtime;
+
+
+private
+{
+    extern (C) bool rt_isHalting();
+
+    alias bool function() ModuleUnitTester;
+    alias bool function(Object) CollectHandler;
+    alias Exception.TraceInfo function( void* ptr = null ) TraceHandler;
+
+    extern (C) void rt_setCollectHandler( CollectHandler h );
+    extern (C) void rt_setTraceHandler( TraceHandler h );
+
+    alias void delegate( Exception ) ExceptionHandler;
+    extern (C) bool rt_init( ExceptionHandler dg = null );
+    extern (C) bool rt_term( ExceptionHandler dg = null );
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Runtime
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * This struct encapsulates all functionality related to the underlying runtime
+ * module for the calling context.
+ */
+struct Runtime
+{
+    /**
+     * Initializes the runtime.  This call is to be used in instances where the
+     * standard program initialization process is not executed.  This is most
+     * often in shared libraries or in libraries linked to a C program.
+     *
+     * Params:
+     *  dg = A delegate which will receive any exception thrown during the
+     *       initialization process or null if such exceptions should be
+     *       discarded.
+     *
+     * Returns:
+     *  true if initialization succeeds and false if initialization fails.
+     */
+    static bool initialize( void delegate( Exception ) dg = null )
+    {
+        return rt_init( dg );
+    }
+
+
+    /**
+     * Terminates the runtime.  This call is to be used in instances where the
+     * standard program termination process will not be not executed.  This is
+     * most often in shared libraries or in libraries linked to a C program.
+     *
+     * Params:
+     *  dg = A delegate which will receive any exception thrown during the
+     *       termination process or null if such exceptions should be
+     *       discarded.
+     *
+     * Returns:
+     *  true if termination succeeds and false if termination fails.
+     */
+    static bool terminate( void delegate( Exception ) dg = null )
+    {
+        return rt_term( dg );
+    }
+
+
+    /**
+     * Returns true if the runtime is halting.  Under normal circumstances,
+     * this will be set between the time that normal application code has
+     * exited and before module dtors are called.
+     *
+     * Returns:
+     *  true if the runtime is halting.
+     */
+    static bool isHalting()
+    {
+        return rt_isHalting();
+    }
+
+
+    /**
+     * Overrides the default trace mechanism with s user-supplied version.  A
+     * trace represents the context from which an exception was thrown, and the
+     * trace handler will be called when this occurs.  The pointer supplied to
+     * this routine indicates the base address from which tracing should occur.
+     * If the supplied pointer is null then the trace routine should determine
+     * an appropriate calling context from which to begin the trace.
+     *
+     * Params:
+     *  h = The new trace handler.  Set to null to use the default handler.
+     */
+    static void traceHandler( TraceHandler h )
+    {
+        rt_setTraceHandler( h );
+    }
+
+
+    /**
+     * Overrides the default collect hander with a user-supplied version.  This
+     * routine will be called for each resource object that is finalized in a
+     * non-deterministic manner--typically during a garbage collection cycle.
+     * If the supplied routine returns true then the object's dtor will called
+     * as normal, but if the routine returns false than the dtor will not be
+     * called.  The default behavior is for all object dtors to be called.
+     *
+     * Params:
+     *  h = The new collect handler.  Set to null to use the default handler.
+     */
+    static void collectHandler( CollectHandler h )
+    {
+        rt_setCollectHandler( h );
+    }
+
+
+    /**
+     * Overrides the default module unit tester with a user-supplied version.
+     * This routine will be called once on program initialization.  The return
+     * value of this routine indicates to the runtime whether the body of the
+     * program will be executed.
+     *
+     * Params:
+     *  h = The new unit tester.  Set to null to use the default unit tester.
+     */
+    static void moduleUnitTester( ModuleUnitTester h )
+    {
+        sm_moduleUnitTester = h;
+    }
+
+
+private:
+    static ModuleUnitTester sm_moduleUnitTester = null;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Overridable Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * This routine is called by the runtime to run module unit tests on startup.
+ * The user-supplied unit tester will be called if one has been supplied,
+ * otherwise all unit tests will be run in sequence.
+ *
+ * Returns:
+ *  true if execution should continue after testing is complete and false if
+ *  not.  Default behavior is to return true.
+ */
+extern (C) bool runModuleUnitTests()
+{
+    if( Runtime.sm_moduleUnitTester is null )
+    {
+        foreach( m; ModuleInfo )
+        {
+            if( m.unitTest )
+                m.unitTest();
+        }
+        return true;
+    }
+    return Runtime.sm_moduleUnitTester();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/core/thread.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,3322 @@
+/**
+ * The thread module provides support for thread creation and management.
+ *
+ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
+ * License:   BSD Style, see LICENSE
+ * Authors:   Sean Kelly
+ */
+module core.thread;
+
+
+// this should be true for most architectures
+version = StackGrowsDown;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Thread and Fiber Exceptions
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Base class for thread exceptions.
+ */
+class ThreadException : Exception
+{
+    this( string msg )
+    {
+        super( msg );
+    }
+}
+
+
+/**
+ * Base class for fiber exceptions.
+ */
+class FiberException : Exception
+{
+    this( string msg )
+    {
+        super( msg );
+    }
+}
+
+
+private
+{
+    //
+    // exposed by compiler runtime
+    //
+    extern (C) void* rt_stackBottom();
+    extern (C) void* rt_stackTop();
+
+
+    void* getStackBottom()
+    {
+        return rt_stackBottom();
+    }
+
+
+    void* getStackTop()
+    {
+        version( D_InlineAsm_X86 )
+        {
+            asm
+            {
+                naked;
+                mov EAX, ESP;
+                ret;
+            }
+        }
+        else
+        {
+            return rt_stackTop();
+        }
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Thread Entry Point and Signal Handlers
+///////////////////////////////////////////////////////////////////////////////
+
+
+version( Windows )
+{
+    private
+    {
+        import stdc.stdint : uintptr_t; // for _beginthreadex decl below
+        import sys.windows.windows;
+
+        const DWORD TLS_OUT_OF_INDEXES  = 0xFFFFFFFF;
+
+        extern (Windows) alias uint function(void*) btex_fptr;
+        extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*);
+
+
+        //
+        // entry point for Windows threads
+        //
+        extern (Windows) uint thread_entryPoint( void* arg )
+        {
+            Thread  obj = cast(Thread) arg;
+            assert( obj );
+            scope( exit ) Thread.remove( obj );
+
+            assert( obj.m_curr is &obj.m_main );
+            obj.m_main.bstack = getStackBottom();
+            obj.m_main.tstack = obj.m_main.bstack;
+            Thread.add( &obj.m_main );
+            Thread.setThis( obj );
+
+            // NOTE: No GC allocations may occur until the stack pointers have
+            //       been set and Thread.getThis returns a valid reference to
+            //       this thread object (this latter condition is not strictly
+            //       necessary on Win32 but it should be followed for the sake
+            //       of consistency).
+
+            // TODO: Consider putting an auto exception object here (using
+            //       alloca) forOutOfMemoryError plus something to track
+            //       whether an exception is in-flight?
+
+            try
+            {
+                obj.run();
+            }
+            catch( Object o )
+            {
+                obj.m_unhandled = o;
+            }
+            return 0;
+        }
+
+
+        //
+        // copy of the same-named function in phobos.std.thread--it uses the
+        // Windows naming convention to be consistent with GetCurrentThreadId
+        //
+        HANDLE GetCurrentThreadHandle()
+        {
+            const uint DUPLICATE_SAME_ACCESS = 0x00000002;
+
+            HANDLE curr = GetCurrentThread(),
+                   proc = GetCurrentProcess(),
+                   hndl;
+
+            DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
+            return hndl;
+        }
+    }
+}
+else version( Posix )
+{
+    private
+    {
+        import stdc.posix.semaphore;
+        import stdc.posix.pthread;
+        import stdc.posix.signal;
+        import stdc.posix.time;
+        import stdc.errno;
+
+        extern (C) int getErrno();
+        version( GNU )
+        {
+            import gcc.builtins;
+        }
+
+
+        //
+        // entry point for POSIX threads
+        //
+        extern (C) void* thread_entryPoint( void* arg )
+        {
+            Thread  obj = cast(Thread) arg;
+            assert( obj );
+            scope( exit )
+            {
+                // NOTE: isRunning should be set to false after the thread is
+                //       removed or a double-removal could occur between this
+                //       function and thread_suspendAll.
+                Thread.remove( obj );
+                obj.m_isRunning = false;
+            }
+
+            static extern (C) void thread_cleanupHandler( void* arg )
+            {
+                Thread  obj = cast(Thread) arg;
+                assert( obj );
+
+                // NOTE: If the thread terminated abnormally, just set it as
+                //       not running and let thread_suspendAll remove it from
+                //       the thread list.  This is safer and is consistent
+                //       with the Windows thread code.
+                obj.m_isRunning = false;
+            }
+
+            // NOTE: Using void to skip the initialization here relies on
+            //       knowledge of how pthread_cleanup is implemented.  It may
+            //       not be appropriate for all platforms.  However, it does
+            //       avoid the need to link the pthread module.  If any
+            //       implementation actually requires default initialization
+            //       then pthread_cleanup should be restructured to maintain
+            //       the current lack of a link dependency.
+            pthread_cleanup cleanup = void;
+            cleanup.push( &thread_cleanupHandler, cast(void*) obj );
+
+            // NOTE: For some reason this does not always work for threads.
+            //obj.m_main.bstack = getStackBottom();
+            version( D_InlineAsm_X86 )
+            {
+                static void* getBasePtr()
+                {
+                    asm
+                    {
+                        naked;
+                        mov EAX, EBP;
+                        ret;
+                    }
+                }
+
+                obj.m_main.bstack = getBasePtr();
+            }
+            else version( StackGrowsDown )
+                obj.m_main.bstack = &obj + 1;
+            else
+                obj.m_main.bstack = &obj;
+            obj.m_main.tstack = obj.m_main.bstack;
+            assert( obj.m_curr == &obj.m_main );
+            Thread.add( &obj.m_main );
+            Thread.setThis( obj );
+
+            // NOTE: No GC allocations may occur until the stack pointers have
+            //       been set and Thread.getThis returns a valid reference to
+            //       this thread object (this latter condition is not strictly
+            //       necessary on Win32 but it should be followed for the sake
+            //       of consistency).
+
+            // TODO: Consider putting an auto exception object here (using
+            //       alloca) forOutOfMemoryError plus something to track
+            //       whether an exception is in-flight?
+
+            try
+            {
+                obj.run();
+            }
+            catch( Object o )
+            {
+                obj.m_unhandled = o;
+            }
+            return null;
+        }
+
+
+        //
+        // used to track the number of suspended threads
+        //
+        sem_t   suspendCount;
+
+
+        extern (C) void thread_suspendHandler( int sig )
+        in
+        {
+            assert( sig == SIGUSR1 );
+        }
+        body
+        {
+            version( LDC )
+            {
+                version(X86)
+                {
+                    uint eax,ecx,edx,ebx,ebp,esi,edi;
+                    asm
+                    {
+                        mov eax[EBP], EAX ;
+                        mov ecx[EBP], ECX ;
+                        mov edx[EBP], EDX ;
+                        mov ebx[EBP], EBX ;
+                        mov ebp[EBP], EBP ;
+                        mov esi[EBP], ESI ;
+                        mov edi[EBP], EDI ;
+                    }
+                }
+                else version (X86_64)
+                {
+                    ulong rax,rbx,rcx,rdx,rbp,rsi,rdi,rsp,r10,r11,r12,r13,r14,r15;
+                    asm
+                    {
+                        movq rax[RBP], RAX ;
+                        movq rbx[RBP], RBX ;
+                        movq rcx[RBP], RCX ;
+                        movq rdx[RBP], RDX ;
+                        movq rbp[RBP], RBP ;
+                        movq rsi[RBP], RSI ;
+                        movq rdi[RBP], RDI ;
+                        movq rsp[RBP], RSP ;
+                        movq r10[RBP], R10 ;
+                        movq r11[RBP], R11 ;
+                        movq r12[RBP], R12 ;
+                        movq r13[RBP], R13 ;
+                        movq r14[RBP], R14 ;
+                        movq r15[RBP], R15 ;
+                    }
+                }
+                else
+                {
+                    static assert( false, "Architecture not supported." );
+                }
+            }
+            else version( D_InlineAsm_X86 )
+            {
+                asm
+                {
+                    pushad;
+                }
+            }
+            else version( GNU )
+            {
+                __builtin_unwind_init();
+            }
+            else
+            {
+                static assert( false, "Architecture not supported." );
+            }
+
+            // NOTE: Since registers are being pushed and popped from the
+            //       stack, any other stack data used by this function should
+            //       be gone before the stack cleanup code is called below.
+            {
+                Thread  obj = Thread.getThis();
+
+                // NOTE: The thread reference returned by getThis is set within
+                //       the thread startup code, so it is possible that this
+                //       handler may be called before the reference is set.  In
+                //       this case it is safe to simply suspend and not worry
+                //       about the stack pointers as the thread will not have
+                //       any references to GC-managed data.
+                if( obj && !obj.m_lock )
+                {
+                    obj.m_curr.tstack = getStackTop();
+                }
+
+                sigset_t    sigres = void;
+                int         status;
+
+                status = sigfillset( &sigres );
+                assert( status == 0 );
+
+                status = sigdelset( &sigres, SIGUSR2 );
+                assert( status == 0 );
+
+                status = sem_post( &suspendCount );
+                assert( status == 0 );
+
+                sigsuspend( &sigres );
+
+                if( obj && !obj.m_lock )
+                {
+                    obj.m_curr.tstack = obj.m_curr.bstack;
+                }
+            }
+
+            version( LDC )
+            {
+                // nothing to pop
+            }
+            else version( D_InlineAsm_X86 )
+            {
+                asm
+                {
+                    popad;
+                }
+            }
+            else version( GNU )
+            {
+                // registers will be popped automatically
+            }
+            else
+            {
+                static assert( false, "Architecture not supported." );
+            }
+        }
+
+
+        extern (C) void thread_resumeHandler( int sig )
+        in
+        {
+            assert( sig == SIGUSR2 );
+        }
+        body
+        {
+
+        }
+    }
+}
+else
+{
+    // NOTE: This is the only place threading versions are checked.  If a new
+    //       version is added, the module code will need to be searched for
+    //       places where version-specific code may be required.  This can be
+    //       easily accomlished by searching for 'Windows' or 'Posix'.
+    static assert( false, "Unknown threading implementation." );
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Thread
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * This class encapsulates all threading functionality for the D
+ * programming language.  As thread manipulation is a required facility
+ * for garbage collection, all user threads should derive from this
+ * class, and instances of this class should never be explicitly deleted.
+ * A new thread may be created using either derivation or composition, as
+ * in the following example.
+ *
+ * Example:
+ * ----------------------------------------------------------------------------
+ *
+ * class DerivedThread : Thread
+ * {
+ *     this()
+ *     {
+ *         super( &run );
+ *     }
+ *
+ * private :
+ *     void run()
+ *     {
+ *         printf( "Derived thread running.\n" );
+ *     }
+ * }
+ *
+ * void threadFunc()
+ * {
+ *     printf( "Composed thread running.\n" );
+ * }
+ *
+ * // create instances of each type
+ * Thread derived = new DerivedThread();
+ * Thread composed = new Thread( &threadFunc );
+ *
+ * // start both threads
+ * derived.start();
+ * composed.start();
+ *
+ * ----------------------------------------------------------------------------
+ */
+class Thread
+{
+    ///////////////////////////////////////////////////////////////////////////
+    // Initialization
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Initializes a thread object which is associated with a static
+     * D function.
+     *
+     * Params:
+     *  fn = The thread function.
+     *  sz = The stack size for this thread.
+     *
+     * In:
+     *  fn must not be null.
+     */
+    this( void function() fn, size_t sz = 0 )
+    in
+    {
+        assert( fn );
+    }
+    body
+    {
+        m_fn   = fn;
+        m_sz   = sz;
+        m_call = Call.FN;
+        m_curr = &m_main;
+    }
+
+
+    /**
+     * Initializes a thread object which is associated with a dynamic
+     * D function.
+     *
+     * Params:
+     *  dg = The thread function.
+     *  sz = The stack size for this thread.
+     *
+     * In:
+     *  dg must not be null.
+     */
+    this( void delegate() dg, size_t sz = 0 )
+    in
+    {
+        assert( dg );
+    }
+    body
+    {
+        m_dg   = dg;
+        m_sz   = sz;
+        m_call = Call.DG;
+        m_curr = &m_main;
+    }
+
+
+    /**
+     * Cleans up any remaining resources used by this object.
+     */
+    ~this()
+    {
+        if( m_addr == m_addr.init )
+        {
+            return;
+        }
+
+        version( Win32 )
+        {
+            m_addr = m_addr.init;
+            CloseHandle( m_hndl );
+            m_hndl = m_hndl.init;
+        }
+        else version( Posix )
+        {
+            pthread_detach( m_addr );
+            m_addr = m_addr.init;
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // General Actions
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Starts the thread and invokes the function or delegate passed upon
+     * construction.
+     *
+     * In:
+     *  This routine may only be called once per thread instance.
+     *
+     * Throws:
+     *  ThreadException if the thread fails to start.
+     */
+    final void start()
+    in
+    {
+        assert( !next && !prev );
+    }
+    body
+    {
+        version( Win32 ) {} else
+        version( Posix )
+        {
+            pthread_attr_t  attr;
+
+            if( pthread_attr_init( &attr ) )
+                throw new ThreadException( "Error initializing thread attributes" );
+            if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
+                throw new ThreadException( "Error initializing thread stack size" );
+            if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) )
+                throw new ThreadException( "Error setting thread joinable" );
+        }
+
+        // NOTE: This operation needs to be synchronized to avoid a race
+        //       condition with the GC.  Without this lock, the thread
+        //       could start and allocate memory before being added to
+        //       the global thread list, preventing it from being scanned
+        //       and causing memory to be collected that is still in use.
+        synchronized( slock )
+        {
+            version( Win32 )
+            {
+                m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr );
+                if( cast(size_t) m_hndl == 0 )
+                    throw new ThreadException( "Error creating thread" );
+            }
+            else version( Posix )
+            {
+                m_isRunning = true;
+                scope( failure ) m_isRunning = false;
+
+                if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
+                    throw new ThreadException( "Error creating thread" );
+            }
+            multiThreadedFlag = true;
+            add( this );
+        }
+    }
+
+
+    /**
+     * Waits for this thread to complete.  If the thread terminated as the
+     * result of an unhandled exception, this exception will be rethrown.
+     *
+     * Params:
+     *  rethrow = Rethrow any unhandled exception which may have caused this
+     *            thread to terminate.
+     *
+     * Throws:
+     *  ThreadException if the operation fails.
+     *  Any exception not handled by the joined thread.
+     *
+     * Returns:
+     *  Any exception not handled by this thread if rethrow = false, null
+     *  otherwise.
+     */
+    final Object join( bool rethrow = true )
+    {
+        version( Win32 )
+        {
+            if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
+                throw new ThreadException( "Unable to join thread" );
+            // NOTE: m_addr must be cleared before m_hndl is closed to avoid
+            //       a race condition with isRunning.  The operation is labeled
+            //       volatile to prevent compiler reordering.
+            volatile m_addr = m_addr.init;
+            CloseHandle( m_hndl );
+            m_hndl = m_hndl.init;
+        }
+        else version( Posix )
+        {
+            if( pthread_join( m_addr, null ) != 0 )
+                throw new ThreadException( "Unable to join thread" );
+            // NOTE: pthread_join acts as a substitute for pthread_detach,
+            //       which is normally called by the dtor.  Setting m_addr
+            //       to zero ensures that pthread_detach will not be called
+            //       on object destruction.
+            volatile m_addr = m_addr.init;
+        }
+        if( m_unhandled )
+        {
+            if( rethrow )
+                throw m_unhandled;
+            return m_unhandled;
+        }
+        return null;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // General Properties
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Gets the user-readable label for this thread.
+     *
+     * Returns:
+     *  The name of this thread.
+     */
+    final char[] name()
+    {
+        synchronized( this )
+        {
+            return m_name;
+        }
+    }
+
+
+    /**
+     * Sets the user-readable label for this thread.
+     *
+     * Params:
+     *  val = The new name of this thread.
+     */
+    final void name( char[] val )
+    {
+        synchronized( this )
+        {
+            m_name = val.dup;
+        }
+    }
+
+
+    /**
+     * Gets the daemon status for this thread.  While the runtime will wait for
+     * all normal threads to complete before tearing down the process, daemon
+     * threads are effectively ignored and thus will not prevent the process
+     * from terminating.  In effect, daemon threads will be terminated
+     * automatically by the OS when the process exits.
+     *
+     * Returns:
+     *  true if this is a daemon thread.
+     */
+    final bool isDaemon()
+    {
+        synchronized( this )
+        {
+            return m_isDaemon;
+        }
+    }
+
+
+    /**
+     * Sets the daemon status for this thread.  While the runtime will wait for
+     * all normal threads to complete before tearing down the process, daemon
+     * threads are effectively ignored and thus will not prevent the process
+     * from terminating.  In effect, daemon threads will be terminated
+     * automatically by the OS when the process exits.
+     *
+     * Params:
+     *  val = The new daemon status for this thread.
+     */
+    final void isDaemon( bool val )
+    {
+        synchronized( this )
+        {
+            m_isDaemon = val;
+        }
+    }
+
+
+    /**
+     * Tests whether this thread is running.
+     *
+     * Returns:
+     *  true if the thread is running, false if not.
+     */
+    final bool isRunning()
+    {
+        if( m_addr == m_addr.init )
+        {
+            return false;
+        }
+
+        version( Win32 )
+        {
+            uint ecode = 0;
+            GetExitCodeThread( m_hndl, &ecode );
+            return ecode == STILL_ACTIVE;
+        }
+        else version( Posix )
+        {
+            // NOTE: It should be safe to access this value without
+            //       memory barriers because word-tearing and such
+            //       really isn't an issue for boolean values.
+            return m_isRunning;
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Thread Priority Actions
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * The minimum scheduling priority that may be set for a thread.  On
+     * systems where multiple scheduling policies are defined, this value
+     * represents the minimum valid priority for the scheduling policy of
+     * the process.
+     */
+    static const int PRIORITY_MIN;
+
+
+    /**
+     * The maximum scheduling priority that may be set for a thread.  On
+     * systems where multiple scheduling policies are defined, this value
+     * represents the minimum valid priority for the scheduling policy of
+     * the process.
+     */
+    static const int PRIORITY_MAX;
+
+
+    /**
+     * Gets the scheduling priority for the associated thread.
+     *
+     * Returns:
+     *  The scheduling priority of this thread.
+     */
+    final int priority()
+    {
+        version( Win32 )
+        {
+            return GetThreadPriority( m_hndl );
+        }
+        else version( Posix )
+        {
+            int         policy;
+            sched_param param;
+
+            if( pthread_getschedparam( m_addr, &policy, &param ) )
+                throw new ThreadException( "Unable to get thread priority" );
+            return param.sched_priority;
+        }
+    }
+
+
+    /**
+     * Sets the scheduling priority for the associated thread.
+     *
+     * Params:
+     *  val = The new scheduling priority of this thread.
+     */
+    final void priority( int val )
+    {
+        version( Win32 )
+        {
+            if( !SetThreadPriority( m_hndl, val ) )
+                throw new ThreadException( "Unable to set thread priority" );
+        }
+        else version( Posix )
+        {
+            // NOTE: pthread_setschedprio is not implemented on linux, so use
+            //       the more complicated get/set sequence below.
+            //if( pthread_setschedprio( m_addr, val ) )
+            //    throw new ThreadException( "Unable to set thread priority" );
+
+            int         policy;
+            sched_param param;
+
+            if( pthread_getschedparam( m_addr, &policy, &param ) )
+                throw new ThreadException( "Unable to set thread priority" );
+            param.sched_priority = val;
+            if( pthread_setschedparam( m_addr, policy, &param ) )
+                throw new ThreadException( "Unable to set thread priority" );
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Actions on Calling Thread
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Suspends the calling thread for at least the supplied period.  This may
+     * result in multiple OS calls if period is greater than the maximum sleep
+     * duration supported by the operating system.
+     *
+     * Params:
+     *  period = The minimum duration the calling thread should be suspended,
+     *           in 100 nanosecond intervals.
+     *
+     * In:
+     *  period must be non-negative.
+     *
+     * Example:
+     * ------------------------------------------------------------------------
+     *
+     * Thread.sleep( 500 );        // sleep for 50 milliseconds
+     * Thread.sleep( 50_000_000 ); // sleep for 5 seconds
+     *
+     * ------------------------------------------------------------------------
+     */
+    static void sleep( long period )
+    in
+    {
+        assert( period >= 0 );
+    }
+    body
+    {
+        version( Win32 )
+        {
+            enum : uint
+            {
+                TICKS_PER_MILLI  = 10_000,
+                MAX_SLEEP_MILLIS = uint.max - 1
+            }
+
+            period = period < TICKS_PER_MILLI ?
+                        1 :
+                        period / TICKS_PER_MILLI;
+            while( period > MAX_SLEEP_MILLIS )
+            {
+                Sleep( MAX_SLEEP_MILLIS );
+                period -= MAX_SLEEP_MILLIS;
+            }
+            Sleep( cast(uint) period );
+        }
+        else version( Posix )
+        {
+            timespec tin  = void;
+            timespec tout = void;
+
+            enum : uint
+            {
+                NANOS_PER_TICK   = 100,
+                TICKS_PER_SECOND = 10_000_000,
+            }
+            enum : typeof(period)
+            {
+                MAX_SLEEP_TICKS = cast(typeof(period)) tin.tv_sec.max * TICKS_PER_SECOND
+            }
+
+            do
+            {
+                if( period > MAX_SLEEP_TICKS )
+                {
+                    tin.tv_sec = tin.tv_sec.max;
+                    tin.tv_nsec = 0;
+                }
+                else
+                {
+                    tin.tv_sec = cast(typeof(tin.tv_sec)) (period / TICKS_PER_SECOND);
+                    tin.tv_nsec = cast(typeof(tin.tv_nsec)) (period % TICKS_PER_SECOND) * NANOS_PER_TICK;
+                }
+                while( true )
+                {
+                    if( !nanosleep( &tin, &tout ) )
+                        return;
+                    if( getErrno() != EINTR )
+                        throw new ThreadException( "Unable to sleep for the specified duration" );
+                    tin = tout;
+                }
+                period -= (cast(typeof(period)) tin.tv_sec) * TICKS_PER_SECOND;
+                period -= (cast(typeof(period)) tin.tv_nsec) / NANOS_PER_TICK;
+            } while( period > 0 );
+        }
+    }
+
+
+    /**
+     * Forces a context switch to occur away from the calling thread.
+     */
+    static void yield()
+    {
+        version( Win32 )
+        {
+            // NOTE: Sleep(1) is necessary because Sleep(0) does not give
+            //       lower priority threads any timeslice, so looping on
+            //       Sleep(0) could be resource-intensive in some cases.
+            Sleep( 1 );
+        }
+        else version( Posix )
+        {
+            sched_yield();
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Thread Accessors
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Provides a reference to the calling thread.
+     *
+     * Returns:
+     *  The thread object representing the calling thread.  The result of
+     *  deleting this object is undefined.
+     */
+    static Thread getThis()
+    {
+        // NOTE: This function may not be called until thread_init has
+        //       completed.  See thread_suspendAll for more information
+        //       on why this might occur.
+        version( Win32 )
+        {
+            return cast(Thread) TlsGetValue( sm_this );
+        }
+        else version( Posix )
+        {
+            return cast(Thread) pthread_getspecific( sm_this );
+        }
+    }
+
+
+    /**
+     * Provides a list of all threads currently being tracked by the system.
+     *
+     * Returns:
+     *  An array containing references to all threads currently being
+     *  tracked by the system.  The result of deleting any contained
+     *  objects is undefined.
+     */
+    static Thread[] getAll()
+    {
+        synchronized( slock )
+        {
+            size_t   pos = 0;
+            Thread[] buf = new Thread[sm_tlen];
+
+            foreach( Thread t; Thread )
+            {
+                buf[pos++] = t;
+            }
+            return buf;
+        }
+    }
+
+
+    /**
+     * Operates on all threads currently being tracked by the system.  The
+     * result of deleting any Thread object is undefined.
+     *
+     * Params:
+     *  dg = The supplied code as a delegate.
+     *
+     * Returns:
+     *  Zero if all elemented are visited, nonzero if not.
+     */
+    static int opApply( int delegate( inout Thread ) dg )
+    {
+        synchronized( slock )
+        {
+            int ret = 0;
+
+            for( Thread t = sm_tbeg; t; t = t.next )
+            {
+                ret = dg( t );
+                if( ret )
+                    break;
+            }
+            return ret;
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Local Storage Actions
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Indicates the number of local storage pointers available at program
+     * startup.  It is recommended that this number be at least 64.
+     */
+    static const uint LOCAL_MAX = 64;
+
+
+    /**
+     * Reserves a local storage pointer for use and initializes this location
+     * to null for all running threads.
+     *
+     * Returns:
+     *  A key representing the array offset of this memory location.
+     */
+    static uint createLocal()
+    {
+        synchronized( slock )
+        {
+            foreach( uint key, inout bool set; sm_local )
+            {
+                if( !set )
+                {
+                    //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
+                    for( Thread t = sm_tbeg; t; t = t.next )
+                    {
+                        t.m_local[key] = null;
+                    }
+                    set = true;
+                    return key;
+                }
+            }
+            throw new ThreadException( "No more local storage slots available" );
+        }
+    }
+
+
+    /**
+     * Marks the supplied key as available and sets the associated location
+     * to null for all running threads.  It is assumed that any key passed
+     * to this function is valid.  The result of calling this function for
+     * a key which is still in use is undefined.
+     *
+     * Params:
+     *  key = The key to delete.
+     */
+    static void deleteLocal( uint key )
+    {
+        synchronized( slock )
+        {
+            sm_local[key] = false;
+            // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
+            for( Thread t = sm_tbeg; t; t = t.next )
+            {
+                t.m_local[key] = null;
+            }
+        }
+    }
+
+
+    /**
+     * Loads the value stored at key within a thread-local static array.  It is
+     * assumed that any key passed to this function is valid.
+     *
+     * Params:
+     *  key = The location which holds the desired data.
+     *
+     * Returns:
+     *  The data associated with the supplied key.
+     */
+    static void* getLocal( uint key )
+    {
+        return getThis().m_local[key];
+    }
+
+
+    /**
+     * Stores the supplied value at key within a thread-local static array.  It
+     * is assumed that any key passed to this function is valid.
+     *
+     * Params:
+     *  key = The location to store the supplied data.
+     *  val = The data to store.
+     *
+     * Returns:
+     *  A copy of the data which has just been stored.
+     */
+    static void* setLocal( uint key, void* val )
+    {
+        return getThis().m_local[key] = val;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Static Initalizer
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * This initializer is used to set thread constants.  All functional
+     * initialization occurs within thread_init().
+     */
+    static this()
+    {
+        version( Win32 )
+        {
+            PRIORITY_MIN = -15;
+            PRIORITY_MAX =  15;
+        }
+        else version( Posix )
+        {
+            int         policy;
+            sched_param param;
+            pthread_t   self = pthread_self();
+
+            int status = pthread_getschedparam( self, &policy, &param );
+            assert( status == 0 );
+
+            PRIORITY_MIN = sched_get_priority_min( policy );
+            assert( PRIORITY_MIN != -1 );
+
+            PRIORITY_MAX = sched_get_priority_max( policy );
+            assert( PRIORITY_MAX != -1 );
+        }
+    }
+
+
+private:
+    //
+    // Initializes a thread object which has no associated executable function.
+    // This is used for the main thread initialized in thread_init().
+    //
+    this()
+    {
+        m_call = Call.NO;
+        m_curr = &m_main;
+    }
+
+
+    //
+    // Thread entry point.  Invokes the function or delegate passed on
+    // construction (if any).
+    //
+    final void run()
+    {
+        switch( m_call )
+        {
+        case Call.FN:
+            m_fn();
+            break;
+        case Call.DG:
+            m_dg();
+            break;
+        default:
+            break;
+        }
+    }
+
+
+private:
+    //
+    // The type of routine passed on thread construction.
+    //
+    enum Call
+    {
+        NO,
+        FN,
+        DG
+    }
+
+
+    //
+    // Standard types
+    //
+    version( Win32 )
+    {
+        alias uint TLSKey;
+        alias uint ThreadAddr;
+    }
+    else version( Posix )
+    {
+        alias pthread_key_t TLSKey;
+        alias pthread_t     ThreadAddr;
+    }
+
+
+    //
+    // Local storage
+    //
+    static bool[LOCAL_MAX]  sm_local;
+    static TLSKey           sm_this;
+
+    void*[LOCAL_MAX]        m_local;
+
+
+    //
+    // Standard thread data
+    //
+    version( Win32 )
+    {
+        HANDLE          m_hndl;
+    }
+    ThreadAddr          m_addr;
+    Call                m_call;
+    char[]              m_name;
+    union
+    {
+        void function() m_fn;
+        void delegate() m_dg;
+    }
+    size_t              m_sz;
+    version( Posix )
+    {
+        bool            m_isRunning;
+    }
+    bool                m_isDaemon;
+    Object              m_unhandled;
+
+
+private:
+    ///////////////////////////////////////////////////////////////////////////
+    // Storage of Active Thread
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    //
+    // Sets a thread-local reference to the current thread object.
+    //
+    static void setThis( Thread t )
+    {
+        version( Win32 )
+        {
+            TlsSetValue( sm_this, cast(void*) t );
+        }
+        else version( Posix )
+        {
+            pthread_setspecific( sm_this, cast(void*) t );
+        }
+    }
+
+
+private:
+    ///////////////////////////////////////////////////////////////////////////
+    // Thread Context and GC Scanning Support
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    final void pushContext( Context* c )
+    in
+    {
+        assert( !c.within );
+    }
+    body
+    {
+        c.within = m_curr;
+        m_curr = c;
+    }
+
+
+    final void popContext()
+    in
+    {
+        assert( m_curr && m_curr.within );
+    }
+    body
+    {
+        Context* c = m_curr;
+        m_curr = c.within;
+        c.within = null;
+    }
+
+
+    final Context* topContext()
+    in
+    {
+        assert( m_curr );
+    }
+    body
+    {
+        return m_curr;
+    }
+
+
+    static struct Context
+    {
+        void*           bstack,
+                        tstack;
+        Context*        within;
+        Context*        next,
+                        prev;
+    }
+
+
+    Context             m_main;
+    Context*            m_curr;
+    bool                m_lock;
+
+    version( Win32 )
+    {
+        uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
+    }
+
+
+private:
+    ///////////////////////////////////////////////////////////////////////////
+    // GC Scanning Support
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    // NOTE: The GC scanning process works like so:
+    //
+    //          1. Suspend all threads.
+    //          2. Scan the stacks of all suspended threads for roots.
+    //          3. Resume all threads.
+    //
+    //       Step 1 and 3 require a list of all threads in the system, while
+    //       step 2 requires a list of all thread stacks (each represented by
+    //       a Context struct).  Traditionally, there was one stack per thread
+    //       and the Context structs were not necessary.  However, Fibers have
+    //       changed things so that each thread has its own 'main' stack plus
+    //       an arbitrary number of nested stacks (normally referenced via
+    //       m_curr).  Also, there may be 'free-floating' stacks in the system,
+    //       which are Fibers that are not currently executing on any specific
+    //       thread but are still being processed and still contain valid
+    //       roots.
+    //
+    //       To support all of this, the Context struct has been created to
+    //       represent a stack range, and a global list of Context structs has
+    //       been added to enable scanning of these stack ranges.  The lifetime
+    //       (and presence in the Context list) of a thread's 'main' stack will
+    //       be equivalent to the thread's lifetime.  So the Ccontext will be
+    //       added to the list on thread entry, and removed from the list on
+    //       thread exit (which is essentially the same as the presence of a
+    //       Thread object in its own global list).  The lifetime of a Fiber's
+    //       context, however, will be tied to the lifetime of the Fiber object
+    //       itself, and Fibers are expected to add/remove their Context struct
+    //       on construction/deletion.
+
+
+    //
+    // All use of the global lists should synchronize on this lock.
+    //
+    static Object slock()
+    {
+        return Thread.classinfo;
+    }
+
+
+    static Context*     sm_cbeg;
+    static size_t       sm_clen;
+
+    static Thread       sm_tbeg;
+    static size_t       sm_tlen;
+
+    //
+    // Used for ordering threads in the global thread list.
+    //
+    Thread              prev;
+    Thread              next;
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Global Context List Operations
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    //
+    // Add a context to the global context list.
+    //
+    static void add( Context* c )
+    in
+    {
+        assert( c );
+        assert( !c.next && !c.prev );
+    }
+    body
+    {
+        synchronized( slock )
+        {
+            if( sm_cbeg )
+            {
+                c.next = sm_cbeg;
+                sm_cbeg.prev = c;
+            }
+            sm_cbeg = c;
+            ++sm_clen;
+        }
+    }
+
+
+    //
+    // Remove a context from the global context list.
+    //
+    static void remove( Context* c )
+    in
+    {
+        assert( c );
+        assert( c.next || c.prev );
+    }
+    body
+    {
+        synchronized( slock )
+        {
+            if( c.prev )
+                c.prev.next = c.next;
+            if( c.next )
+                c.next.prev = c.prev;
+            if( sm_cbeg == c )
+                sm_cbeg = c.next;
+            --sm_clen;
+        }
+        // NOTE: Don't null out c.next or c.prev because opApply currently
+        //       follows c.next after removing a node.  This could be easily
+        //       addressed by simply returning the next node from this
+        //       function, however, a context should never be re-added to the
+        //       list anyway and having next and prev be non-null is a good way
+        //       to ensure that.
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Global Thread List Operations
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    //
+    // Add a thread to the global thread list.
+    //
+    static void add( Thread t )
+    in
+    {
+        assert( t );
+        assert( !t.next && !t.prev );
+        assert( t.isRunning );
+    }
+    body
+    {
+        synchronized( slock )
+        {
+            if( sm_tbeg )
+            {
+                t.next = sm_tbeg;
+                sm_tbeg.prev = t;
+            }
+            sm_tbeg = t;
+            ++sm_tlen;
+        }
+    }
+
+
+    //
+    // Remove a thread from the global thread list.
+    //
+    static void remove( Thread t )
+    in
+    {
+        assert( t );
+        assert( t.next || t.prev );
+        version( Win32 )
+        {
+            // NOTE: This doesn't work for Posix as m_isRunning must be set to
+            //       false after the thread is removed during normal execution.
+            assert( !t.isRunning );
+        }
+    }
+    body
+    {
+        synchronized( slock )
+        {
+            // NOTE: When a thread is removed from the global thread list its
+            //       main context is invalid and should be removed as well.
+            //       It is possible that t.m_curr could reference more
+            //       than just the main context if the thread exited abnormally
+            //       (if it was terminated), but we must assume that the user
+            //       retains a reference to them and that they may be re-used
+            //       elsewhere.  Therefore, it is the responsibility of any
+            //       object that creates contexts to clean them up properly
+            //       when it is done with them.
+            remove( &t.m_main );
+
+            if( t.prev )
+                t.prev.next = t.next;
+            if( t.next )
+                t.next.prev = t.prev;
+            if( sm_tbeg == t )
+                sm_tbeg = t.next;
+            --sm_tlen;
+        }
+        // NOTE: Don't null out t.next or t.prev because opApply currently
+        //       follows t.next after removing a node.  This could be easily
+        //       addressed by simply returning the next node from this
+        //       function, however, a thread should never be re-added to the
+        //       list anyway and having next and prev be non-null is a good way
+        //       to ensure that.
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// GC Support Routines
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Initializes the thread module.  This function must be called by the
+ * garbage collector on startup and before any other thread routines
+ * are called.
+ */
+extern (C) void thread_init()
+{
+    // NOTE: If thread_init itself performs any allocations then the thread
+    //       routines reserved for garbage collector use may be called while
+    //       thread_init is being processed.  However, since no memory should
+    //       exist to be scanned at this point, it is sufficient for these
+    //       functions to detect the condition and return immediately.
+
+    version( Win32 )
+    {
+        Thread.sm_this = TlsAlloc();
+        assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
+    }
+    else version( Posix )
+    {
+        int         status;
+        sigaction_t sigusr1 = void;
+        sigaction_t sigusr2 = void;
+
+        // This is a quick way to zero-initialize the structs without using
+        // memset or creating a link dependency on their static initializer.
+        (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
+        (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
+
+        // NOTE: SA_RESTART indicates that system calls should restart if they
+        //       are interrupted by a signal, but this is not available on all
+        //       Posix systems, even those that support multithreading.
+        static if( is( typeof( SA_RESTART ) ) )
+            sigusr1.sa_flags = SA_RESTART;
+        else
+            sigusr1.sa_flags   = 0;
+        sigusr1.sa_handler = &thread_suspendHandler;
+        // NOTE: We want to ignore all signals while in this handler, so fill
+        //       sa_mask to indicate this.
+        status = sigfillset( &sigusr1.sa_mask );
+        assert( status == 0 );
+
+        // NOTE: Since SIGUSR2 should only be issued for threads within the
+        //       suspend handler, we don't want this signal to trigger a
+        //       restart.
+        sigusr2.sa_flags   = 0;
+        sigusr2.sa_handler = &thread_resumeHandler;
+        // NOTE: We want to ignore all signals while in this handler, so fill
+        //       sa_mask to indicate this.
+        status = sigfillset( &sigusr2.sa_mask );
+        assert( status == 0 );
+
+        status = sigaction( SIGUSR1, &sigusr1, null );
+        assert( status == 0 );
+
+        status = sigaction( SIGUSR2, &sigusr2, null );
+        assert( status == 0 );
+
+        status = sem_init( &suspendCount, 0, 0 );
+        assert( status == 0 );
+
+        status = pthread_key_create( &Thread.sm_this, null );
+        assert( status == 0 );
+    }
+
+    thread_attachThis();
+}
+
+
+/**
+ * Registers the calling thread for use with the D Runtime.  If this routine
+ * is called for a thread which is already registered, the result is undefined.
+ */
+extern (C) void thread_attachThis()
+{
+    version( Win32 )
+    {
+        Thread          thisThread  = new Thread();
+        Thread.Context* thisContext = &thisThread.m_main;
+        assert( thisContext == thisThread.m_curr );
+
+        thisThread.m_addr  = GetCurrentThreadId();
+        thisThread.m_hndl  = GetCurrentThreadHandle();
+        thisContext.bstack = getStackBottom();
+        thisContext.tstack = thisContext.bstack;
+
+        thisThread.m_isDaemon = true;
+
+        Thread.setThis( thisThread );
+    }
+    else version( Posix )
+    {
+        Thread          thisThread  = new Thread();
+        Thread.Context* thisContext = thisThread.m_curr;
+        assert( thisContext == &thisThread.m_main );
+
+        thisThread.m_addr  = pthread_self();
+        thisContext.bstack = getStackBottom();
+        thisContext.tstack = thisContext.bstack;
+
+        thisThread.m_isRunning = true;
+        thisThread.m_isDaemon  = true;
+
+        Thread.setThis( thisThread );
+    }
+
+    Thread.add( thisThread );
+    Thread.add( thisContext );
+}
+
+
+/**
+ * Deregisters the calling thread from use with the runtime.  If this routine
+ * is called for a thread which is already registered, the result is undefined.
+ */
+extern (C) void thread_detachThis()
+{
+    Thread.remove( Thread.getThis() );
+}
+
+
+/**
+ * Joins all non-daemon threads that are currently running.  This is done by
+ * performing successive scans through the thread list until a scan consists
+ * of only daemon threads.
+ */
+extern (C) void thread_joinAll()
+{
+
+    while( true )
+    {
+        Thread nonDaemon = null;
+
+        foreach( t; Thread )
+        {
+            if( !t.isDaemon )
+            {
+                nonDaemon = t;
+                break;
+            }
+        }
+        if( nonDaemon is null )
+            return;
+        nonDaemon.join();
+    }
+}
+
+
+/**
+ * Performs intermediate shutdown of the thread module.
+ */
+static ~this()
+{
+    // NOTE: The functionality related to garbage collection must be minimally
+    //       operable after this dtor completes.  Therefore, only minimal
+    //       cleanup may occur.
+
+    for( Thread t = Thread.sm_tbeg; t; t = t.next )
+    {
+        if( !t.isRunning )
+            Thread.remove( t );
+    }
+}
+
+
+// Used for needLock below
+private bool multiThreadedFlag = false;
+
+
+/**
+ * This function is used to determine whether the the process is
+ * multi-threaded.  Optimizations may only be performed on this
+ * value if the programmer can guarantee that no path from the
+ * enclosed code will start a thread.
+ *
+ * Returns:
+ *  True if Thread.start() has been called in this process.
+ */
+extern (C) bool thread_needLock()
+{
+    return multiThreadedFlag;
+}
+
+
+// Used for suspendAll/resumeAll below
+private uint suspendDepth = 0;
+
+
+/**
+ * Suspend all threads but the calling thread for "stop the world" garbage
+ * collection runs.  This function may be called multiple times, and must
+ * be followed by a matching number of calls to thread_resumeAll before
+ * processing is resumed.
+ *
+ * Throws:
+ *  ThreadException if the suspend operation fails for a running thread.
+ */
+extern (C) void thread_suspendAll()
+{
+    /**
+     * Suspend the specified thread and load stack and register information for
+     * use by thread_scanAll.  If the supplied thread is the calling thread,
+     * stack and register information will be loaded but the thread will not
+     * be suspended.  If the suspend operation fails and the thread is not
+     * running then it will be removed from the global thread list, otherwise
+     * an exception will be thrown.
+     *
+     * Params:
+     *  t = The thread to suspend.
+     *
+     * Throws:
+     *  ThreadException if the suspend operation fails for a running thread.
+     */
+    void suspend( Thread t )
+    {
+        version( Win32 )
+        {
+            if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
+            {
+                if( !t.isRunning )
+                {
+                    Thread.remove( t );
+                    return;
+                }
+                throw new ThreadException( "Unable to suspend thread" );
+            }
+
+            CONTEXT context = void;
+            context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
+
+            if( !GetThreadContext( t.m_hndl, &context ) )
+                throw new ThreadException( "Unable to load thread context" );
+            if( !t.m_lock )
+                t.m_curr.tstack = cast(void*) context.Esp;
+            // edi,esi,ebp,esp,ebx,edx,ecx,eax
+            t.m_reg[0] = context.Edi;
+            t.m_reg[1] = context.Esi;
+            t.m_reg[2] = context.Ebp;
+            t.m_reg[3] = context.Esp;
+            t.m_reg[4] = context.Ebx;
+            t.m_reg[5] = context.Edx;
+            t.m_reg[6] = context.Ecx;
+            t.m_reg[7] = context.Eax;
+        }
+        else version( Posix )
+        {
+            if( t.m_addr != pthread_self() )
+            {
+                if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
+                {
+                    if( !t.isRunning )
+                    {
+                        Thread.remove( t );
+                        return;
+                    }
+                    throw new ThreadException( "Unable to suspend thread" );
+                }
+                // NOTE: It's really not ideal to wait for each thread to
+                //       signal individually -- rather, it would be better to
+                //       suspend them all and wait once at the end.  However,
+                //       semaphores don't really work this way, and the obvious
+                //       alternative (looping on an atomic suspend count)
+                //       requires either the atomic module (which only works on
+                //       x86) or other specialized functionality.  It would
+                //       also be possible to simply loop on sem_wait at the
+                //       end, but I'm not convinced that this would be much
+                //       faster than the current approach.
+                sem_wait( &suspendCount );
+            }
+            else if( !t.m_lock )
+            {
+                t.m_curr.tstack = getStackTop();
+            }
+        }
+    }
+
+
+    // NOTE: We've got an odd chicken & egg problem here, because while the GC
+    //       is required to call thread_init before calling any other thread
+    //       routines, thread_init may allocate memory which could in turn
+    //       trigger a collection.  Thus, thread_suspendAll, thread_scanAll,
+    //       and thread_resumeAll must be callable before thread_init
+    //       completes, with the assumption that no other GC memory has yet
+    //       been allocated by the system, and thus there is no risk of losing
+    //       data if the global thread list is empty.  The check of
+    //       Thread.sm_tbeg below is done to ensure thread_init has completed,
+    //       and therefore that calling Thread.getThis will not result in an
+    //       error.  For the short time when Thread.sm_tbeg is null, there is
+    //       no reason not to simply call the multithreaded code below, with
+    //       the expectation that the foreach loop will never be entered.
+    if( !multiThreadedFlag && Thread.sm_tbeg )
+    {
+        if( ++suspendDepth == 1 )
+            suspend( Thread.getThis() );
+        return;
+    }
+    synchronized( Thread.slock )
+    {
+        if( ++suspendDepth > 1 )
+            return;
+
+        // NOTE: I'd really prefer not to check isRunning within this loop but
+        //       not doing so could be problematic if threads are termianted
+        //       abnormally and a new thread is created with the same thread
+        //       address before the next GC run.  This situation might cause
+        //       the same thread to be suspended twice, which would likely
+        //       cause the second suspend to fail, the garbage collection to
+        //       abort, and Bad Things to occur.
+        for( Thread t = Thread.sm_tbeg; t; t = t.next )
+        {
+            if( t.isRunning )
+                suspend( t );
+            else
+                Thread.remove( t );
+        }
+
+        version( Posix )
+        {
+            // wait on semaphore -- see note in suspend for
+            // why this is currently not implemented
+        }
+    }
+}
+
+
+/**
+ * Resume all threads but the calling thread for "stop the world" garbage
+ * collection runs.  This function must be called once for each preceding
+ * call to thread_suspendAll before the threads are actually resumed.
+ *
+ * In:
+ *  This routine must be preceded by a call to thread_suspendAll.
+ *
+ * Throws:
+ *  ThreadException if the resume operation fails for a running thread.
+ */
+extern (C) void thread_resumeAll()
+in
+{
+    assert( suspendDepth > 0 );
+}
+body
+{
+    /**
+     * Resume the specified thread and unload stack and register information.
+     * If the supplied thread is the calling thread, stack and register
+     * information will be unloaded but the thread will not be resumed.  If
+     * the resume operation fails and the thread is not running then it will
+     * be removed from the global thread list, otherwise an exception will be
+     * thrown.
+     *
+     * Params:
+     *  t = The thread to resume.
+     *
+     * Throws:
+     *  ThreadException if the resume fails for a running thread.
+     */
+    void resume( Thread t )
+    {
+        version( Win32 )
+        {
+            if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
+            {
+                if( !t.isRunning )
+                {
+                    Thread.remove( t );
+                    return;
+                }
+                throw new ThreadException( "Unable to resume thread" );
+            }
+
+            if( !t.m_lock )
+                t.m_curr.tstack = t.m_curr.bstack;
+            t.m_reg[0 .. $] = 0;
+        }
+        else version( Posix )
+        {
+            if( t.m_addr != pthread_self() )
+            {
+                if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
+                {
+                    if( !t.isRunning )
+                    {
+                        Thread.remove( t );
+                        return;
+                    }
+                    throw new ThreadException( "Unable to resume thread" );
+                }
+            }
+            else if( !t.m_lock )
+            {
+                t.m_curr.tstack = t.m_curr.bstack;
+            }
+        }
+    }
+
+
+    // NOTE: See thread_suspendAll for the logic behind this.
+    if( !multiThreadedFlag && Thread.sm_tbeg )
+    {
+        if( --suspendDepth == 0 )
+            resume( Thread.getThis() );
+        return;
+    }
+    synchronized( Thread.slock )
+    {
+        if( --suspendDepth > 0 )
+            return;
+
+        for( Thread t = Thread.sm_tbeg; t; t = t.next )
+        {
+            resume( t );
+        }
+    }
+}
+
+
+private alias void delegate( void*, void* ) scanAllThreadsFn;
+
+
+/**
+ * The main entry point for garbage collection.  The supplied delegate
+ * will be passed ranges representing both stack and register values.
+ *
+ * Params:
+ *  scan        = The scanner function.  It should scan from p1 through p2 - 1.
+ *  curStackTop = An optional pointer to the top of the calling thread's stack.
+ *
+ * In:
+ *  This routine must be preceded by a call to thread_suspendAll.
+ */
+extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null )
+in
+{
+    assert( suspendDepth > 0 );
+}
+body
+{
+    Thread  thisThread  = null;
+    void*   oldStackTop = null;
+
+    if( curStackTop && Thread.sm_tbeg )
+    {
+        thisThread  = Thread.getThis();
+        if( !thisThread.m_lock )
+        {
+            oldStackTop = thisThread.m_curr.tstack;
+            thisThread.m_curr.tstack = curStackTop;
+        }
+    }
+
+    scope( exit )
+    {
+        if( curStackTop && Thread.sm_tbeg )
+        {
+            if( !thisThread.m_lock )
+            {
+                thisThread.m_curr.tstack = oldStackTop;
+            }
+        }
+    }
+
+    // NOTE: Synchronizing on Thread.slock is not needed because this
+    //       function may only be called after all other threads have
+    //       been suspended from within the same lock.
+    for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
+    {
+        version( StackGrowsDown )
+        {
+            // NOTE: We can't index past the bottom of the stack
+            //       so don't do the "+1" for StackGrowsDown.
+            if( c.tstack && c.tstack < c.bstack )
+                scan( c.tstack, c.bstack );
+        }
+        else
+        {
+            if( c.bstack && c.bstack < c.tstack )
+                scan( c.bstack, c.tstack + 1 );
+        }
+    }
+    version( Win32 )
+    {
+        for( Thread t = Thread.sm_tbeg; t; t = t.next )
+        {
+            scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length );
+        }
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Thread Local
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * This class encapsulates the operations required to initialize, access, and
+ * destroy thread local data.
+ */
+class ThreadLocal( T )
+{
+    ///////////////////////////////////////////////////////////////////////////
+    // Initialization
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Initializes thread local storage for the indicated value which will be
+     * initialized to def for all threads.
+     *
+     * Params:
+     *  def = The default value to return if no value has been explicitly set.
+     */
+    this( T def = T.init )
+    {
+        m_def = def;
+        m_key = Thread.createLocal();
+    }
+
+
+    ~this()
+    {
+        Thread.deleteLocal( m_key );
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Accessors
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Gets the value last set by the calling thread, or def if no such value
+     * has been set.
+     *
+     * Returns:
+     *  The stored value or def if no value is stored.
+     */
+    T val()
+    {
+        Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
+
+        return wrap ? wrap.val : m_def;
+    }
+
+
+    /**
+     * Copies newval to a location specific to the calling thread, and returns
+     * newval.
+     *
+     * Params:
+     *  newval = The value to set.
+     *
+     * Returns:
+     *  The value passed to this function.
+     */
+    T val( T newval )
+    {
+        Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
+
+        if( wrap is null )
+        {
+            wrap = new Wrap;
+            Thread.setLocal( m_key, wrap );
+        }
+        wrap.val = newval;
+        return newval;
+    }
+
+
+private:
+    //
+    // A wrapper for the stored data.  This is needed for determining whether
+    // set has ever been called for this thread (and therefore whether the
+    // default value should be returned) and also to flatten the differences
+    // between data that is smaller and larger than (void*).sizeof.  The
+    // obvious tradeoff here is an extra per-thread allocation for each
+    // ThreadLocal value as compared to calling the Thread routines directly.
+    //
+    struct Wrap
+    {
+        T   val;
+    }
+
+
+    T       m_def;
+    uint    m_key;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Thread Group
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * This class is intended to simplify certain common programming techniques.
+ */
+class ThreadGroup
+{
+    /**
+     * Creates and starts a new Thread object that executes fn and adds it to
+     * the list of tracked threads.
+     *
+     * Params:
+     *  fn = The thread function.
+     *
+     * Returns:
+     *  A reference to the newly created thread.
+     */
+    final Thread create( void function() fn )
+    {
+        Thread t = new Thread( fn );
+
+        t.start();
+        synchronized( this )
+        {
+            m_all[t] = t;
+        }
+        return t;
+    }
+
+
+    /**
+     * Creates and starts a new Thread object that executes dg and adds it to
+     * the list of tracked threads.
+     *
+     * Params:
+     *  dg = The thread function.
+     *
+     * Returns:
+     *  A reference to the newly created thread.
+     */
+    final Thread create( void delegate() dg )
+    {
+        Thread t = new Thread( dg );
+
+        t.start();
+        synchronized( this )
+        {
+            m_all[t] = t;
+        }
+        return t;
+    }
+
+
+    /**
+     * Add t to the list of tracked threads if it is not already being tracked.
+     *
+     * Params:
+     *  t = The thread to add.
+     *
+     * In:
+     *  t must not be null.
+     */
+    final void add( Thread t )
+    in
+    {
+        assert( t );
+    }
+    body
+    {
+        synchronized( this )
+        {
+            m_all[t] = t;
+        }
+    }
+
+
+    /**
+     * Removes t from the list of tracked threads.  No operation will be
+     * performed if t is not currently being tracked by this object.
+     *
+     * Params:
+     *  t = The thread to remove.
+     *
+     * In:
+     *  t must not be null.
+     */
+    final void remove( Thread t )
+    in
+    {
+        assert( t );
+    }
+    body
+    {
+        synchronized( this )
+        {
+            m_all.remove( t );
+        }
+    }
+
+
+    /**
+     * Operates on all threads currently tracked by this object.
+     */
+    final int opApply( int delegate( inout Thread ) dg )
+    {
+        synchronized( this )
+        {
+            int ret = 0;
+
+            // NOTE: This loop relies on the knowledge that m_all uses the
+            //       Thread object for both the key and the mapped value.
+            foreach( Thread t; m_all.keys )
+            {
+                ret = dg( t );
+                if( ret )
+                    break;
+            }
+            return ret;
+        }
+    }
+
+
+    /**
+     * Iteratively joins all tracked threads.  This function will block add,
+     * remove, and opApply until it completes.
+     *
+     * Params:
+     *  rethrow = Rethrow any unhandled exception which may have caused the
+     *            current thread to terminate.
+     *
+     * Throws:
+     *  Any exception not handled by the joined threads.
+     */
+    final void joinAll( bool rethrow = true )
+    {
+        synchronized( this )
+        {
+            // NOTE: This loop relies on the knowledge that m_all uses the
+            //       Thread object for both the key and the mapped value.
+            foreach( Thread t; m_all.keys )
+            {
+                t.join( rethrow );
+            }
+        }
+    }
+
+
+private:
+    Thread[Thread]  m_all;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Fiber Platform Detection and Memory Allocation
+///////////////////////////////////////////////////////////////////////////////
+
+
+private
+{
+    version( D_InlineAsm_X86 )
+    {
+        version( X86_64 )
+        {
+
+        }
+        else
+        {
+            version( Win32 )
+                version = AsmX86_Win32;
+            else version( Posix )
+                version = AsmX86_Posix;
+        }
+    }
+    else version( PPC )
+    {
+        version( Posix )
+            version = AsmPPC_Posix;
+    }
+
+    version( LLVM_InlineAsm_X86 )
+    {
+        version( Win32 )
+            version = LLVM_AsmX86_Win32;
+        else version( Posix )
+            version = LLVM_AsmX86_Posix;
+    }
+    else version( LLVM_InlineAsm_X86_64 )
+    {
+        version( Posix )
+            version = LLVM_AsmX86_64_Posix;
+    }
+
+    version( Posix )
+    {
+        import stdc.posix.unistd;   // for sysconf
+        import stdc.posix.sys.mman; // for mmap
+        import stdc.posix.stdlib;   // for malloc, valloc, free
+
+        version( AsmX86_Win32 ) {} else
+        version( AsmX86_Posix ) {} else
+        version( AsmPPC_Posix ) {} else
+        version( LLVM_AsmX86_Win32 ) {} else
+        version( LLVM_AsmX86_Posix ) {} else
+        //TODO: Enable when x86-64 Posix supports fibers
+        //version( LLVM_AsmX86_64_Posix ) {} else
+        {
+            // NOTE: The ucontext implementation requires architecture specific
+            //       data definitions to operate so testing for it must be done
+            //       by checking for the existence of ucontext_t rather than by
+            //       a version identifier.  Please note that this is considered
+            //       an obsolescent feature according to the POSIX spec, so a
+            //       custom solution is still preferred.
+            import stdc.posix.ucontext;
+        }
+    }
+
+    const size_t PAGESIZE;
+}
+
+
+static this()
+{
+    static if( is( typeof( GetSystemInfo ) ) )
+    {
+        SYSTEM_INFO info;
+        GetSystemInfo( &info );
+
+        PAGESIZE = info.dwPageSize;
+        assert( PAGESIZE < int.max );
+    }
+    else static if( is( typeof( sysconf ) ) &&
+                    is( typeof( _SC_PAGESIZE ) ) )
+    {
+        PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
+        assert( PAGESIZE < int.max );
+    }
+    else
+    {
+        version( PPC )
+            PAGESIZE = 8192;
+        else
+            PAGESIZE = 4096;
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Fiber Entry Point and Context Switch
+///////////////////////////////////////////////////////////////////////////////
+
+
+private
+{
+    extern (C) void fiber_entryPoint()
+    {
+        Fiber   obj = Fiber.getThis();
+        assert( obj );
+
+        assert( Thread.getThis().m_curr is obj.m_ctxt );
+        volatile Thread.getThis().m_lock = false;
+        obj.m_ctxt.tstack = obj.m_ctxt.bstack;
+        obj.m_state = Fiber.State.EXEC;
+
+        try
+        {
+            obj.run();
+        }
+        catch( Object o )
+        {
+            obj.m_unhandled = o;
+        }
+
+        static if( is( ucontext_t ) )
+          obj.m_ucur = &obj.m_utxt;
+
+        obj.m_state = Fiber.State.TERM;
+        obj.switchOut();
+    }
+
+
+  // NOTE: If AsmPPC_Posix is defined then the context switch routine will
+  //       be defined externally until GDC supports inline PPC ASM.
+  version( AsmPPC_Posix )
+    extern (C) void fiber_switchContext( void** oldp, void* newp );
+  else
+    extern (C) void fiber_switchContext( void** oldp, void* newp )
+    {
+        // NOTE: The data pushed and popped in this routine must match the
+        //       default stack created by Fiber.initStack or the initial
+        //       switch into a new context will fail.
+
+        version( AsmX86_Win32 )
+        {
+            asm
+            {
+                naked;
+
+                // save current stack state
+                push EBP;
+                mov  EBP, ESP;
+                push EAX;
+                push dword ptr FS:[0];
+                push dword ptr FS:[4];
+                push dword ptr FS:[8];
+                push EBX;
+                push ESI;
+                push EDI;
+
+                // store oldp again with more accurate address
+                mov EAX, dword ptr 8[EBP];
+                mov [EAX], ESP;
+                // load newp to begin context switch
+                mov ESP, dword ptr 12[EBP];
+
+                // load saved state from new stack
+                pop EDI;
+                pop ESI;
+                pop EBX;
+                pop dword ptr FS:[8];
+                pop dword ptr FS:[4];
+                pop dword ptr FS:[0];
+                pop EAX;
+                pop EBP;
+
+                // 'return' to complete switch
+                ret;
+            }
+        }
+        else version( AsmX86_Posix )
+        {
+            asm
+            {
+                naked;
+
+                // save current stack state
+                push EBP;
+                mov  EBP, ESP;
+                push EAX;
+                push EBX;
+                push ESI;
+                push EDI;
+
+                // store oldp again with more accurate address
+                mov EAX, dword ptr 8[EBP];
+                mov [EAX], ESP;
+                // load newp to begin context switch
+                mov ESP, dword ptr 12[EBP];
+
+                // load saved state from new stack
+                pop EDI;
+                pop ESI;
+                pop EBX;
+                pop EAX;
+                pop EBP;
+
+                // 'return' to complete switch
+                ret;
+            }
+        }
+        else version( LLVM_AsmX86_Posix )
+        {
+            asm
+            {
+                // clobber registers to save
+                inc EBX;
+                inc ESI;
+                inc EDI;
+
+                // store oldp again with more acc
+                mov EAX, oldp;
+                mov [EAX], ESP;
+                // load newp to begin context swi
+                mov ESP, newp;
+            }
+        }
+/+
+        version( LLVM_AsmX86_64_Posix )
+        {
+            //TODO: Fiber implementation here
+        }
++/
+        else static if( is( ucontext_t ) )
+        {
+            Fiber   cfib = Fiber.getThis();
+            void*   ucur = cfib.m_ucur;
+
+            *oldp = &ucur;
+            swapcontext( **(cast(ucontext_t***) oldp),
+                          *(cast(ucontext_t**)  newp) );
+        }
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Fiber
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * This class provides a cooperative concurrency mechanism integrated with the
+ * threading and garbage collection functionality.  Calling a fiber may be
+ * considered a blocking operation that returns when the fiber yields (via
+ * Fiber.yield()).  Execution occurs within the context of the calling thread
+ * so synchronization is not necessary to guarantee memory visibility so long
+ * as the same thread calls the fiber each time.  Please note that there is no
+ * requirement that a fiber be bound to one specific thread.  Rather, fibers
+ * may be freely passed between threads so long as they are not currently
+ * executing.  Like threads, a new fiber thread may be created using either
+ * derivation or composition, as in the following example.
+ *
+ * Example:
+ * ----------------------------------------------------------------------
+ *
+ * class DerivedFiber : Fiber
+ * {
+ *     this()
+ *     {
+ *         super( &run );
+ *     }
+ *
+ * private :
+ *     void run()
+ *     {
+ *         printf( "Derived fiber running.\n" );
+ *     }
+ * }
+ *
+ * void fiberFunc()
+ * {
+ *     printf( "Composed fiber running.\n" );
+ *     Fiber.yield();
+ *     printf( "Composed fiber running.\n" );
+ * }
+ *
+ * // create instances of each type
+ * Fiber derived = new DerivedFiber();
+ * Fiber composed = new Fiber( &fiberFunc );
+ *
+ * // call both fibers once
+ * derived.call();
+ * composed.call();
+ * printf( "Execution returned to calling context.\n" );
+ * composed.call();
+ *
+ * // since each fiber has run to completion, each should have state TERM
+ * assert( derived.state == Fiber.State.TERM );
+ * assert( composed.state == Fiber.State.TERM );
+ *
+ * ----------------------------------------------------------------------
+ *
+ * Authors: Based on a design by Mikola Lysenko.
+ */
+class Fiber
+{
+    ///////////////////////////////////////////////////////////////////////////
+    // Initialization
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Initializes a fiber object which is associated with a static
+     * D function.
+     *
+     * Params:
+     *  fn = The thread function.
+     *  sz = The stack size for this fiber.
+     *
+     * In:
+     *  fn must not be null.
+     */
+    this( void function() fn, size_t sz = PAGESIZE )
+    in
+    {
+        assert( fn );
+    }
+    body
+    {
+        m_fn    = fn;
+        m_call  = Call.FN;
+        m_state = State.HOLD;
+        allocStack( sz );
+        initStack();
+    }
+
+
+    /**
+     * Initializes a fiber object which is associated with a dynamic
+     * D function.
+     *
+     * Params:
+     *  dg = The thread function.
+     *  sz = The stack size for this fiber.
+     *
+     * In:
+     *  dg must not be null.
+     */
+    this( void delegate() dg, size_t sz = PAGESIZE )
+    in
+    {
+        assert( dg );
+    }
+    body
+    {
+        m_dg    = dg;
+        m_call  = Call.DG;
+        m_state = State.HOLD;
+        allocStack( sz );
+        initStack();
+    }
+
+
+    /**
+     * Cleans up any remaining resources used by this object.
+     */
+    ~this()
+    {
+        // NOTE: A live reference to this object will exist on its associated
+        //       stack from the first time its call() method has been called
+        //       until its execution completes with State.TERM.  Thus, the only
+        //       times this dtor should be called are either if the fiber has
+        //       terminated (and therefore has no active stack) or if the user
+        //       explicitly deletes this object.  The latter case is an error
+        //       but is not easily tested for, since State.HOLD may imply that
+        //       the fiber was just created but has never been run.  There is
+        //       not a compelling case to create a State.INIT just to offer a
+        //       means of ensuring the user isn't violating this object's
+        //       contract, so for now this requirement will be enforced by
+        //       documentation only.
+        freeStack();
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // General Actions
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Transfers execution to this fiber object.  The calling context will be
+     * suspended until the fiber calls Fiber.yield() or until it terminates
+     * via an unhandled exception.
+     *
+     * Params:
+     *  rethrow = Rethrow any unhandled exception which may have caused this
+     *            fiber to terminate.
+     *
+     * In:
+     *  This fiber must be in state HOLD.
+     *
+     * Throws:
+     *  Any exception not handled by the joined thread.
+     *
+     * Returns:
+     *  Any exception not handled by this fiber if rethrow = false, null
+     *  otherwise.
+     */
+    final Object call( bool rethrow = true )
+    in
+    {
+        assert( m_state == State.HOLD );
+    }
+    body
+    {
+        Fiber   cur = getThis();
+
+        static if( is( ucontext_t ) )
+          m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
+
+        setThis( this );
+        this.switchIn();
+        setThis( cur );
+
+        static if( is( ucontext_t ) )
+          m_ucur = null;
+
+        // NOTE: If the fiber has terminated then the stack pointers must be
+        //       reset.  This ensures that the stack for this fiber is not
+        //       scanned if the fiber has terminated.  This is necessary to
+        //       prevent any references lingering on the stack from delaying
+        //       the collection of otherwise dead objects.  The most notable
+        //       being the current object, which is referenced at the top of
+        //       fiber_entryPoint.
+        if( m_state == State.TERM )
+        {
+            m_ctxt.tstack = m_ctxt.bstack;
+        }
+        if( m_unhandled )
+        {
+            Object obj  = m_unhandled;
+            m_unhandled = null;
+            if( rethrow )
+                throw obj;
+            return obj;
+        }
+        return null;
+    }
+
+
+    /**
+     * Resets this fiber so that it may be re-used.  This routine may only be
+     * called for fibers that have terminated, as doing otherwise could result
+     * in scope-dependent functionality that is not executed.  Stack-based
+     * classes, for example, may not be cleaned up properly if a fiber is reset
+     * before it has terminated.
+     *
+     * In:
+     *  This fiber must be in state TERM.
+     */
+    final void reset()
+    in
+    {
+        assert( m_state == State.TERM );
+        assert( m_ctxt.tstack == m_ctxt.bstack );
+    }
+    body
+    {
+        m_state = State.HOLD;
+        initStack();
+        m_unhandled = null;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // General Properties
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * A fiber may occupy one of three states: HOLD, EXEC, and TERM.  The HOLD
+     * state applies to any fiber that is suspended and ready to be called.
+     * The EXEC state will be set for any fiber that is currently executing.
+     * And the TERM state is set when a fiber terminates.  Once a fiber
+     * terminates, it must be reset before it may be called again.
+     */
+    enum State
+    {
+        HOLD,   ///
+        EXEC,   ///
+        TERM    ///
+    }
+
+
+    /**
+     * Gets the current state of this fiber.
+     *
+     * Returns:
+     *  The state of this fiber as an enumerated value.
+     */
+    final State state()
+    {
+        return m_state;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Actions on Calling Fiber
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Forces a context switch to occur away from the calling fiber.
+     */
+    static void yield()
+    {
+        Fiber   cur = getThis();
+        assert( cur, "Fiber.yield() called with no active fiber" );
+        assert( cur.m_state == State.EXEC );
+
+        static if( is( ucontext_t ) )
+          cur.m_ucur = &cur.m_utxt;
+
+        cur.m_state = State.HOLD;
+        cur.switchOut();
+        cur.m_state = State.EXEC;
+    }
+
+
+    /**
+     * Forces a context switch to occur away from the calling fiber and then
+     * throws obj in the calling fiber.
+     *
+     * Params:
+     *  obj = The object to throw.
+     *
+     * In:
+     *  obj must not be null.
+     */
+    static void yieldAndThrow( Object obj )
+    in
+    {
+        assert( obj );
+    }
+    body
+    {
+        Fiber   cur = getThis();
+        assert( cur, "Fiber.yield() called with no active fiber" );
+        assert( cur.m_state == State.EXEC );
+
+        static if( is( ucontext_t ) )
+          cur.m_ucur = &cur.m_utxt;
+
+        cur.m_unhandled = obj;
+        cur.m_state = State.HOLD;
+        cur.switchOut();
+        cur.m_state = State.EXEC;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Fiber Accessors
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Provides a reference to the calling fiber or null if no fiber is
+     * currently active.
+     *
+     * Returns:
+     *  The fiber object representing the calling fiber or null if no fiber
+     *  is currently active.  The result of deleting this object is undefined.
+     */
+    static Fiber getThis()
+    {
+        version( Win32 )
+        {
+            return cast(Fiber) TlsGetValue( sm_this );
+        }
+        else version( Posix )
+        {
+            return cast(Fiber) pthread_getspecific( sm_this );
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Static Initialization
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    static this()
+    {
+        version( Win32 )
+        {
+            sm_this = TlsAlloc();
+            assert( sm_this != TLS_OUT_OF_INDEXES );
+        }
+        else version( Posix )
+        {
+            int status;
+
+            status = pthread_key_create( &sm_this, null );
+            assert( status == 0 );
+
+          static if( is( ucontext_t ) )
+          {
+            status = getcontext( &sm_utxt );
+            assert( status == 0 );
+          }
+        }
+    }
+
+
+private:
+    //
+    // Initializes a fiber object which has no associated executable function.
+    //
+    this()
+    {
+        m_call = Call.NO;
+    }
+
+
+    //
+    // Fiber entry point.  Invokes the function or delegate passed on
+    // construction (if any).
+    //
+    final void run()
+    {
+        switch( m_call )
+        {
+        case Call.FN:
+            m_fn();
+            break;
+        case Call.DG:
+            m_dg();
+            break;
+        default:
+            break;
+        }
+    }
+
+
+private:
+    //
+    // The type of routine passed on fiber construction.
+    //
+    enum Call
+    {
+        NO,
+        FN,
+        DG
+    }
+
+
+    //
+    // Standard fiber data
+    //
+    Call                m_call;
+    union
+    {
+        void function() m_fn;
+        void delegate() m_dg;
+    }
+    bool                m_isRunning;
+    Object              m_unhandled;
+    State               m_state;
+
+
+private:
+    ///////////////////////////////////////////////////////////////////////////
+    // Stack Management
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    //
+    // Allocate a new stack for this fiber.
+    //
+    final void allocStack( size_t sz )
+    in
+    {
+        assert( !m_pmem && !m_ctxt );
+    }
+    body
+    {
+        // adjust alloc size to a multiple of PAGESIZE
+        sz += PAGESIZE - 1;
+        sz -= sz % PAGESIZE;
+
+        // NOTE: This instance of Thread.Context is dynamic so Fiber objects
+        //       can be collected by the GC so long as no user level references
+        //       to the object exist.  If m_ctxt were not dynamic then its
+        //       presence in the global context list would be enough to keep
+        //       this object alive indefinitely.  An alternative to allocating
+        //       room for this struct explicitly would be to mash it into the
+        //       base of the stack being allocated below.  However, doing so
+        //       requires too much special logic to be worthwhile.
+        m_ctxt = new Thread.Context;
+
+        static if( is( typeof( VirtualAlloc ) ) )
+        {
+            // reserve memory for stack
+            m_pmem = VirtualAlloc( null,
+                                   sz + PAGESIZE,
+                                   MEM_RESERVE,
+                                   PAGE_NOACCESS );
+            if( !m_pmem )
+            {
+                throw new FiberException( "Unable to reserve memory for stack" );
+            }
+
+            version( StackGrowsDown )
+            {
+                void* stack = m_pmem + PAGESIZE;
+                void* guard = m_pmem;
+                void* pbase = stack + sz;
+            }
+            else
+            {
+                void* stack = m_pmem;
+                void* guard = m_pmem + sz;
+                void* pbase = stack;
+            }
+
+            // allocate reserved stack segment
+            stack = VirtualAlloc( stack,
+                                  sz,
+                                  MEM_COMMIT,
+                                  PAGE_READWRITE );
+            if( !stack )
+            {
+                throw new FiberException( "Unable to allocate memory for stack" );
+            }
+
+            // allocate reserved guard page
+            guard = VirtualAlloc( guard,
+                                  PAGESIZE,
+                                  MEM_COMMIT,
+                                  PAGE_READWRITE | PAGE_GUARD );
+            if( !guard )
+            {
+                throw new FiberException( "Unable to create guard page for stack" );
+            }
+
+            m_ctxt.bstack = pbase;
+            m_ctxt.tstack = pbase;
+            m_size = sz;
+        }
+        else
+        {   static if( is( typeof( mmap ) ) )
+            {
+                m_pmem = mmap( null,
+                               sz,
+                               PROT_READ | PROT_WRITE,
+                               MAP_PRIVATE | MAP_ANON,
+                               -1,
+                               0 );
+                if( m_pmem == MAP_FAILED )
+                    m_pmem = null;
+            }
+            else static if( is( typeof( valloc ) ) )
+            {
+                m_pmem = valloc( sz );
+            }
+            else static if( is( typeof( malloc ) ) )
+            {
+                m_pmem = malloc( sz );
+            }
+            else
+            {
+                m_pmem = null;
+            }
+
+            if( !m_pmem )
+            {
+                throw new FiberException( "Unable to allocate memory for stack" );
+            }
+
+            version( StackGrowsDown )
+            {
+                m_ctxt.bstack = m_pmem + sz;
+                m_ctxt.tstack = m_pmem + sz;
+            }
+            else
+            {
+                m_ctxt.bstack = m_pmem;
+                m_ctxt.tstack = m_pmem;
+            }
+            m_size = sz;
+        }
+
+        Thread.add( m_ctxt );
+    }
+
+
+    //
+    // Free this fiber's stack.
+    //
+    final void freeStack()
+    in
+    {
+        assert( m_pmem && m_ctxt );
+    }
+    body
+    {
+        // NOTE: Since this routine is only ever expected to be called from
+        //       the dtor, pointers to freed data are not set to null.
+
+        // NOTE: m_ctxt is guaranteed to be alive because it is held in the
+        //       global context list.
+        Thread.remove( m_ctxt );
+
+        static if( is( typeof( VirtualAlloc ) ) )
+        {
+            VirtualFree( m_pmem, 0, MEM_RELEASE );
+        }
+        else static if( is( typeof( mmap ) ) )
+        {
+            munmap( m_pmem, m_size );
+        }
+        else static if( is( typeof( valloc ) ) )
+        {
+            free( m_pmem );
+        }
+        else static if( is( typeof( malloc ) ) )
+        {
+            free( m_pmem );
+        }
+        delete m_ctxt;
+    }
+
+
+    //
+    // Initialize the allocated stack.
+    //
+    final void initStack()
+    in
+    {
+        assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
+        assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
+    }
+    body
+    {
+        void* pstack = m_ctxt.tstack;
+        scope( exit )  m_ctxt.tstack = pstack;
+
+        void push( size_t val )
+        {
+            version( StackGrowsDown )
+            {
+                pstack -= size_t.sizeof;
+                *(cast(size_t*) pstack) = val;
+            }
+            else
+            {
+                pstack += size_t.sizeof;
+                *(cast(size_t*) pstack) = val;
+            }
+        }
+
+        // NOTE: On OS X the stack must be 16-byte aligned according to the
+        // IA-32 call spec.
+        version( darwin )
+        {
+             pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F));
+        }
+
+        version( AsmX86_Win32 )
+        {
+            push( cast(size_t) &fiber_entryPoint );                 // EIP
+            push( 0xFFFFFFFF );                                     // EBP
+            push( 0x00000000 );                                     // EAX
+            push( 0xFFFFFFFF );                                     // FS:[0]
+            version( StackGrowsDown )
+            {
+                push( cast(size_t) m_ctxt.bstack );                 // FS:[4]
+                push( cast(size_t) m_ctxt.bstack - m_size );        // FS:[8]
+            }
+            else
+            {
+                push( cast(size_t) m_ctxt.bstack );                 // FS:[4]
+                push( cast(size_t) m_ctxt.bstack + m_size );        // FS:[8]
+            }
+            push( 0x00000000 );                                     // EBX
+            push( 0x00000000 );                                     // ESI
+            push( 0x00000000 );                                     // EDI
+        }
+        else version( AsmX86_Posix )
+        {
+            push( cast(size_t) &fiber_entryPoint );                 // EIP
+            push( 0x00000000 );                                     // EBP
+            push( 0x00000000 );                                     // EAX
+            push( 0x00000000 );                                     // EBX
+            push( 0x00000000 );                                     // ESI
+            push( 0x00000000 );                                     // EDI
+        }
+        else version( LLVM_AsmX86_Posix )
+        {
+            push( cast(size_t) &fiber_entryPoint );                 // EIP
+            push( 0x00000000 );                                     // newp
+            push( 0x00000000 );                                     // oldp
+            push( 0x00000000 );                                     // EBP
+            push( 0x00000000 );                                     // EBX
+            push( 0x00000000 );                                     // ESI
+            push( 0x00000000 );                                     // EDI
+        }
+//TODO: Implement x86-64 fibers
+/+
+        else version( LLVM_AsmX86_Posix )
+        {
+        }
++/
+        else version( AsmPPC_Posix )
+        {
+            version( StackGrowsDown )
+            {
+                pstack -= int.sizeof * 5;
+            }
+            else
+            {
+                pstack += int.sizeof * 5;
+            }
+
+            push( cast(size_t) &fiber_entryPoint );     // link register
+            push( 0x00000000 );                         // control register
+            push( 0x00000000 );                         // old stack pointer
+
+            // GPR values
+            version( StackGrowsDown )
+            {
+                pstack -= int.sizeof * 20;
+            }
+            else
+            {
+                pstack += int.sizeof * 20;
+            }
+
+            assert( cast(uint) pstack & 0x0f == 0 );
+        }
+        else static if( is( ucontext_t ) )
+        {
+            getcontext( &m_utxt );
+            m_utxt.uc_stack.ss_sp   = m_ctxt.bstack;
+            m_utxt.uc_stack.ss_size = m_size;
+            makecontext( &m_utxt, &fiber_entryPoint, 0 );
+            // NOTE: If ucontext is being used then the top of the stack will
+            //       be a pointer to the ucontext_t struct for that fiber.
+            push( cast(size_t) &m_utxt );
+        }
+    }
+
+
+    Thread.Context* m_ctxt;
+    size_t          m_size;
+    void*           m_pmem;
+
+    static if( is( ucontext_t ) )
+    {
+        // NOTE: The static ucontext instance is used to represent the context
+        //       of the main application thread.
+        static ucontext_t   sm_utxt = void;
+        ucontext_t          m_utxt  = void;
+        ucontext_t*         m_ucur  = null;
+    }
+
+
+private:
+    ///////////////////////////////////////////////////////////////////////////
+    // Storage of Active Fiber
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    //
+    // Sets a thread-local reference to the current fiber object.
+    //
+    static void setThis( Fiber f )
+    {
+        version( Win32 )
+        {
+            TlsSetValue( sm_this, cast(void*) f );
+        }
+        else version( Posix )
+        {
+            pthread_setspecific( sm_this, cast(void*) f );
+        }
+    }
+
+
+    static Thread.TLSKey    sm_this;
+
+
+private:
+    ///////////////////////////////////////////////////////////////////////////
+    // Context Switching
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    //
+    // Switches into the stack held by this fiber.
+    //
+    final void switchIn()
+    {
+        Thread  tobj = Thread.getThis();
+        void**  oldp = &tobj.m_curr.tstack;
+        void*   newp = m_ctxt.tstack;
+
+        // NOTE: The order of operations here is very important.  The current
+        //       stack top must be stored before m_lock is set, and pushContext
+        //       must not be called until after m_lock is set.  This process
+        //       is intended to prevent a race condition with the suspend
+        //       mechanism used for garbage collection.  If it is not followed,
+        //       a badly timed collection could cause the GC to scan from the
+        //       bottom of one stack to the top of another, or to miss scanning
+        //       a stack that still contains valid data.  The old stack pointer
+        //       oldp will be set again before the context switch to guarantee
+        //       that it points to exactly the correct stack location so the
+        //       successive pop operations will succeed.
+        *oldp = getStackTop();
+        volatile tobj.m_lock = true;
+        tobj.pushContext( m_ctxt );
+
+        fiber_switchContext( oldp, newp );
+
+        // NOTE: As above, these operations must be performed in a strict order
+        //       to prevent Bad Things from happening.
+        tobj.popContext();
+        volatile tobj.m_lock = false;
+        tobj.m_curr.tstack = tobj.m_curr.bstack;
+    }
+
+
+    //
+    // Switches out of the current stack and into the enclosing stack.
+    //
+    final void switchOut()
+    {
+        Thread  tobj = Thread.getThis();
+        void**  oldp = &m_ctxt.tstack;
+        void*   newp = tobj.m_curr.within.tstack;
+
+        // NOTE: The order of operations here is very important.  The current
+        //       stack top must be stored before m_lock is set, and pushContext
+        //       must not be called until after m_lock is set.  This process
+        //       is intended to prevent a race condition with the suspend
+        //       mechanism used for garbage collection.  If it is not followed,
+        //       a badly timed collection could cause the GC to scan from the
+        //       bottom of one stack to the top of another, or to miss scanning
+        //       a stack that still contains valid data.  The old stack pointer
+        //       oldp will be set again before the context switch to guarantee
+        //       that it points to exactly the correct stack location so the
+        //       successive pop operations will succeed.
+        *oldp = getStackTop();
+        volatile tobj.m_lock = true;
+
+        fiber_switchContext( oldp, newp );
+
+        // NOTE: As above, these operations must be performed in a strict order
+        //       to prevent Bad Things from happening.
+        volatile tobj.m_lock = false;
+        tobj.m_curr.tstack = tobj.m_curr.bstack;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/ldc.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,139 @@
+# Makefile to build the D runtime library core components for Posix
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the common library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=libdruntime-core.a
+LIB_MASK=libdruntime-core*.a
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-O $(ADD_CFLAGS)
+#CFLAGS=-g $(ADD_CFLAGS)
+
+DFLAGS=-release -O -inline -w $(ADD_DFLAGS)
+#DFLAGS=-g -w $(ADD_DFLAGS)
+
+TFLAGS=-O -inline -w $(ADD_DFLAGS)
+#TFLAGS=-g -w $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=gcc
+LC=$(AR) -qsv
+DC=ldc2
+
+INC_DEST=../../import
+LIB_DEST=../../lib
+DOC_DEST=../../doc
+
+.SUFFIXES: .s .S .c .cpp .d .html .o
+
+.s.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.S.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.o:
+	g++ -c $(CFLAGS) $< -o$@
+
+.d.o:
+	$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
+#	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+
+targets : lib doc
+all     : lib doc
+core    : lib
+lib     : core.lib
+doc     : core.doc
+
+######################################################
+
+OBJ_CORE= \
+    core/bitmanip.o \
+    core/exception.o \
+    core/memory_.o \
+    core/runtime.o \
+    core/thread.o
+
+OBJ_STDC= \
+    stdc/errno.o
+
+ALL_OBJS= \
+    $(OBJ_CORE) \
+    $(OBJ_STDC)
+
+######################################################
+
+DOC_CORE= \
+    core/bitmanip.html \
+    core/exception.html \
+    core/memory.html \
+    core/runtime.html \
+    core/thread.html
+
+
+ALL_DOCS=
+
+######################################################
+
+core.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) $@ $(ALL_OBJS)
+
+core.doc : $(ALL_DOCS)
+	echo Documentation generated.
+
+######################################################
+
+### bitmanip
+
+core/bitmanip.o : core/bitmanip.d
+	$(DC) -c $(DFLAGS) core/bitmanip.d -of$@
+
+### memory
+
+core/memory_.o : core/memory.d
+	$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
+
+### thread
+
+core/thread.o : core/thread.d
+	$(DC) -c $(DFLAGS) -d -Hf$*.di core/thread.d -of$@
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	find . -name "$(LIB_MASK)" | xargs $(RM)
+
+install :
+	$(MD) $(INC_DEST)
+	find . -name "*.di" -exec cp -f {} $(INC_DEST)/{} \;
+	$(MD) $(DOC_DEST)
+	find . -name "*.html" -exec cp -f {} $(DOC_DEST)/{} \;
+	$(MD) $(LIB_DEST)
+	find . -name "$(LIB_MASK)" -exec cp -f {} $(LIB_DEST)/{} \;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/posix.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,139 @@
+# Makefile to build the D runtime library core components for Posix
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the common library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=libdruntime-core.a
+LIB_MASK=libdruntime-core*.a
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-O $(ADD_CFLAGS)
+#CFLAGS=-g $(ADD_CFLAGS)
+
+DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
+#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
+#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=gcc
+LC=$(AR) -qsv
+DC=dmd
+
+INC_DEST=../../import
+LIB_DEST=../../lib
+DOC_DEST=../../doc
+
+.SUFFIXES: .s .S .c .cpp .d .html .o
+
+.s.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.S.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.o:
+	g++ -c $(CFLAGS) $< -o$@
+
+.d.o:
+	$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
+#	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+
+targets : lib doc
+all     : lib doc
+core    : lib
+lib     : core.lib
+doc     : core.doc
+
+######################################################
+
+OBJ_CORE= \
+    core/bitmanip.o \
+    core/exception.o \
+    core/memory_.o \
+    core/runtime.o \
+    core/thread.o
+
+OBJ_STDC= \
+    stdc/errno.o
+
+ALL_OBJS= \
+    $(OBJ_CORE) \
+    $(OBJ_STDC)
+
+######################################################
+
+DOC_CORE= \
+    core/bitmanip.html \
+    core/exception.html \
+    core/memory.html \
+    core/runtime.html \
+    core/thread.html
+
+
+ALL_DOCS=
+
+######################################################
+
+core.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) $@ $(ALL_OBJS)
+
+core.doc : $(ALL_DOCS)
+	echo Documentation generated.
+
+######################################################
+
+### bitmanip
+
+core/bitmanip.o : core/bitmanip.d
+	$(DC) -c $(DFLAGS) core/bitmanip.d -of$@
+
+### memory
+
+core/memory_.o : core/memory.d
+	$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
+
+### thread
+
+core/thread.o : core/thread.d
+	$(DC) -c $(DFLAGS) -d -Hf$*.di core/thread.d -of$@
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	find . -name "$(LIB_MASK)" | xargs $(RM)
+
+install :
+	$(MD) $(INC_DEST)
+	find . -name "*.di" -exec cp -f {} $(INC_DEST)/{} \;
+	$(MD) $(DOC_DEST)
+	find . -name "*.html" -exec cp -f {} $(DOC_DEST)/{} \;
+	$(MD) $(LIB_DEST)
+	find . -name "$(LIB_MASK)" -exec cp -f {} $(LIB_DEST)/{} \;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/stdc/errno.c	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,21 @@
+/**
+ * This file contains wrapper functions for macro-defined C rouines.
+ *
+ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
+ * License:   BSD Style, see LICENSE
+ * Authors:   Sean Kelly
+ */
+#include <errno.h>
+
+
+int getErrno()
+{
+    return errno;
+}
+
+
+int setErrno( int val )
+{
+    errno = val;
+    return val;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/win32.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,130 @@
+# Makefile to build the D runtime library core components for Win32
+# Designed to work with DigitalMars make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the common library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=druntime-core.lib
+LIB_MASK=druntime-core*.lib
+
+CP=xcopy /y
+RM=del /f
+MD=mkdir
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-mn -6 -r $(ADD_CFLAGS)
+#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS)
+
+DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
+#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+TFLAGS=-O -inline -w  -nofloat $(ADD_DFLAGS)
+#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=dmc
+LC=lib
+DC=dmd
+
+INC_DEST=..\..\import
+LIB_DEST=..\..\lib
+DOC_DEST=..\..\doc
+
+.DEFAULT: .asm .c .cpp .d .html .obj
+
+.asm.obj:
+	$(CC) -c $<
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.obj:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.d.obj:
+	$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
+#	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+
+targets : lib doc
+all     : lib doc
+core    : lib
+lib     : core.lib
+doc     : core.doc
+
+######################################################
+
+OBJ_CORE= \
+    core\bitmanip.obj \
+    core\exception.obj \
+    core\memory.obj \
+    core\runtime.obj \
+    core\thread.obj
+
+OBJ_STDC= \
+    stdc\errno.obj
+
+ALL_OBJS= \
+    $(OBJ_CORE) \
+    $(OBJ_STDC)
+
+######################################################
+
+DOC_CORE= \
+    core\bitmanip.html \
+    core\exception.html \
+    core\memory.html \
+    core\runtime.html \
+    core\thread.html
+
+ALL_DOCS=
+
+######################################################
+
+core.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) -c -n $@ $(ALL_OBJS)
+
+core.doc : $(ALL_DOCS)
+	@echo Documentation generated.
+
+######################################################
+
+### bitmanip
+
+core\bitmanip.obj : core\bitmanip.d
+	$(DC) -c $(DFLAGS) core\bitmanip.d -of$@
+
+### thread
+
+core\thread.obj : core\thread.d
+	$(DC) -c $(DFLAGS) -d -Hf$*.di core\thread.d -of$@
+
+######################################################
+
+clean :
+	$(RM) /s .\*.di
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(INC_DEST)\.
+	$(CP) /s *.di $(INC_DEST)\.
+	$(MD) $(DOC_DEST)
+	$(CP) /s *.html $(DOC_DEST)\.
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)\.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/aApply.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,408 @@
+/**
+ * Part of the D programming language runtime library.
+ */
+
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.aApply;
+
+/* This code handles decoding UTF strings for foreach loops.
+ * There are 6 combinations of conversions between char, wchar,
+ * and dchar, and 2 of each of those.
+ */
+
+private import util.utf;
+
+/**********************************************
+ */
+
+// dg is D, but _aApplycd() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+extern (C) int _aApplycd1(char[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycd1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+
+        d = aa[i];
+        if (d & 0x80)
+            d = decode(aa, i);
+        else
+            i++;
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywd1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+
+        d = aa[i];
+        if (d & ~0x7F)
+            d = decode(aa, i);
+        else
+            i++;
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplycw1(char[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycw1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+        wchar w;
+
+        w = aa[i];
+        if (w & 0x80)
+        {   d = decode(aa, i);
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        else
+            i++;
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywc1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+        wchar w;
+        char c;
+
+        w = aa[i];
+        if (w & ~0x7F)
+        {
+            char[4] buf;
+
+            d = decode(aa, i);
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)w;
+            i++;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
+    foreach (dchar d; aa)
+    {
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {
+            c = cast(char)d;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
+    foreach (dchar d; aa)
+    {
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+
+/****************************************************************************/
+
+// dg is D, but _aApplycd2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+extern (C) int _aApplycd2(char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycd2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+
+        d = aa[i];
+        if (d & 0x80)
+        {
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywd2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+
+        d = aa[i];
+        if (d & ~0x7F)
+        {
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplycw2(char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycw2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+        wchar w;
+
+        w = aa[i];
+        if (w & 0x80)
+        {   n = i;
+            d = decode(aa, n);
+            n -= i;
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(&i, cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywc2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+        wchar w;
+        char c;
+
+        w = aa[i];
+        if (w & ~0x7F)
+        {
+            char[4] buf;
+
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)w;
+            n = 1;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplydc2(), len = %d\n", len);
+    for (i = 0; i < len; i++)
+    {   dchar d;
+        char c;
+
+        d = aa[i];
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)d;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
+    foreach (size_t i, dchar d; aa)
+    {
+        wchar w;
+        auto j = i;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(&j, cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(&j, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/aApplyR.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,974 @@
+/**
+ * Part of the D programming language runtime library.
+ */
+
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.aApplyR;
+
+/* This code handles decoding UTF strings for foreach_reverse loops.
+ * There are 6 combinations of conversions between char, wchar,
+ * and dchar, and 2 of each of those.
+ */
+
+private import util.utf;
+
+/**********************************************/
+/* 1 argument versions */
+
+// dg is D, but _aApplyRcd() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d & 0x80)
+        {   char c = cast(char)d;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+        }
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcd1.unittest\n");
+
+    auto s = "hello"c;
+    int i;
+
+    foreach_reverse(dchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(dchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == '\U00100456'); break;
+            case 2:     assert(d == '\u1234'); break;
+            case 3:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwd1.unittest\n");
+
+    auto s = "hello"w;
+    int i;
+
+    foreach_reverse(dchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(dchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == '\U00100456'); break;
+            case 2:     assert(d == '\u1234'); break;
+            case 3:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        wchar w;
+
+        i--;
+        w = aa[i];
+        if (w & 0x80)
+        {   char c = cast(char)w;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcw1.unittest\n");
+
+    auto s = "hello"c;
+    int i;
+
+    foreach_reverse(wchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(wchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xDBC1); break;
+            case 2:     assert(d == 0xDC56); break;
+            case 3:     assert(d == 0x1234); break;
+            case 4:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        char c;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        c = cast(char)d;
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwc1.unittest\n");
+
+    auto s = "hello"w;
+    int i;
+
+    foreach_reverse(char d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(char d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xF4); break;
+            case 2:     assert(d == 0x80); break;
+            case 3:     assert(d == 0x91); break;
+            case 4:     assert(d == 0x96); break;
+            case 5:     assert(d == 0xE1); break;
+            case 6:     assert(d == 0x88); break;
+            case 7:     assert(d == 0xB4); break;
+            case 8:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0;)
+    {   dchar d = aa[--i];
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {
+            c = cast(char)d;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdc1.unittest\n");
+
+    auto s = "hello"d;
+    int i;
+
+    foreach_reverse(char d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(char d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xF4); break;
+            case 2:     assert(d == 0x80); break;
+            case 3:     assert(d == 0x91); break;
+            case 4:     assert(d == 0x96); break;
+            case 5:     assert(d == 0xE1); break;
+            case 6:     assert(d == 0x88); break;
+            case 7:     assert(d == 0xB4); break;
+            case 8:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdw1.unittest\n");
+
+    auto s = "hello"d;
+    int i;
+
+    foreach_reverse(wchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(wchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xDBC1); break;
+            case 2:     assert(d == 0xDC56); break;
+            case 3:     assert(d == 0x1234); break;
+            case 4:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+
+/****************************************************************************/
+/* 2 argument versions */
+
+// dg is D, but _aApplyRcd2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
+    for (i = len; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d & 0x80)
+        {   char c = cast(char)d;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+        }
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcd2.unittest\n");
+
+    auto s = "hello"c;
+    int i;
+
+    foreach_reverse(k, dchar d; s)
+    {
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); assert(k == 8); break;
+            case 1:     assert(d == '\U00100456'); assert(k == 4); break;
+            case 2:     assert(d == '\u1234'); assert(k == 1); break;
+            case 3:     assert(d == 'a'); assert(k == 0); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwd2.unittest\n");
+
+    auto s = "hello"w;
+    int i;
+
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 4); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == '\U00100456'); break;
+            case 2:     assert(k == 1); assert(d == '\u1234'); break;
+            case 3:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        wchar w;
+
+        i--;
+        w = aa[i];
+        if (w & 0x80)
+        {   char c = cast(char)w;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(&i, cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcw2.unittest\n");
+
+    auto s = "hello"c;
+    int i;
+
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 8); assert(d == 'b'); break;
+            case 1:     assert(k == 4); assert(d == 0xDBC1); break;
+            case 2:     assert(k == 4); assert(d == 0xDC56); break;
+            case 3:     assert(k == 1); assert(d == 0x1234); break;
+            case 4:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        char c;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        c = cast(char)d;
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwc2.unittest\n");
+
+    auto s = "hello"w;
+    int i;
+
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 4); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xF4); break;
+            case 2:     assert(k == 2); assert(d == 0x80); break;
+            case 3:     assert(k == 2); assert(d == 0x91); break;
+            case 4:     assert(k == 2); assert(d == 0x96); break;
+            case 5:     assert(k == 1); assert(d == 0xE1); break;
+            case 6:     assert(k == 1); assert(d == 0x88); break;
+            case 7:     assert(k == 1); assert(d == 0xB4); break;
+            case 8:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)d;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdc2.unittest\n");
+
+    auto s = "hello"d;
+    int i;
+
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 3); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xF4); break;
+            case 2:     assert(k == 2); assert(d == 0x80); break;
+            case 3:     assert(k == 2); assert(d == 0x91); break;
+            case 4:     assert(k == 2); assert(d == 0x96); break;
+            case 5:     assert(k == 1); assert(d == 0xE1); break;
+            case 6:     assert(k == 1); assert(d == 0x88); break;
+            case 7:     assert(k == 1); assert(d == 0xB4); break;
+            case 8:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(&i, cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdw2.unittest\n");
+
+    auto s = "hello"d;
+    int i;
+
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 3); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xDBC1); break;
+            case 2:     assert(k == 2); assert(d == 0xDC56); break;
+            case 3:     assert(k == 1); assert(d == 0x1234); break;
+            case 4:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/aaA.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,886 @@
+//_ aaA.d
+
+/**
+ * Part of the D programming language runtime library.
+ * Implementation of associative arrays.
+ */
+
+/*
+ *  Copyright (C) 2000-2008 by Digital Mars, http://www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.aaA;
+
+private
+{
+    import stdc.stdarg;
+    import stdc.string;
+
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) void  gc_free( void* p );
+}
+
+// Auto-rehash and pre-allocate - Dave Fladebo
+
+static size_t[] prime_list = [
+              97UL,            389UL,
+           1_543UL,          6_151UL,
+          24_593UL,         98_317UL,
+          393_241UL,      1_572_869UL,
+        6_291_469UL,     25_165_843UL,
+      100_663_319UL,    402_653_189UL,
+    1_610_612_741UL,  4_294_967_291UL,
+//  8_589_934_513UL, 17_179_869_143UL
+];
+
+/* This is the type of the return value for dynamic arrays.
+ * It should be a type that is returned in registers.
+ * Although DMD will return types of Array in registers,
+ * gcc will not, so we instead use a 'long'.
+ */
+alias long ArrayRet_t;
+
+struct Array
+{
+    size_t length;
+    void* ptr;
+}
+
+struct aaA
+{
+    aaA *left;
+    aaA *right;
+    hash_t hash;
+    /* key   */
+    /* value */
+}
+
+struct BB
+{
+    aaA*[] b;
+    size_t nodes;       // total number of aaA nodes
+    TypeInfo keyti;     // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
+}
+
+/* This is the type actually seen by the programmer, although
+ * it is completely opaque.
+ */
+
+struct AA
+{
+    BB* a;
+}
+
+/**********************************
+ * Align to next pointer boundary, so that
+ * GC won't be faced with misaligned pointers
+ * in value.
+ */
+
+size_t aligntsize(size_t tsize)
+{
+    // Is pointer alignment on the x64 4 bytes or 8?
+    return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
+}
+
+extern (C):
+
+/*************************************************
+ * Invariant for aa.
+ */
+
+/+
+void _aaInvAh(aaA*[] aa)
+{
+    for (size_t i = 0; i < aa.length; i++)
+    {
+        if (aa[i])
+            _aaInvAh_x(aa[i]);
+    }
+}
+
+private int _aaCmpAh_x(aaA *e1, aaA *e2)
+{   int c;
+
+    c = e1.hash - e2.hash;
+    if (c == 0)
+    {
+        c = e1.key.length - e2.key.length;
+        if (c == 0)
+            c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
+    }
+    return c;
+}
+
+private void _aaInvAh_x(aaA *e)
+{
+    hash_t key_hash;
+    aaA *e1;
+    aaA *e2;
+
+    key_hash = getHash(e.key);
+    assert(key_hash == e.hash);
+
+    while (1)
+    {   int c;
+
+        e1 = e.left;
+        if (e1)
+        {
+            _aaInvAh_x(e1);             // ordinary recursion
+            do
+            {
+                c = _aaCmpAh_x(e1, e);
+                assert(c < 0);
+                e1 = e1.right;
+            } while (e1 != null);
+        }
+
+        e2 = e.right;
+        if (e2)
+        {
+            do
+            {
+                c = _aaCmpAh_x(e, e2);
+                assert(c < 0);
+                e2 = e2.left;
+            } while (e2 != null);
+            e = e.right;                // tail recursion
+        }
+        else
+            break;
+    }
+}
++/
+
+/****************************************************
+ * Determine number of entries in associative array.
+ */
+
+size_t _aaLen(AA aa)
+in
+{
+    //printf("_aaLen()+\n");
+    //_aaInv(aa);
+}
+out (result)
+{
+    size_t len = 0;
+
+    void _aaLen_x(aaA* ex)
+    {
+        auto e = ex;
+        len++;
+
+        while (1)
+        {
+            if (e.right)
+               _aaLen_x(e.right);
+            e = e.left;
+            if (!e)
+                break;
+            len++;
+        }
+    }
+
+    if (aa.a)
+    {
+        foreach (e; aa.a.b)
+        {
+            if (e)
+                _aaLen_x(e);
+        }
+    }
+    assert(len == result);
+
+    //printf("_aaLen()-\n");
+}
+body
+{
+    return aa.a ? aa.a.nodes : 0;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Add entry for key if it is not already there.
+ */
+
+void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
+in
+{
+    assert(aa);
+}
+out (result)
+{
+    assert(result);
+    assert(aa.a);
+    assert(aa.a.b.length);
+    //assert(_aaInAh(*aa.a, key));
+}
+body
+{
+    auto pkey = cast(void *)(&valuesize + 1);
+    size_t i;
+    aaA *e;
+    auto keysize = aligntsize(keyti.tsize());
+
+    if (!aa.a)
+        aa.a = new BB();
+    aa.a.keyti = keyti;
+
+    if (!aa.a.b.length)
+    {
+        alias aaA *pa;
+        auto len = prime_list[0];
+
+        aa.a.b = new pa[len];
+    }
+
+    auto key_hash = keyti.getHash(pkey);
+    //printf("hash = %d\n", key_hash);
+    i = key_hash % aa.a.b.length;
+    auto pe = &aa.a.b[i];
+    while ((e = *pe) !is null)
+    {
+        if (key_hash == e.hash)
+        {
+            auto c = keyti.compare(pkey, e + 1);
+            if (c == 0)
+                goto Lret;
+            pe = (c < 0) ? &e.left : &e.right;
+        }
+        else
+            pe = (key_hash < e.hash) ? &e.left : &e.right;
+    }
+
+    // Not found, create new elem
+    //printf("create new one\n");
+    size_t size = aaA.sizeof + keysize + valuesize;
+    e = cast(aaA *) gc_calloc(size);
+    memcpy(e + 1, pkey, keysize);
+    e.hash = key_hash;
+    *pe = e;
+
+    auto nodes = ++aa.a.nodes;
+    //printf("length = %d, nodes = %d\n", (*aa.a).length, nodes);
+    if (nodes > aa.a.b.length * 4)
+    {
+        _aaRehash(aa,keyti);
+    }
+
+Lret:
+    return cast(void *)(e + 1) + keysize;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Returns null if it is not already there.
+ */
+
+void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
+{
+    //printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
+    if (!aa.a)
+        return null;
+
+    auto pkey = cast(void *)(&valuesize + 1);
+    auto keysize = aligntsize(keyti.tsize());
+    auto len = aa.a.b.length;
+
+    if (len)
+    {
+        auto key_hash = keyti.getHash(pkey);
+        //printf("hash = %d\n", key_hash);
+        size_t i = key_hash % len;
+        auto e = aa.a.b[i];
+        while (e !is null)
+        {
+            if (key_hash == e.hash)
+            {
+                auto c = keyti.compare(pkey, e + 1);
+            if (c == 0)
+                return cast(void *)(e + 1) + keysize;
+                e = (c < 0) ? e.left : e.right;
+            }
+            else
+                e = (key_hash < e.hash) ? e.left : e.right;
+        }
+    }
+    return null;    // not found, caller will throw exception
+}
+
+
+/*************************************************
+ * Determine if key is in aa.
+ * Returns:
+ *      null    not in aa
+ *      !=null  in aa, return pointer to value
+ */
+
+void* _aaIn(AA aa, TypeInfo keyti, ...)
+in
+{
+}
+out (result)
+{
+    //assert(result == 0 || result == 1);
+}
+body
+{
+    if (aa.a)
+    {
+        auto pkey = cast(void *)(&keyti + 1);
+
+        //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
+        auto len = aa.a.b.length;
+
+        if (len)
+        {
+            auto key_hash = keyti.getHash(pkey);
+            //printf("hash = %d\n", key_hash);
+            size_t i = key_hash % len;
+            auto e = aa.a.b[i];
+            while (e !is null)
+            {
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(pkey, e + 1);
+                    if (c == 0)
+                        return cast(void *)(e + 1) + aligntsize(keyti.tsize());
+                    e = (c < 0) ? e.left : e.right;
+                }
+                else
+                    e = (key_hash < e.hash) ? e.left : e.right;
+            }
+        }
+    }
+
+    // Not found
+    return null;
+}
+
+/*************************************************
+ * Delete key entry in aa[].
+ * If key is not in aa[], do nothing.
+ */
+
+void _aaDel(AA aa, TypeInfo keyti, ...)
+{
+    auto pkey = cast(void *)(&keyti + 1);
+    aaA *e;
+
+    if (aa.a && aa.a.b.length)
+    {
+        auto key_hash = keyti.getHash(pkey);
+        //printf("hash = %d\n", key_hash);
+        size_t i = key_hash % aa.a.b.length;
+        auto pe = &aa.a.b[i];
+        while ((e = *pe) !is null) // null means not found
+        {
+            if (key_hash == e.hash)
+            {
+                auto c = keyti.compare(pkey, e + 1);
+                if (c == 0)
+                {
+                    if (!e.left && !e.right)
+                    {
+                        *pe = null;
+                    }
+                    else if (e.left && !e.right)
+                    {
+                        *pe = e.left;
+                         e.left = null;
+                    }
+                    else if (!e.left && e.right)
+                    {
+                        *pe = e.right;
+                         e.right = null;
+                    }
+                    else
+                    {
+                        *pe = e.left;
+                        e.left = null;
+                        do
+                            pe = &(*pe).right;
+                        while (*pe);
+                        *pe = e.right;
+                        e.right = null;
+                    }
+
+                    aa.a.nodes--;
+                    gc_free(e);
+                    break;
+                }
+                pe = (c < 0) ? &e.left : &e.right;
+            }
+            else
+                pe = (key_hash < e.hash) ? &e.left : &e.right;
+        }
+    }
+}
+
+
+/********************************************
+ * Produce array of values from aa.
+ */
+
+ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
+in
+{
+    assert(keysize == aligntsize(keysize));
+}
+body
+{
+    size_t resi;
+    Array a;
+
+    void _aaValues_x(aaA* e)
+    {
+        do
+        {
+            memcpy(a.ptr + resi * valuesize,
+                   cast(byte*)e + aaA.sizeof + keysize,
+                   valuesize);
+            resi++;
+            if (e.left)
+            {   if (!e.right)
+                {   e = e.left;
+                    continue;
+                }
+                _aaValues_x(e.left);
+            }
+            e = e.right;
+        } while (e !is null);
+    }
+
+    if (aa.a)
+    {
+        a.length = _aaLen(aa);
+        a.ptr = cast(byte*) gc_malloc(a.length * valuesize,
+                                      valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
+        resi = 0;
+        foreach (e; aa.a.b)
+        {
+            if (e)
+                _aaValues_x(e);
+        }
+        assert(resi == a.length);
+    }
+    return *cast(ArrayRet_t*)(&a);
+}
+
+
+/********************************************
+ * Rehash an array.
+ */
+
+void* _aaRehash(AA* paa, TypeInfo keyti)
+in
+{
+    //_aaInvAh(paa);
+}
+out (result)
+{
+    //_aaInvAh(result);
+}
+body
+{
+    BB newb;
+
+    void _aaRehash_x(aaA* olde)
+    {
+        while (1)
+        {
+            auto left = olde.left;
+            auto right = olde.right;
+            olde.left = null;
+            olde.right = null;
+
+            aaA *e;
+
+            //printf("rehash %p\n", olde);
+            auto key_hash = olde.hash;
+            size_t i = key_hash % newb.b.length;
+            auto pe = &newb.b[i];
+            while ((e = *pe) !is null)
+            {
+                //printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
+                assert(e.left != e);
+                assert(e.right != e);
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(olde + 1, e + 1);
+                    assert(c != 0);
+                    pe = (c < 0) ? &e.left : &e.right;
+                }
+                else
+                    pe = (key_hash < e.hash) ? &e.left : &e.right;
+            }
+            *pe = olde;
+
+            if (right)
+            {
+                if (!left)
+                {   olde = right;
+                    continue;
+                }
+                _aaRehash_x(right);
+            }
+            if (!left)
+                break;
+            olde = left;
+        }
+    }
+
+    //printf("Rehash\n");
+    if (paa.a)
+    {
+        auto aa = paa.a;
+        auto len = _aaLen(*paa);
+        if (len)
+        {   size_t i;
+
+            for (i = 0; i < prime_list.length - 1; i++)
+            {
+                if (len <= prime_list[i])
+                    break;
+            }
+            len = prime_list[i];
+            newb.b = new aaA*[len];
+
+            foreach (e; aa.b)
+            {
+                if (e)
+                    _aaRehash_x(e);
+            }
+
+            newb.nodes = aa.nodes;
+            newb.keyti = aa.keyti;
+        }
+
+        *paa.a = newb;
+        _aaBalance(paa);
+    }
+    return (*paa).a;
+}
+
+/********************************************
+ * Balance an array.
+ */
+
+void _aaBalance(AA* paa)
+{
+    //printf("_aaBalance()\n");
+    if (paa.a)
+    {
+        aaA*[16] tmp;
+        aaA*[] array = tmp;
+        auto aa = paa.a;
+        foreach (j, e; aa.b)
+        {
+            /* Temporarily store contents of bucket in array[]
+             */
+            size_t k = 0;
+            void addToArray(aaA* e)
+            {
+                while (e)
+                {   addToArray(e.left);
+                    if (k == array.length)
+                        array.length = array.length * 2;
+                    array[k++] = e;
+                    e = e.right;
+                }
+            }
+            addToArray(e);
+            /* The contents of the bucket are now sorted into array[].
+             * Rebuild the tree.
+             */
+            void buildTree(aaA** p, size_t x1, size_t x2)
+            {
+                if (x1 >= x2)
+                    *p = null;
+                else
+                {   auto mid = (x1 + x2) >> 1;
+                    *p = array[mid];
+                    buildTree(&(*p).left, x1, mid);
+                    buildTree(&(*p).right, mid + 1, x2);
+                }
+            }
+            auto p = &aa.b[j];
+            buildTree(p, 0, k);
+        }
+    }
+}
+/********************************************
+ * Produce array of N byte keys from aa.
+ */
+
+ArrayRet_t _aaKeys(AA aa, size_t keysize)
+{
+    byte[] res;
+    size_t resi;
+
+    void _aaKeys_x(aaA* e)
+    {
+        do
+        {
+            memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
+            resi++;
+            if (e.left)
+            {   if (!e.right)
+                {   e = e.left;
+                    continue;
+                }
+                _aaKeys_x(e.left);
+            }
+            e = e.right;
+        } while (e !is null);
+    }
+
+    auto len = _aaLen(aa);
+    if (!len)
+        return 0;
+    res = (cast(byte*) gc_malloc(len * keysize,
+                                 !(aa.a.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0))[0 .. len * keysize];
+    resi = 0;
+    foreach (e; aa.a.b)
+    {
+        if (e)
+            _aaKeys_x(e);
+    }
+    assert(resi == len);
+
+    Array a;
+    a.length = len;
+    a.ptr = res.ptr;
+    return *cast(ArrayRet_t*)(&a);
+}
+
+
+/**********************************************
+ * 'apply' for associative arrays - to support foreach
+ */
+
+// dg is D, but _aaApply() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+int _aaApply(AA aa, size_t keysize, dg_t dg)
+in
+{
+    assert(aligntsize(keysize) == keysize);
+}
+body
+{   int result;
+
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
+
+    int treewalker(aaA* e)
+    {   int result;
+
+        do
+        {
+            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
+            result = dg(cast(void *)(e + 1) + keysize);
+            if (result)
+                break;
+            if (e.right)
+            {   if (!e.left)
+                {
+                    e = e.right;
+                    continue;
+                }
+                result = treewalker(e.right);
+                if (result)
+                    break;
+            }
+            e = e.left;
+        } while (e);
+
+        return result;
+    }
+
+    if (aa.a)
+    {
+        foreach (e; aa.a.b)
+        {
+            if (e)
+            {
+                result = treewalker(e);
+                if (result)
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+// dg is D, but _aaApply2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+int _aaApply2(AA aa, size_t keysize, dg2_t dg)
+in
+{
+    assert(aligntsize(keysize) == keysize);
+}
+body
+{   int result;
+
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
+
+    int treewalker(aaA* e)
+    {   int result;
+
+        do
+        {
+            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
+            result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
+            if (result)
+                break;
+            if (e.right)
+            {   if (!e.left)
+                {
+                    e = e.right;
+                    continue;
+                }
+                result = treewalker(e.right);
+                if (result)
+                    break;
+            }
+            e = e.left;
+        } while (e);
+
+        return result;
+    }
+
+    if (aa.a)
+    {
+        foreach (e; aa.a.b)
+        {
+            if (e)
+            {
+                result = treewalker(e);
+                if (result)
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+
+/***********************************
+ * Construct an associative array of type ti from
+ * length pairs of key/value pairs.
+ */
+
+extern (C)
+BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
+{
+    auto valuesize = ti.next.tsize();           // value size
+    auto keyti = ti.key;
+    auto keysize = keyti.tsize();               // key size
+    BB* result;
+
+    //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
+    //printf("tivalue = %.*s\n", ti.next.classinfo.name);
+    if (length == 0 || valuesize == 0 || keysize == 0)
+    {
+        ;
+    }
+    else
+    {
+        va_list q;
+        va_start!(size_t)(q, length);
+
+        result = new BB();
+        result.keyti = keyti;
+        size_t i;
+
+        for (i = 0; i < prime_list.length - 1; i++)
+        {
+            if (length <= prime_list[i])
+                break;
+        }
+        auto len = prime_list[i];
+        result.b = new aaA*[len];
+
+        size_t keystacksize   = (keysize   + int.sizeof - 1) & ~(int.sizeof - 1);
+        size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
+
+        size_t keytsize = aligntsize(keysize);
+
+        for (size_t j = 0; j < length; j++)
+        {   void* pkey = q;
+            q += keystacksize;
+            void* pvalue = q;
+            q += valuestacksize;
+            aaA* e;
+
+            auto key_hash = keyti.getHash(pkey);
+            //printf("hash = %d\n", key_hash);
+            i = key_hash % len;
+            auto pe = &result.b[i];
+            while (1)
+            {
+                e = *pe;
+                if (!e)
+                {
+                    // Not found, create new elem
+                    //printf("create new one\n");
+                    e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
+                    memcpy(e + 1, pkey, keysize);
+                    e.hash = key_hash;
+                    *pe = e;
+                    result.nodes++;
+                    break;
+                }
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(pkey, e + 1);
+                    if (c == 0)
+                        break;
+                    pe = (c < 0) ? &e.left : &e.right;
+                }
+                else
+                    pe = (key_hash < e.hash) ? &e.left : &e.right;
+            }
+            memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
+        }
+
+        va_end(q);
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/adi.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,625 @@
+//_ adi.d
+
+/**
+ * Part of the D programming language runtime library.
+ * Dynamic array property support routines
+ */
+
+/*
+ *  Copyright (C) 2000-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.adi;
+
+//debug=adi;            // uncomment to turn on debugging printf's
+
+private
+{
+    debug(adi) import stdc.stdio;
+    import stdc.string;
+    import stdc.stdlib;
+    import util.utf;
+
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) void  gc_free( void* p );
+}
+
+
+struct Array
+{
+    size_t  length;
+    void*   ptr;
+}
+
+/**********************************************
+ * Reverse array of chars.
+ * Handled separately because embedded multibyte encodings should not be
+ * reversed.
+ */
+
+extern (C) long _adReverseChar(char[] a)
+{
+    if (a.length > 1)
+    {
+        char[6] tmp;
+        char[6] tmplo;
+        char* lo = a.ptr;
+        char* hi = &a[length - 1];
+
+        while (lo < hi)
+        {   auto clo = *lo;
+            auto chi = *hi;
+
+            debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
+            if (clo <= 0x7F && chi <= 0x7F)
+            {
+                debug(adi) printf("\tascii\n");
+                *lo = chi;
+                *hi = clo;
+                lo++;
+                hi--;
+                continue;
+            }
+
+            uint stridelo = UTF8stride[clo];
+
+            uint stridehi = 1;
+            while ((chi & 0xC0) == 0x80)
+            {
+                chi = *--hi;
+                stridehi++;
+                assert(hi >= lo);
+            }
+            if (lo == hi)
+                break;
+
+            debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
+            if (stridelo == stridehi)
+            {
+
+                memcpy(tmp.ptr, lo, stridelo);
+                memcpy(lo, hi, stridelo);
+                memcpy(hi, tmp.ptr, stridelo);
+                lo += stridelo;
+                hi--;
+                continue;
+            }
+
+            /* Shift the whole array. This is woefully inefficient
+             */
+            memcpy(tmp.ptr, hi, stridehi);
+            memcpy(tmplo.ptr, lo, stridelo);
+            memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo);
+            memcpy(lo, tmp.ptr, stridehi);
+            memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
+
+            lo += stridehi;
+            hi = hi - 1 + (stridehi - stridelo);
+        }
+    }
+    return *cast(long*)(&a);
+}
+
+unittest
+{
+    auto a = "abcd"c;
+
+    auto r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "dcba");
+
+    a = "a\u1235\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234\u1235a");
+
+    a = "ab\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234ba");
+
+    a = "\u3026\u2021\u3061\n";
+    r = a.dup.reverse;
+    assert(r == "\n\u3061\u2021\u3026");
+}
+
+
+/**********************************************
+ * Reverse array of wchars.
+ * Handled separately because embedded multiword encodings should not be
+ * reversed.
+ */
+
+extern (C) long _adReverseWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+        wchar[2] tmp;
+        wchar* lo = a.ptr;
+        wchar* hi = &a[length - 1];
+
+        while (lo < hi)
+        {   auto clo = *lo;
+            auto chi = *hi;
+
+            if ((clo < 0xD800 || clo > 0xDFFF) &&
+                (chi < 0xD800 || chi > 0xDFFF))
+            {
+                *lo = chi;
+                *hi = clo;
+                lo++;
+                hi--;
+                continue;
+            }
+
+            int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
+
+            int stridehi = 1;
+            if (chi >= 0xDC00 && chi <= 0xDFFF)
+            {
+                chi = *--hi;
+                stridehi++;
+                assert(hi >= lo);
+            }
+            if (lo == hi)
+                break;
+
+            if (stridelo == stridehi)
+            {   int stmp;
+
+                assert(stridelo == 2);
+                assert(stmp.sizeof == 2 * (*lo).sizeof);
+                stmp = *cast(int*)lo;
+                *cast(int*)lo = *cast(int*)hi;
+                *cast(int*)hi = stmp;
+                lo += stridelo;
+                hi--;
+                continue;
+            }
+
+            /* Shift the whole array. This is woefully inefficient
+             */
+            memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
+            memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
+            memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
+            memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
+
+            lo += stridehi;
+            hi = hi - 1 + (stridehi - stridelo);
+        }
+    }
+    return *cast(long*)(&a);
+}
+
+unittest
+{
+    wstring a = "abcd";
+
+    auto r = a.dup.reverse;
+    assert(r == "dcba");
+
+    a = "a\U00012356\U00012346c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012346\U00012356a");
+
+    a = "ab\U00012345c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012345ba");
+}
+
+
+/**********************************************
+ * Support for array.reverse property.
+ */
+
+extern (C) long _adReverse(Array a, size_t szelem)
+    out (result)
+    {
+        assert(result is *cast(long*)(&a));
+    }
+    body
+    {
+        if (a.length >= 2)
+        {
+            byte*    tmp;
+            byte[16] buffer;
+
+            void* lo = a.ptr;
+            void* hi = a.ptr + (a.length - 1) * szelem;
+
+            tmp = buffer.ptr;
+            if (szelem > 16)
+            {
+                //version (Windows)
+                    tmp = cast(byte*) alloca(szelem);
+                //else
+                    //tmp = gc_malloc(szelem);
+            }
+
+            for (; lo < hi; lo += szelem, hi -= szelem)
+            {
+                memcpy(tmp, lo,  szelem);
+                memcpy(lo,  hi,  szelem);
+                memcpy(hi,  tmp, szelem);
+            }
+
+            version (Windows)
+            {
+            }
+            else
+            {
+                //if (szelem > 16)
+                    // BUG: bad code is generate for delete pointer, tries
+                    // to call delclass.
+                    //gc_free(tmp);
+            }
+        }
+        return *cast(long*)(&a);
+    }
+
+unittest
+{
+    debug(adi) printf("array.reverse.unittest\n");
+
+    int[] a = new int[5];
+    int[] b;
+    size_t i;
+
+    for (i = 0; i < 5; i++)
+        a[i] = i;
+    b = a.reverse;
+    assert(b is a);
+    for (i = 0; i < 5; i++)
+        assert(a[i] == 4 - i);
+
+    struct X20
+    {   // More than 16 bytes in size
+        int a;
+        int b, c, d, e;
+    }
+
+    X20[] c = new X20[5];
+    X20[] d;
+
+    for (i = 0; i < 5; i++)
+    {   c[i].a = i;
+        c[i].e = 10;
+    }
+    d = c.reverse;
+    assert(d is c);
+    for (i = 0; i < 5; i++)
+    {
+        assert(c[i].a == 4 - i);
+        assert(c[i].e == 10);
+    }
+}
+
+/**********************************************
+ * Sort array of chars.
+ */
+
+extern (C) long _adSortChar(char[] a)
+{
+    if (a.length > 1)
+    {
+        dstring da = toUTF32(a);
+        da.sort;
+        size_t i = 0;
+        foreach (dchar d; da)
+        {   char[4] buf;
+            auto t = toUTF8(buf, d);
+            a[i .. i + t.length] = t[];
+            i += t.length;
+        }
+        delete da;
+    }
+    return *cast(long*)(&a);
+}
+
+/**********************************************
+ * Sort array of wchars.
+ */
+
+extern (C) long _adSortWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+        dstring da = toUTF32(a);
+        da.sort;
+        size_t i = 0;
+        foreach (dchar d; da)
+        {   wchar[2] buf;
+            auto t = toUTF16(buf, d);
+            a[i .. i + t.length] = t[];
+            i += t.length;
+        }
+        delete da;
+    }
+    return *cast(long*)(&a);
+}
+
+/***************************************
+ * Support for array equality test.
+ * Returns:
+ *      1       equal
+ *      0       not equal
+ */
+
+extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    if (a1.length != a2.length)
+        return 0; // not equal
+    auto sz = ti.tsize();
+    auto p1 = a1.ptr;
+    auto p2 = a2.ptr;
+
+    if (sz == 1)
+        // We should really have a ti.isPOD() check for this
+        return (memcmp(p1, p2, a1.length) == 0);
+
+    for (size_t i = 0; i < a1.length; i++)
+    {
+        if (!ti.equals(p1 + i * sz, p2 + i * sz))
+            return 0; // not equal
+    }
+    return 1; // equal
+}
+
+extern (C) int _adEq2(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    if (a1.length != a2.length)
+        return 0;               // not equal
+    if (!ti.equals(&a1, &a2))
+        return 0;
+    return 1;
+}
+unittest
+{
+    debug(adi) printf("array.Eq unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a != "hel");
+    assert(a != "helloo");
+    assert(a != "betty");
+    assert(a == "hello");
+    assert(a != "hxxxx");
+}
+
+/***************************************
+ * Support for array compare test.
+ */
+
+extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("adCmp()\n");
+    auto len = a1.length;
+    if (a2.length < len)
+        len = a2.length;
+    auto sz = ti.tsize();
+    void *p1 = a1.ptr;
+    void *p2 = a2.ptr;
+
+    if (sz == 1)
+    {   // We should really have a ti.isPOD() check for this
+        auto c = memcmp(p1, p2, len);
+        if (c)
+            return c;
+    }
+    else
+    {
+        for (size_t i = 0; i < len; i++)
+        {
+            auto c = ti.compare(p1 + i * sz, p2 + i * sz);
+            if (c)
+                return c;
+        }
+    }
+    if (a1.length == a2.length)
+        return 0;
+    return (a1.length > a2.length) ? 1 : -1;
+}
+
+extern (C) int _adCmp2(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    return ti.compare(&a1, &a2);
+}
+unittest
+{
+    debug(adi) printf("array.Cmp unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
+
+/***************************************
+ * Support for array compare test.
+ */
+
+extern (C) int _adCmpChar(Array a1, Array a2)
+{
+  version (X86)
+  {
+    asm
+    {   naked                   ;
+
+        push    EDI             ;
+        push    ESI             ;
+
+        mov    ESI,a1+4[4+ESP]  ;
+        mov    EDI,a2+4[4+ESP]  ;
+
+        mov    ECX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        cmp     ECX,EDX         ;
+        jb      GotLength       ;
+
+        mov     ECX,EDX         ;
+
+GotLength:
+        cmp    ECX,4            ;
+        jb    DoBytes           ;
+
+        // Do alignment if neither is dword aligned
+        test    ESI,3           ;
+        jz    Aligned           ;
+
+        test    EDI,3           ;
+        jz    Aligned           ;
+DoAlign:
+        mov    AL,[ESI]         ; //align ESI to dword bounds
+        mov    DL,[EDI]         ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        inc    ESI              ;
+        inc    EDI              ;
+
+        test    ESI,3           ;
+
+        lea    ECX,[ECX-1]      ;
+        jnz    DoAlign          ;
+Aligned:
+        mov    EAX,ECX          ;
+
+        // do multiple of 4 bytes at a time
+
+        shr    ECX,2            ;
+        jz    TryOdd            ;
+
+        repe                    ;
+        cmpsd                   ;
+
+        jnz    UnequalQuad      ;
+
+TryOdd:
+        mov    ECX,EAX          ;
+DoBytes:
+        // if still equal and not end of string, do up to 3 bytes slightly
+        // slower.
+
+        and    ECX,3            ;
+        jz    Equal             ;
+
+        repe                    ;
+        cmpsb                   ;
+
+        jnz    Unequal          ;
+Equal:
+        mov    EAX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        sub    EAX,EDX          ;
+        pop    ESI              ;
+
+        pop    EDI              ;
+        ret                     ;
+
+UnequalQuad:
+        mov    EDX,[EDI-4]      ;
+        mov    EAX,[ESI-4]      ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        cmp    AH,DH            ;
+        jnz    Unequal          ;
+
+        shr    EAX,16           ;
+
+        shr    EDX,16           ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        cmp    AH,DH            ;
+Unequal:
+        sbb    EAX,EAX          ;
+        pop    ESI              ;
+
+        or     EAX,1            ;
+        pop    EDI              ;
+
+        ret                     ;
+    }
+  }
+  else
+  {
+    int len;
+    int c;
+
+    debug(adi) printf("adCmpChar()\n");
+    len = a1.length;
+    if (a2.length < len)
+        len = a2.length;
+    c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
+    if (!c)
+        c = cast(int)a1.length - cast(int)a2.length;
+    return c;
+  }
+}
+
+unittest
+{
+    debug(adi) printf("array.CmpChar unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/alloca.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,110 @@
+/*_ _alloca.d
+ * Copyright (C) 1990-2003 by Digital Mars, www.digitalmars.com
+ * All Rights Reserved
+ * Written by Walter Bright
+ */
+
+module rt.alloca;
+
+/+
+#if DOS386
+extern size_t _x386_break;
+#else
+extern size_t _pastdata;
+#endif
++/
+
+/*******************************************
+ * Allocate data from the caller's stack frame.
+ * This is a 'magic' function that needs help from the compiler to
+ * work right, do not change its name, do not call it from other compilers.
+ * Input:
+ *      nbytes  number of bytes to allocate
+ *      ECX     address of variable with # of bytes in locals
+ *              This is adjusted upon return to reflect the additional
+ *              size of the stack frame.
+ * Returns:
+ *      EAX     allocated data, null if stack overflows
+ */
+
+extern (C) void* __alloca(int nbytes)
+{
+    asm
+    {
+        naked                   ;
+        mov     EDX,ECX         ;
+        mov     EAX,4[ESP]      ; // get nbytes
+        push    EBX             ;
+        push    EDI             ;
+        push    ESI             ;
+        add     EAX,3           ;
+        and     EAX,0xFFFFFFFC  ; // round up to dword
+        jnz     Abegin          ;
+        mov     EAX,4           ; // allow zero bytes allocation, 0 rounded to dword is 4..
+    Abegin:
+        mov     ESI,EAX         ; // ESI = nbytes
+        neg     EAX             ;
+        add     EAX,ESP         ; // EAX is now what the new ESP will be.
+        jae     Aoverflow       ;
+    }
+    version (Windows)
+    {
+    asm
+    {
+        // We need to be careful about the guard page
+        // Thus, for every 4k page, touch it to cause the OS to load it in.
+        mov     ECX,EAX         ; // ECX is new location for stack
+        mov     EBX,ESI         ; // EBX is size to "grow" stack
+    L1:
+        test    [ECX+EBX],EBX   ; // bring in page
+        sub     EBX,0x1000      ; // next 4K page down
+        jae     L1              ; // if more pages
+        test    [ECX],EBX       ; // bring in last page
+    }
+    }
+    version (DOS386)
+    {
+    asm
+    {
+        // is ESP off bottom?
+        cmp     EAX,_x386_break ;
+        jbe     Aoverflow       ;
+    }
+    }
+    version (Unix)
+    {
+    asm
+    {
+        cmp     EAX,_pastdata   ;
+        jbe     Aoverflow       ; // Unlikely - ~2 Gbytes under UNIX
+    }
+    }
+    asm
+    {
+        // Copy down to [ESP] the temps on the stack.
+        // The number of temps is (EBP - ESP - locals).
+        mov     ECX,EBP         ;
+        sub     ECX,ESP         ;
+        sub     ECX,[EDX]       ; // ECX = number of temps (bytes) to move.
+        add     [EDX],ESI       ; // adjust locals by nbytes for next call to alloca()
+        mov     ESP,EAX         ; // Set up new stack pointer.
+        add     EAX,ECX         ; // Return value = ESP + temps.
+        mov     EDI,ESP         ; // Destination of copy of temps.
+        add     ESI,ESP         ; // Source of copy.
+        shr     ECX,2           ; // ECX to count of dwords in temps
+                                  // Always at least 4 (nbytes, EIP, ESI,and EDI).
+        rep                     ;
+        movsd                   ;
+        jmp     done            ;
+
+    Aoverflow:
+        // Overflowed the stack.  Return null
+        xor     EAX,EAX         ;
+
+    done:
+        pop     ESI             ;
+        pop     EDI             ;
+        pop     EBX             ;
+        ret                     ;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arrayassign.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,180 @@
+/**
+ * Part of the D programming language runtime library.
+ *  http://www.digitalmars.com
+ *  Written by Walter Bright
+ *  Placed in the Public Domain
+ */
+module rt.arrayassign;
+
+private
+{
+    import util.string;
+    import stdc.string;
+    import stdc.stdlib;
+    debug(PRINTF) import stdc.stdio;
+}
+
+/**
+ * Does array assignment (not construction) from another
+ * array of the same element type.
+ * ti is the element type.
+ * Handles overlapping copies.
+ */
+extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to)
+{
+    debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize());
+
+    if (to.length != from.length)
+    {
+        char[10] tmp = void;
+        string msg = "lengths don't match for array copy,"c;
+        msg ~= tmp.intToString(to.length) ~ " = " ~ tmp.intToString(from.length);
+        throw new Exception(msg);
+    }
+
+    auto element_size = ti.tsize();
+
+    /* Need a temporary buffer tmp[] big enough to hold one element
+     */
+    void[16] buf = void;
+    void[] tmp;
+    if (element_size > buf.sizeof)
+        tmp = alloca(element_size)[0 .. element_size];
+    else
+        tmp = buf;
+
+
+    if (to.ptr <= from.ptr)
+    {
+        foreach (i; 0 .. to.length)
+        {
+            void* pto   = to.ptr   + i * element_size;
+            void* pfrom = from.ptr + i * element_size;
+            memcpy(tmp.ptr, pto, element_size);
+            memcpy(pto, pfrom, element_size);
+            ti.postblit(pto);
+            ti.destroy(tmp.ptr);
+        }
+    }
+    else
+    {
+        for (int i = to.length; i--; )
+        {
+            void* pto   = to.ptr   + i * element_size;
+            void* pfrom = from.ptr + i * element_size;
+            memcpy(tmp.ptr, pto, element_size);
+            memcpy(pto, pfrom, element_size);
+            ti.postblit(pto);
+            ti.destroy(tmp.ptr);
+        }
+    }
+    return to;
+}
+
+/**
+ * Does array initialization (not assignment) from another
+ * array of the same element type.
+ * ti is the element type.
+ */
+extern (C) void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to)
+{
+    debug(PRINTF) printf("_d_arrayctor(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize());
+
+    if (to.length != from.length)
+    {
+        char[10] tmp = void;
+        string msg = "lengths don't match for array initialization,"c;
+        msg ~= tmp.intToString(to.length) ~ " = " ~ tmp.intToString(from.length);
+        throw new Exception(msg);
+    }
+
+    auto element_size = ti.tsize();
+
+    int i;
+    try
+    {
+        for (i = 0; i < to.length; i++)
+        {
+            // Copy construction is defined as bit copy followed by postblit.
+            memcpy(to.ptr + i * element_size, from.ptr + i * element_size, element_size);
+            ti.postblit(to.ptr + i * element_size);
+        }
+    }
+    catch (Object o)
+    {
+        /* Destroy, in reverse order, what we've constructed so far
+         */
+        while (i--)
+        {
+            ti.destroy(to.ptr + i * element_size);
+        }
+
+        throw o;
+    }
+    return to;
+}
+
+
+/**
+ * Do assignment to an array.
+ *      p[0 .. count] = value;
+ */
+extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti)
+{
+    void* pstart = p;
+
+    auto element_size = ti.tsize();
+
+    //Need a temporary buffer tmp[] big enough to hold one element
+    void[16] buf = void;
+    void[] tmp;
+    if (element_size > buf.sizeof)
+    {
+        tmp = alloca(element_size)[0 .. element_size];
+    }
+    else
+        tmp = buf;
+
+    foreach (i; 0 .. count)
+    {
+        memcpy(tmp.ptr, p, element_size);
+        memcpy(p, value, element_size);
+        ti.postblit(p);
+        ti.destroy(tmp.ptr);
+        p += element_size;
+    }
+    return pstart;
+}
+
+/**
+ * Do construction of an array.
+ *      ti[count] p = value;
+ */
+extern (C) void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti)
+{
+    void* pstart = p;
+    auto element_size = ti.tsize();
+
+    try
+    {
+        foreach (i; 0 .. count)
+        {
+            // Copy construction is defined as bit copy followed by postblit.
+            memcpy(p, value, element_size);
+            ti.postblit(p);
+            p += element_size;
+        }
+    }
+    catch (Object o)
+    {
+        // Destroy, in reverse order, what we've constructed so far
+        while (p > pstart)
+        {
+            p -= element_size;
+            ti.destroy(p);
+        }
+
+        throw o;
+    }
+    return pstart;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arraybyte.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,1890 @@
+/***************************
+ * D programming language http://www.digitalmars.com/d/
+ * Runtime support for byte array operations.
+ * Based on code originally written by Burton Radons.
+ * Placed in public domain.
+ */
+
+/* Contains SSE2 and MMX versions of certain operations for char, byte,
+ * and ubyte ('a', 'g' and 'h' suffixes).
+ */
+
+module rt.arraybyte;
+
+import util.cpuid;
+
+version (Unittest)
+{
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 4;
+    bool mmx()      { return cpuid == 1 && util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias util.cpuid.mmx mmx;
+    alias util.cpuid.sse sse;
+    alias util.cpuid.sse2 sse2;
+    alias util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias byte T;
+
+extern (C):
+
+/* ======================================================================== */
+
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_a(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_g(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_h(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_g(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_g(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1088% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startaddsse2u:
+                    add ESI, 64;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM4;
+                    paddb XMM2, XMM4;
+                    paddb XMM3, XMM4;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startaddsse2a:
+                    add ESI, 64;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM4;
+                    paddb XMM2, XMM4;
+                    paddb XMM3, XMM4;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 1000% faster
+        if (mmx() && a.length >= 32)
+        {
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 4;
+            startaddmmx:
+                add ESI, 32;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                paddb MM0, MM4;
+                paddb MM1, MM4;
+                paddb MM2, MM4;
+                paddb MM3, MM4;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startaddmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        /* trying to be fair and treat normal 32-bit cpu the same way as we do
+         * the SIMD units, with unrolled asm.  There's not enough registers,
+         * really.
+         */
+        else
+        if (a.length >= 4)
+        {
+
+            auto n = aptr + (a.length & ~3);
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov CL, value;
+
+                align 4;
+            startadd386:
+                add ESI, 4;
+                mov DX, [EAX];
+                mov BX, [EAX+2];
+                add EAX, 4;
+                add BL, CL;
+                add BH, CL;
+                add DL, CL;
+                add DH, CL;
+                mov [ESI   -4], DX;
+                mov [ESI+2 -4], BX;
+                cmp ESI, EDI;
+                jb startadd386;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ + value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_a(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_g(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_h(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_g(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_g(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceAddSliceAssign_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 5739% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                version (log) printf("\tsse2 unaligned\n");
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 8;
+                startaddlsse2u:
+                    add ESI, 64;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    movdqu XMM4, [ECX];
+                    movdqu XMM5, [ECX+16];
+                    movdqu XMM6, [ECX+32];
+                    movdqu XMM7, [ECX+48];
+                    add ECX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM5;
+                    paddb XMM2, XMM6;
+                    paddb XMM3, XMM7;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddlsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                version (log) printf("\tsse2 aligned\n");
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 8;
+                startaddlsse2a:
+                    add ESI, 64;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    movdqa XMM4, [ECX];
+                    movdqa XMM5, [ECX+16];
+                    movdqa XMM6, [ECX+32];
+                    movdqa XMM7, [ECX+48];
+                    add ECX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM5;
+                    paddb XMM2, XMM6;
+                    paddb XMM3, XMM7;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddlsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 4428% faster
+        if (mmx() && a.length >= 32)
+        {
+            version (log) printf("\tmmx\n");
+            auto n = aptr + (a.length & ~31);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startaddlmmx:
+                add ESI, 32;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                movq MM4, [ECX];
+                movq MM5, [ECX+8];
+                movq MM6, [ECX+16];
+                movq MM7, [ECX+24];
+                add ECX, 32;
+                paddb MM0, MM4;
+                paddb MM1, MM5;
+                paddb MM2, MM6;
+                paddb MM3, MM7;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startaddlmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    version (log) if (aptr < aend) printf("\tbase\n");
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ + *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_a(T[] a, T value)
+{
+    return _arrayExpSliceAddass_g(a, value);
+}
+
+T[] _arrayExpSliceAddass_h(T[] a, T value)
+{
+    return _arrayExpSliceAddass_g(a, value);
+}
+
+T[] _arrayExpSliceAddass_g(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_g(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1578% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startaddasssse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM2, [ESI+32];
+                    movdqu XMM3, [ESI+48];
+                    add ESI, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM4;
+                    paddb XMM2, XMM4;
+                    paddb XMM3, XMM4;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddasssse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startaddasssse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM2, [ESI+32];
+                    movdqa XMM3, [ESI+48];
+                    add ESI, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM4;
+                    paddb XMM2, XMM4;
+                    paddb XMM3, XMM4;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddasssse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 1721% faster
+        if (mmx() && a.length >= 32)
+        {
+
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 8;
+            startaddassmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                add ESI, 32;
+                paddb MM0, MM4;
+                paddb MM1, MM4;
+                paddb MM2, MM4;
+                paddb MM3, MM4;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startaddassmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_a(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_g(a, b);
+}
+
+T[] _arraySliceSliceAddass_h(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_g(a, b);
+}
+
+T[] _arraySliceSliceAddass_g(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 4727% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 8;
+                startaddasslsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM2, [ESI+32];
+                    movdqu XMM3, [ESI+48];
+                    add ESI, 64;
+                    movdqu XMM4, [ECX];
+                    movdqu XMM5, [ECX+16];
+                    movdqu XMM6, [ECX+32];
+                    movdqu XMM7, [ECX+48];
+                    add ECX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM5;
+                    paddb XMM2, XMM6;
+                    paddb XMM3, XMM7;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddasslsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 8;
+                startaddasslsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM2, [ESI+32];
+                    movdqa XMM3, [ESI+48];
+                    add ESI, 64;
+                    movdqa XMM4, [ECX];
+                    movdqa XMM5, [ECX+16];
+                    movdqa XMM6, [ECX+32];
+                    movdqa XMM7, [ECX+48];
+                    add ECX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM5;
+                    paddb XMM2, XMM6;
+                    paddb XMM3, XMM7;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddasslsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 3059% faster
+        if (mmx() && a.length >= 32)
+        {
+
+            auto n = aptr + (a.length & ~31);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 8;
+            startaddasslmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                add ESI, 32;
+                movq MM4, [ECX];
+                movq MM5, [ECX+8];
+                movq MM6, [ECX+16];
+                movq MM7, [ECX+24];
+                add ECX, 32;
+                paddb MM0, MM4;
+                paddb MM1, MM5;
+                paddb MM2, MM6;
+                paddb MM3, MM7;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startaddasslmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_a(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_g(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_h(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_g(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_g(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1189% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubsse2u:
+                    add ESI, 64;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM4;
+                    psubb XMM2, XMM4;
+                    psubb XMM3, XMM4;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubsse2a:
+                    add ESI, 64;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM4;
+                    psubb XMM2, XMM4;
+                    psubb XMM3, XMM4;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 1079% faster
+        if (mmx() && a.length >= 32)
+        {
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 4;
+            startsubmmx:
+                add ESI, 32;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                psubb MM0, MM4;
+                psubb MM1, MM4;
+                psubb MM2, MM4;
+                psubb MM3, MM4;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startsubmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        // trying to be fair and treat normal 32-bit cpu the same way as we do the SIMD units, with unrolled asm.  There's not enough registers, really.
+        else
+        if (a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov CL, value;
+
+                align 4;
+            startsub386:
+                add ESI, 4;
+                mov DX, [EAX];
+                mov BX, [EAX+2];
+                add EAX, 4;
+                sub BL, CL;
+                sub BH, CL;
+                sub DL, CL;
+                sub DH, CL;
+                mov [ESI   -4], DX;
+                mov [ESI+2 -4], BX;
+                cmp ESI, EDI;
+                jb startsub386;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ - value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] = b[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, c[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_a(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_g(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_h(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_g(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_g(T[] a, T[] b, T value)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 8748% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubrsse2u:
+                    add ESI, 64;
+                    movdqa XMM5, XMM4;
+                    movdqa XMM6, XMM4;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    psubb XMM5, XMM0;
+                    psubb XMM6, XMM1;
+                    movdqu [ESI   -64], XMM5;
+                    movdqu [ESI+16-64], XMM6;
+                    movdqa XMM5, XMM4;
+                    movdqa XMM6, XMM4;
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    psubb XMM5, XMM2;
+                    psubb XMM6, XMM3;
+                    movdqu [ESI+32-64], XMM5;
+                    movdqu [ESI+48-64], XMM6;
+                    cmp ESI, EDI;
+                    jb startsubrsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubrsse2a:
+                    add ESI, 64;
+                    movdqa XMM5, XMM4;
+                    movdqa XMM6, XMM4;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    psubb XMM5, XMM0;
+                    psubb XMM6, XMM1;
+                    movdqa [ESI   -64], XMM5;
+                    movdqa [ESI+16-64], XMM6;
+                    movdqa XMM5, XMM4;
+                    movdqa XMM6, XMM4;
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    psubb XMM5, XMM2;
+                    psubb XMM6, XMM3;
+                    movdqa [ESI+32-64], XMM5;
+                    movdqa [ESI+48-64], XMM6;
+                    cmp ESI, EDI;
+                    jb startsubrsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 7397% faster
+        if (mmx() && a.length >= 32)
+        {
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 4;
+            startsubrmmx:
+                add ESI, 32;
+                movq MM5, MM4;
+                movq MM6, MM4;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                psubb MM5, MM0;
+                psubb MM6, MM1;
+                movq [ESI   -32], MM5;
+                movq [ESI+8 -32], MM6;
+                movq MM5, MM4;
+                movq MM6, MM4;
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                psubb MM5, MM2;
+                psubb MM6, MM3;
+                movq [ESI+16-32], MM5;
+                movq [ESI+24-32], MM6;
+                cmp ESI, EDI;
+                jb startsubrmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(value - *bptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] = 6 - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - b[i]))
+                {
+                    printf("[%d]: %d != 6 - %d\n", i, c[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_a(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_g(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_h(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_g(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_g(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 5756% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 8;
+                startsublsse2u:
+                    add ESI, 64;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    movdqu XMM4, [ECX];
+                    movdqu XMM5, [ECX+16];
+                    movdqu XMM6, [ECX+32];
+                    movdqu XMM7, [ECX+48];
+                    add ECX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM5;
+                    psubb XMM2, XMM6;
+                    psubb XMM3, XMM7;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsublsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 8;
+                startsublsse2a:
+                    add ESI, 64;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    movdqa XMM4, [ECX];
+                    movdqa XMM5, [ECX+16];
+                    movdqa XMM6, [ECX+32];
+                    movdqa XMM7, [ECX+48];
+                    add ECX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM5;
+                    psubb XMM2, XMM6;
+                    psubb XMM3, XMM7;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsublsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 4428% faster
+        if (mmx() && a.length >= 32)
+        {
+            auto n = aptr + (a.length & ~31);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 8;
+            startsublmmx:
+                add ESI, 32;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                movq MM4, [ECX];
+                movq MM5, [ECX+8];
+                movq MM6, [ECX+16];
+                movq MM7, [ECX+24];
+                add ECX, 32;
+                psubb MM0, MM4;
+                psubb MM1, MM5;
+                psubb MM2, MM6;
+                psubb MM3, MM7;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startsublmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ - *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_a(T[] a, T value)
+{
+    return _arrayExpSliceMinass_g(a, value);
+}
+
+T[] _arrayExpSliceMinass_h(T[] a, T value)
+{
+    return _arrayExpSliceMinass_g(a, value);
+}
+
+T[] _arrayExpSliceMinass_g(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_g(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1577% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubasssse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM2, [ESI+32];
+                    movdqu XMM3, [ESI+48];
+                    add ESI, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM4;
+                    psubb XMM2, XMM4;
+                    psubb XMM3, XMM4;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubasssse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubasssse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM2, [ESI+32];
+                    movdqa XMM3, [ESI+48];
+                    add ESI, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM4;
+                    psubb XMM2, XMM4;
+                    psubb XMM3, XMM4;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubasssse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 1577% faster
+        if (mmx() && a.length >= 32)
+        {
+
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 8;
+            startsubassmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                add ESI, 32;
+                psubb MM0, MM4;
+                psubb MM1, MM4;
+                psubb MM2, MM4;
+                psubb MM3, MM4;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startsubassmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_a(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_g(a, b);
+}
+
+T[] _arraySliceSliceMinass_h(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_g(a, b);
+}
+
+T[] _arraySliceSliceMinass_g(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 4800% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 8;
+                startsubasslsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM2, [ESI+32];
+                    movdqu XMM3, [ESI+48];
+                    add ESI, 64;
+                    movdqu XMM4, [ECX];
+                    movdqu XMM5, [ECX+16];
+                    movdqu XMM6, [ECX+32];
+                    movdqu XMM7, [ECX+48];
+                    add ECX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM5;
+                    psubb XMM2, XMM6;
+                    psubb XMM3, XMM7;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubasslsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 8;
+                startsubasslsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM2, [ESI+32];
+                    movdqa XMM3, [ESI+48];
+                    add ESI, 64;
+                    movdqa XMM4, [ECX];
+                    movdqa XMM5, [ECX+16];
+                    movdqa XMM6, [ECX+32];
+                    movdqa XMM7, [ECX+48];
+                    add ECX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM5;
+                    psubb XMM2, XMM6;
+                    psubb XMM3, XMM7;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubasslsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 3107% faster
+        if (mmx() && a.length >= 32)
+        {
+
+            auto n = aptr + (a.length & ~31);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 8;
+            startsubasslmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                add ESI, 32;
+                movq MM4, [ECX];
+                movq MM5, [ECX+8];
+                movq MM6, [ECX+16];
+                movq MM7, [ECX+24];
+                add ECX, 32;
+                psubb MM0, MM4;
+                psubb MM1, MM5;
+                psubb MM2, MM6;
+                psubb MM3, MM7;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startsubasslmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinass_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arraycast.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.arraycast;
+
+/******************************************
+ * Runtime helper to convert dynamic array of one
+ * type to dynamic array of another.
+ * Adjusts the length of the array.
+ * Throws exception if new length is not aligned.
+ */
+
+extern (C)
+
+void[] _d_arraycast(size_t tsize, size_t fsize, void[] a)
+{
+    auto length = a.length;
+
+    auto nbytes = length * fsize;
+    if (nbytes % tsize != 0)
+    {
+    throw new Exception("array cast misalignment");
+    }
+    length = nbytes / tsize;
+    *cast(size_t *)&a = length; // jam new length
+    return a;
+}
+
+unittest
+{
+    byte[int.sizeof * 3] b;
+    int[] i;
+    short[] s;
+
+    i = cast(int[])b;
+    assert(i.length == 3);
+
+    s = cast(short[])b;
+    assert(s.length == 6);
+
+    s = cast(short[])i;
+    assert(s.length == 6);
+}
+
+/******************************************
+ * Runtime helper to convert dynamic array of bits
+ * dynamic array of another.
+ * Adjusts the length of the array.
+ * Throws exception if new length is not aligned.
+ */
+
+version (none)
+{
+extern (C)
+
+void[] _d_arraycast_frombit(uint tsize, void[] a)
+{
+    uint length = a.length;
+
+    if (length & 7)
+    {
+    throw new Exception("bit[] array cast misalignment");
+    }
+    length /= 8 * tsize;
+    *cast(size_t *)&a = length; // jam new length
+    return a;
+}
+
+unittest
+{
+    version (D_Bits)
+    {
+    bit[int.sizeof * 3 * 8] b;
+    int[] i;
+    short[] s;
+
+    i = cast(int[])b;
+    assert(i.length == 3);
+
+    s = cast(short[])b;
+    assert(s.length == 6);
+    }
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arraycat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,61 @@
+/**
+ * Part of the D programming language runtime library.
+ */
+
+/*
+ *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.arraycat;
+
+private
+{
+    import stdc.string;
+    debug import stdc.stdio;
+}
+
+extern (C):
+
+byte[] _d_arraycopy(size_t size, byte[] from, byte[] to)
+{
+    debug printf("f = %p,%d, t = %p,%d, size = %d\n",
+                 from.ptr, from.length, to.ptr, to.length, size);
+
+    if (to.length != from.length)
+    {
+        throw new Exception("lengths don't match for array copy");
+    }
+    else if (to.ptr + to.length * size <= from.ptr ||
+             from.ptr + from.length * size <= to.ptr)
+    {
+        memcpy(to.ptr, from.ptr, to.length * size);
+    }
+    else
+    {
+        throw new Exception("overlapping array copy");
+    }
+    return to;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arraydouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,1714 @@
+/***************************
+ * D programming language http://www.digitalmars.com/d/
+ * Runtime support for double array operations.
+ * Based on code originally written by Burton Radons.
+ * Placed in public domain.
+ */
+
+module rt.arraydouble;
+
+private import util.cpuid;
+
+version (Unittest)
+{
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 5;
+    bool mmx()      { return cpuid == 1 && util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias util.cpuid.mmx mmx;
+    alias util.cpuid.sse sse;
+    alias util.cpuid.sse2 sse2;
+    alias util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+/* Performance figures measured by Burton Radons
+ */
+
+alias double T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_d(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 333% faster
+        if (sse2() && b.length >= 16)
+        {
+            auto n = aptr + (b.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ESI, 64;
+                addpd XMM0, XMM4;
+                addpd XMM1, XMM5;
+                addpd XMM2, XMM6;
+                addpd XMM3, XMM7;
+                add ECX, 64;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ = *bptr++ + *cptr++;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_d(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 324% faster
+        if (sse2() && b.length >= 8)
+        {
+            auto n = aptr + (b.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ESI, 64;
+                subpd XMM0, XMM4;
+                subpd XMM1, XMM5;
+                subpd XMM2, XMM6;
+                subpd XMM3, XMM7;
+                add ECX, 64;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ = *bptr++ - *cptr++;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %g != %g - %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_d(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 305% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                addpd XMM0, XMM4;
+                addpd XMM1, XMM4;
+                addpd XMM2, XMM4;
+                addpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ + value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %g != %g + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_d(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 114% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = cast(T*)((cast(uint)aend) & ~7);
+            if (aptr < n)
+
+            // Unaligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                addpd XMM0, XMM4;
+                addpd XMM1, XMM4;
+                addpd XMM2, XMM4;
+                addpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %g != %g + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_d(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 183% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ECX, 64;
+                addpd XMM0, XMM4;
+                addpd XMM1, XMM5;
+                addpd XMM2, XMM6;
+                addpd XMM3, XMM7;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_d(T[] a, T value, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 305% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                subpd XMM0, XMM4;
+                subpd XMM1, XMM4;
+                subpd XMM2, XMM4;
+                subpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ - value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_d(T[] a, T[] b, T value)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 66% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movapd XMM5, XMM4;
+                movapd XMM6, XMM4;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                subpd XMM5, XMM0;
+                subpd XMM6, XMM1;
+                movupd [ESI+ 0-64], XMM5;
+                movupd [ESI+16-64], XMM6;
+                movapd XMM5, XMM4;
+                movapd XMM6, XMM4;
+                subpd XMM5, XMM2;
+                subpd XMM6, XMM3;
+                movupd [ESI+32-64], XMM5;
+                movupd [ESI+48-64], XMM6;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = value - *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = 6 - a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - a[i]))
+                {
+                    printf("[%d]: %g != 6 - %g\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_d(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 115% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = cast(T*)((cast(uint)aend) & ~7);
+            if (aptr < n)
+
+            // Unaligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                subpd XMM0, XMM4;
+                subpd XMM1, XMM4;
+                subpd XMM2, XMM4;
+                subpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_d(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 183% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ECX, 64;
+                subpd XMM0, XMM4;
+                subpd XMM1, XMM5;
+                subpd XMM2, XMM6;
+                subpd XMM3, XMM7;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAssign_d(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMulSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 304% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM4;
+                mulpd XMM2, XMM4;
+                mulpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * c[]
+ */
+
+T[] _arraySliceSliceMulSliceAssign_d(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceMulSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 329% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add ESI, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add EAX, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM5;
+                mulpd XMM2, XMM6;
+                mulpd XMM3, XMM7;
+                add ECX, 64;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * b[i]))
+                {
+                    printf("[%d]: %g != %g * %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= value
+ */
+
+T[] _arrayExpSliceMulass_d(T[] a, T value)
+{
+    //printf("_arrayExpSliceMulass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 109% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = cast(T*)((cast(uint)aend) & ~7);
+            if (aptr < n)
+
+            // Unaligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM4;
+                mulpd XMM2, XMM4;
+                mulpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= b[]
+ */
+
+T[] _arraySliceSliceMulass_d(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMulass_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 205% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ECX, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM5;
+                mulpd XMM2, XMM6;
+                mulpd XMM3, XMM7;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] / value
+ */
+
+T[] _arraySliceExpDivSliceAssign_d(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpDivSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    /* Multiplying by the reciprocal is faster, but does
+     * not produce as accurate an answer.
+     */
+    T recip = cast(T)1 / value;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 299% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, recip;
+                //movsd XMM4, value
+                //rcpsd XMM4, XMM4
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM4;
+                mulpd XMM2, XMM4;
+                mulpd XMM3, XMM4;
+                //divpd XMM0, XMM4;
+                //divpd XMM1, XMM4;
+                //divpd XMM2, XMM4;
+                //divpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+    {
+        *aptr++ = *bptr++ / value;
+        //*aptr++ = *bptr++ * recip;
+    }
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpDivSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] / 8;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %g ?= %g / 8\n", i, c[i], a[i]);
+                if (c[i] != cast(T)(a[i] / 8))
+                {
+                    printf("[%d]: %g != %g / 8\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] /= value
+ */
+
+T[] _arrayExpSliceDivass_d(T[] a, T value)
+{
+    //printf("_arrayExpSliceDivass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    /* Multiplying by the reciprocal is faster, but does
+     * not produce as accurate an answer.
+     */
+    T recip = cast(T)1 / value;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 65% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, recip;
+                //movsd XMM4, value
+                //rcpsd XMM4, XMM4
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM4;
+                mulpd XMM2, XMM4;
+                mulpd XMM3, XMM4;
+                //divpd XMM0, XMM4;
+                //divpd XMM1, XMM4;
+                //divpd XMM2, XMM4;
+                //divpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= recip;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arrayExpSliceDivass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] /= 8;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] / 8))
+                {
+                    printf("[%d]: %g != %g / 8\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[] * value
+ */
+
+T[] _arraySliceExpMulSliceMinass_d(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAddass_d(a, -value, b);
+}
+
+/***********************
+ * Computes:
+ *      a[] += b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAddass_d(T[] a, T value, T[] b)
+in
+{
+        assert(a.length == b.length);
+        assert(disjoint(a, b));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ += *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAddass_d unittest\n");
+
+    cpuid = 1;
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 1; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]);
+                if (c[i] != cast(T)(b[i] + a[i] * 6))
+                {
+                    printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arrayfloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,2303 @@
+/***************************
+ * D programming language http://www.digitalmars.com/d/
+ * Runtime support for float array operations.
+ * Based on code originally written by Burton Radons.
+ * Placed in public domain.
+ */
+
+module rt.arrayfloat;
+
+private import util.cpuid;
+
+version (Unittest)
+{
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 5;
+    bool mmx()      { return cpuid == 1 && util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias util.cpuid.mmx mmx;
+    alias util.cpuid.sse sse;
+    alias util.cpuid.sse2 sse2;
+    alias util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias float T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_f(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceAddSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 834% faster
+        if (sse() && b.length >= 16)
+        {
+            version (log) printf("\tsse unaligned\n");
+            auto n = aptr + (b.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ESI, 64;
+                addps XMM0, XMM4;
+                addps XMM1, XMM5;
+                addps XMM2, XMM6;
+                addps XMM3, XMM7;
+                add ECX, 64;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is only 13% faster
+        if (amd3dnow() && b.length >= 8)
+        {
+            version (log) printf("\tamd3dnow\n");
+            auto n = aptr + (b.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+
+                align 4;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfadd MM0, [ECX];
+                pfadd MM1, [ECX+8];
+                pfadd MM2, [ECX+16];
+                pfadd MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ECX, 32;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    // Handle remainder
+    version (log) if (aptr < aend) printf("\tbase\n");
+    while (aptr < aend)
+        *aptr++ = *bptr++ + *cptr++;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_f(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 834% faster
+        if (sse() && b.length >= 16)
+        {
+            auto n = aptr + (b.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ESI, 64;
+                subps XMM0, XMM4;
+                subps XMM1, XMM5;
+                subps XMM2, XMM6;
+                subps XMM3, XMM7;
+                add ECX, 64;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is only 13% faster
+        if (amd3dnow() && b.length >= 8)
+        {
+            auto n = aptr + (b.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+
+                align 4;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfsub MM0, [ECX];
+                pfsub MM1, [ECX+8];
+                pfsub MM2, [ECX+16];
+                pfsub MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ECX, 32;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ = *bptr++ - *cptr++;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %g != %gd - %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_f(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 665% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                addps XMM0, XMM4;
+                addps XMM1, XMM4;
+                addps XMM2, XMM4;
+                addps XMM3, XMM4;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 69% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfadd MM0, MM4;
+                pfadd MM1, MM4;
+                pfadd MM2, MM4;
+                pfadd MM3, MM4;
+                movq [ESI],    MM0;
+                movq [ESI+8],  MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ + value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %g != %g + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_f(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 302% faster
+        if (sse() && a.length >= 16)
+        {
+            // align pointer
+            auto n = cast(T*)((cast(uint)aptr + 15) & ~15);
+            while (aptr < n)
+                *aptr++ += value;
+            n = cast(T*)((cast(uint)aend) & ~15);
+            if (aptr < n)
+
+            // Aligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movaps XMM0, [ESI];
+                movaps XMM1, [ESI+16];
+                movaps XMM2, [ESI+32];
+                movaps XMM3, [ESI+48];
+                add ESI, 64;
+                addps XMM0, XMM4;
+                addps XMM1, XMM4;
+                addps XMM2, XMM4;
+                addps XMM3, XMM4;
+                movaps [ESI+ 0-64], XMM0;
+                movaps [ESI+16-64], XMM1;
+                movaps [ESI+32-64], XMM2;
+                movaps [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+        else
+        // 3DNow! version is 63% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start3dnow:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfadd MM0, MM4;
+                pfadd MM1, MM4;
+                pfadd MM2, MM4;
+                pfadd MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %g != %g + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_f(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 468% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [ESI];
+                movups XMM1, [ESI+16];
+                movups XMM2, [ESI+32];
+                movups XMM3, [ESI+48];
+                add ESI, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ECX, 64;
+                addps XMM0, XMM4;
+                addps XMM1, XMM5;
+                addps XMM2, XMM6;
+                addps XMM3, XMM7;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is 57% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr]; // destination operand
+                mov EDI, dword ptr [n];    // end comparison
+                mov ECX, dword ptr [bptr]; // right operand
+
+                align 4;
+            start3dnow:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfadd MM0, [ECX];
+                pfadd MM1, [ECX+8];
+                pfadd MM2, [ECX+16];
+                pfadd MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add ECX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+                mov dword ptr [bptr], ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_f(T[] a, T value, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 622% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                subps XMM0, XMM4;
+                subps XMM1, XMM4;
+                subps XMM2, XMM4;
+                subps XMM3, XMM4;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 67% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            T[2] w;
+
+            w[0] = w[1] = value;
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                mov EAX, dword ptr [bptr];
+                movq MM4, qword ptr [w];
+
+                align 8;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfsub MM0, MM4;
+                pfsub MM1, MM4;
+                pfsub MM2, MM4;
+                pfsub MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+                mov dword ptr [bptr], EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ - value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_f(T[] a, T[] b, T value)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 690% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movaps XMM5, XMM4;
+                movaps XMM6, XMM4;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                subps XMM5, XMM0;
+                subps XMM6, XMM1;
+                movups [ESI+ 0-64], XMM5;
+                movups [ESI+16-64], XMM6;
+                movaps XMM5, XMM4;
+                movaps XMM6, XMM4;
+                subps XMM5, XMM2;
+                subps XMM6, XMM3;
+                movups [ESI+32-64], XMM5;
+                movups [ESI+48-64], XMM6;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 67% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfsubr MM0, MM4;
+                pfsubr MM1, MM4;
+                pfsubr MM2, MM4;
+                pfsubr MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = value - *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = 6 - a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - a[i]))
+                {
+                    printf("[%d]: %g != 6 - %g\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_f(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 304% faster
+        if (sse() && a.length >= 16)
+        {
+            // align pointer
+            auto n = cast(T*)((cast(uint)aptr + 15) & ~15);
+            while (aptr < n)
+                *aptr++ -= value;
+            n = cast(T*)((cast(uint)aend) & ~15);
+            if (aptr < n)
+
+            // Aligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movaps XMM0, [ESI];
+                movaps XMM1, [ESI+16];
+                movaps XMM2, [ESI+32];
+                movaps XMM3, [ESI+48];
+                add ESI, 64;
+                subps XMM0, XMM4;
+                subps XMM1, XMM4;
+                subps XMM2, XMM4;
+                subps XMM3, XMM4;
+                movaps [ESI+ 0-64], XMM0;
+                movaps [ESI+16-64], XMM1;
+                movaps [ESI+32-64], XMM2;
+                movaps [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+        else
+        // 3DNow! version is 63% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfsub MM0, MM4;
+                pfsub MM1, MM4;
+                pfsub MM2, MM4;
+                pfsub MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceminass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_f(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 468% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [ESI];
+                movups XMM1, [ESI+16];
+                movups XMM2, [ESI+32];
+                movups XMM3, [ESI+48];
+                add ESI, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ECX, 64;
+                subps XMM0, XMM4;
+                subps XMM1, XMM5;
+                subps XMM2, XMM6;
+                subps XMM3, XMM7;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is 57% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr]; // destination operand
+                mov EDI, dword ptr [n]; // end comparison
+                mov ECX, dword ptr [bptr]; // right operand
+
+                align 4;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfsub MM0, [ECX];
+                pfsub MM1, [ECX+8];
+                pfsub MM2, [ECX+16];
+                pfsub MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add ECX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAssign_f(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMulSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 607% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM4;
+                mulps XMM2, XMM4;
+                mulps XMM3, XMM4;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 69% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                mov EAX, dword ptr [bptr];
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfmul MM0, MM4;
+                pfmul MM1, MM4;
+                pfmul MM2, MM4;
+                pfmul MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * c[]
+ */
+
+T[] _arraySliceSliceMulSliceAssign_f(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceMulSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 833% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add ESI, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add EAX, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM5;
+                mulps XMM2, XMM6;
+                mulps XMM3, XMM7;
+                add ECX, 64;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is only 13% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr]; // destination operand
+                mov EDI, dword ptr [n]; // end comparison
+                mov EAX, dword ptr [bptr]; // left operand
+                mov ECX, dword ptr [cptr]; // right operand
+
+                align 4;
+            start:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfmul MM0, [ECX];
+                pfmul MM1, [ECX+8];
+                pfmul MM2, [ECX+16];
+                pfmul MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ECX, 32;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * b[i]))
+                {
+                    printf("[%d]: %g != %g * %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= value
+ */
+
+T[] _arrayExpSliceMulass_f(T[] a, T value)
+{
+    //printf("_arrayExpSliceMulass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 303% faster
+        if (sse() && a.length >= 16)
+        {
+            // align pointer
+            auto n = cast(T*)((cast(uint)aptr + 15) & ~15);
+            while (aptr < n)
+                *aptr++ *= value;
+            n = cast(T*)((cast(uint)aend) & ~15);
+            if (aptr < n)
+
+            // Aligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movaps XMM0, [ESI];
+                movaps XMM1, [ESI+16];
+                movaps XMM2, [ESI+32];
+                movaps XMM3, [ESI+48];
+                add ESI, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM4;
+                mulps XMM2, XMM4;
+                mulps XMM3, XMM4;
+                movaps [ESI+ 0-64], XMM0;
+                movaps [ESI+16-64], XMM1;
+                movaps [ESI+32-64], XMM2;
+                movaps [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+        else
+        // 3DNow! version is 63% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfmul MM0, MM4;
+                pfmul MM1, MM4;
+                pfmul MM2, MM4;
+                pfmul MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= b[]
+ */
+
+T[] _arraySliceSliceMulass_f(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMulass_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 525% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [ESI];
+                movups XMM1, [ESI+16];
+                movups XMM2, [ESI+32];
+                movups XMM3, [ESI+48];
+                add ESI, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ECX, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM5;
+                mulps XMM2, XMM6;
+                mulps XMM3, XMM7;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is 57% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr]; // destination operand
+                mov EDI, dword ptr [n]; // end comparison
+                mov ECX, dword ptr [bptr]; // right operand
+
+                align 4;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfmul MM0, [ECX];
+                pfmul MM1, [ECX+8];
+                pfmul MM2, [ECX+16];
+                pfmul MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add ECX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+                mov dword ptr [bptr], ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] / value
+ */
+
+T[] _arraySliceExpDivSliceAssign_f(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpDivSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    /* Multiplying by the reciprocal is faster, but does
+     * not produce as accurate an answer.
+     */
+    T recip = cast(T)1 / value;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 587% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, recip;
+                //movss XMM4, value
+                //rcpss XMM4, XMM4
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM4;
+                mulps XMM2, XMM4;
+                mulps XMM3, XMM4;
+                //divps XMM0, XMM4;
+                //divps XMM1, XMM4;
+                //divps XMM2, XMM4;
+                //divps XMM3, XMM4;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 72% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            T[2] w = void;
+
+            w[0] = recip;
+            w[1] = recip;
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                mov EAX, dword ptr [bptr];
+                movq MM4, qword ptr [w];
+
+                align 8;
+            start:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfmul MM0, MM4;
+                pfmul MM1, MM4;
+                pfmul MM2, MM4;
+                pfmul MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+                mov dword ptr [bptr], EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * recip;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpDivSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] / 8;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] / 8))
+                {
+                    printf("[%d]: %g != %g / 8\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] /= value
+ */
+
+T[] _arrayExpSliceDivass_f(T[] a, T value)
+{
+    //printf("_arrayExpSliceDivass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    /* Multiplying by the reciprocal is faster, but does
+     * not produce as accurate an answer.
+     */
+    T recip = cast(T)1 / value;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 245% faster
+        if (sse() && a.length >= 16)
+        {
+            // align pointer
+            auto n = cast(T*)((cast(uint)aptr + 15) & ~15);
+            while (aptr < n)
+                *aptr++ *= recip;
+            n = cast(T*)((cast(uint)aend) & ~15);
+            if (aptr < n)
+
+            // Aligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, recip;
+                //movss XMM4, value
+                //rcpss XMM4, XMM4
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movaps XMM0, [ESI];
+                movaps XMM1, [ESI+16];
+                movaps XMM2, [ESI+32];
+                movaps XMM3, [ESI+48];
+                add ESI, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM4;
+                mulps XMM2, XMM4;
+                mulps XMM3, XMM4;
+                //divps XMM0, XMM4;
+                //divps XMM1, XMM4;
+                //divps XMM2, XMM4;
+                //divps XMM3, XMM4;
+                movaps [ESI+ 0-64], XMM0;
+                movaps [ESI+16-64], XMM1;
+                movaps [ESI+32-64], XMM2;
+                movaps [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+        else
+        // 3DNow! version is 57% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            T[2] w = void;
+
+            w[0] = w[1] = recip;
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                movq MM4, qword ptr [w];
+
+                align 8;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfmul MM0, MM4;
+                pfmul MM1, MM4;
+                pfmul MM2, MM4;
+                pfmul MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= recip;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceDivass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] /= 8;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] / 8))
+                {
+                    printf("[%d]: %g != %g / 8\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[] * value
+ */
+
+T[] _arraySliceExpMulSliceMinass_f(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAddass_f(a, -value, b);
+}
+
+/***********************
+ * Computes:
+ *      a[] += b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAddass_f(T[] a, T value, T[] b)
+in
+{
+        assert(a.length == b.length);
+        assert(disjoint(a, b));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ += *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAddass_f unittest\n");
+
+    cpuid = 1;
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 1; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]);
+                if (c[i] != cast(T)(b[i] + a[i] * 6))
+                {
+                    printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arrayint.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,2427 @@
+/***************************
+ * D programming language http://www.digitalmars.com/d/
+ * Runtime support for byte array operations.
+ * Based on code originally written by Burton Radons.
+ * Placed in public domain.
+ */
+
+/* Contains MMX versions of certain operations for dchar, int,
+ * and uint ('w', 'i' and 'k' suffixes).
+ */
+
+module rt.arrayint;
+
+private import util.cpuid;
+
+version (Unittest)
+{
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 4;
+    bool mmx()      { return cpuid == 1 && util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias util.cpuid.mmx mmx;
+    alias util.cpuid.sse sse;
+    alias util.cpuid.sse2 sse2;
+    alias util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias int T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_w(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_k(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_i(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 380% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 298% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                paddd MM0, MM2;
+                paddd MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        if (a.length >= 2)
+        {
+            auto n = aptr + (a.length & ~1);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov EDX, value;
+
+                align 4;
+            start386:
+                add ESI, 8;
+                mov EBX, [EAX];
+                mov ECX, [EAX+4];
+                add EAX, 8;
+                add EBX, EDX;
+                add ECX, EDX;
+                mov [ESI  -8], EBX;
+                mov [ESI+4-8], ECX;
+                cmp ESI, EDI;
+                jb start386;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ + value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_w(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_k(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_i(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceAddSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1710% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 995% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM2, [ECX];
+                movq MM1, [EAX+8];
+                movq MM3, [ECX+8];
+                add EAX, 16;
+                add ECX, 16;
+                paddd MM0, MM2;
+                paddd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+normal:
+    while (aptr < aend)
+        *aptr++ = *bptr++ + *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_w(T[] a, T value)
+{
+    return _arrayExpSliceAddass_i(a, value);
+}
+
+T[] _arrayExpSliceAddass_k(T[] a, T value)
+{
+    return _arrayExpSliceAddass_i(a, value);
+}
+
+T[] _arrayExpSliceAddass_i(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 83% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 81% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                paddd MM0, MM2;
+                paddd MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+        else
+        if (a.length >= 2)
+        {
+            auto n = aptr + (a.length & ~1);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EDX, value;
+
+                align 4;
+            start386:
+                mov EBX, [ESI];
+                mov ECX, [ESI+4];
+                add ESI, 8;
+                add EBX, EDX;
+                add ECX, EDX;
+                mov [ESI  -8], EBX;
+                mov [ESI+4-8], ECX;
+                cmp ESI, EDI;
+                jb start386;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            a[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(c[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, a[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_w(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_i(a, b);
+}
+
+T[] _arraySliceSliceAddass_k(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_i(a, b);
+}
+
+T[] _arraySliceSliceAddass_i(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 695% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 471% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM2, [ECX];
+                movq MM1, [ESI+8];
+                movq MM3, [ECX+8];
+                add ESI, 16;
+                add ECX, 16;
+                paddd MM0, MM2;
+                paddd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+normal:
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] + a[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_w(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_k(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_i(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 400% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 315% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        if (a.length >= 2)
+        {
+            auto n = aptr + (a.length & ~1);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov EDX, value;
+
+                align 4;
+            start386:
+                add ESI, 8;
+                mov EBX, [EAX];
+                mov ECX, [EAX+4];
+                add EAX, 8;
+                sub EBX, EDX;
+                sub ECX, EDX;
+                mov [ESI  -8], EBX;
+                mov [ESI+4-8], ECX;
+                cmp ESI, EDI;
+                jb start386;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ - value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_w(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_i(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_k(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_i(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_i(T[] a, T[] b, T value)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1812% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM2, [EAX];
+                    movdqu XMM3, [EAX+16];
+                    movdqa XMM0, XMM4;
+                    movdqa XMM1, XMM4;
+                    add EAX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM2, [EAX];
+                    movdqa XMM3, [EAX+16];
+                    movdqa XMM0, XMM4;
+                    movdqa XMM1, XMM4;
+                    add EAX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 1077% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM4, l;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM2, [EAX];
+                movq MM3, [EAX+8];
+                movq MM0, MM4;
+                movq MM1, MM4;
+                add EAX, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = value - *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = 6 - a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - a[i]))
+                {
+                    printf("[%d]: %d != 6 - %d\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_w(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_k(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_i(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1721% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 1002% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM2, [ECX];
+                movq MM1, [EAX+8];
+                movq MM3, [ECX+8];
+                add EAX, 16;
+                add ECX, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ - *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_w(T[] a, T value)
+{
+    return _arrayExpSliceMinass_i(a, value);
+}
+
+T[] _arrayExpSliceMinass_k(T[] a, T value)
+{
+    return _arrayExpSliceMinass_i(a, value);
+}
+
+T[] _arrayExpSliceMinass_i(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 81% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 81% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+        else
+        if (a.length >= 2)
+        {
+            auto n = aptr + (a.length & ~1);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EDX, value;
+
+                align 4;
+            start386:
+                mov EBX, [ESI];
+                mov ECX, [ESI+4];
+                add ESI, 8;
+                sub EBX, EDX;
+                sub ECX, EDX;
+                mov [ESI  -8], EBX;
+                mov [ESI+4-8], ECX;
+                cmp ESI, EDI;
+                jb start386;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            a[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(c[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, a[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_w(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_i(a, b);
+}
+
+T[] _arraySliceSliceMinass_k(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_i(a, b);
+}
+
+T[] _arraySliceSliceMinass_i(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 731% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 441% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM2, [ECX];
+                movq MM1, [ESI+8];
+                movq MM3, [ECX+8];
+                add ESI, 16;
+                add ECX, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] -= a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] - a[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAssign_w(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpMulSliceAssign_k(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpMulSliceAssign_i(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMulSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+  version (none)        // multiplying a pair is not supported by MMX
+  {
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1380% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        {
+        // MMX version is 1380% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                pmuludq MM0, MM2;       // only multiplies low 32 bits
+                pmuludq MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+        }
+  }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %d ?= %d * 6\n", i, c[i], a[i]);
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %d != %d * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * c[]
+ */
+
+T[] _arraySliceSliceMulSliceAssign_w(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMulSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceMulSliceAssign_k(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMulSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceMulSliceAssign_i(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceMulSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+  version (none)
+  {
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1407% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+               }
+            }
+        }
+        else
+        // MMX version is 1029% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM2, [ECX];
+                movq MM1, [EAX+8];
+                movq MM3, [ECX+8];
+                add EAX, 16;
+                add ECX, 16;
+                pmuludq MM0, MM2;
+                pmuludq MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+  }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * b[i]))
+                {
+                    printf("[%d]: %d != %d * %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= value
+ */
+
+T[] _arrayExpSliceMulass_w(T[] a, T value)
+{
+    return _arrayExpSliceMulass_i(a, value);
+}
+
+T[] _arrayExpSliceMulass_k(T[] a, T value)
+{
+    return _arrayExpSliceMulass_i(a, value);
+}
+
+T[] _arrayExpSliceMulass_i(T[] a, T value)
+{
+    //printf("_arrayExpSliceMulass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+  version (none)
+  {
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 400% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 402% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                pmuludq MM0, MM2;
+                pmuludq MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+  }
+
+    while (aptr < aend)
+        *aptr++ *= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = a[];
+            a[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(b[i] * 6))
+                {
+                    printf("[%d]: %d != %d * 6\n", i, a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= b[]
+ */
+
+T[] _arraySliceSliceMulass_w(T[] a, T[] b)
+{
+    return _arraySliceSliceMulass_i(a, b);
+}
+
+T[] _arraySliceSliceMulass_k(T[] a, T[] b)
+{
+    return _arraySliceSliceMulass_i(a, b);
+}
+
+T[] _arraySliceSliceMulass_i(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMulass_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+  version (none)
+  {
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 873% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+               }
+            }
+        }
+/+ BUG: comment out this section until we figure out what is going
+   wrong with the invalid pshufd instructions.
+
+        else
+        // MMX version is 573% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM2, [ECX];
+                movq MM1, [ESI+8];
+                movq MM3, [ECX+8];
+                pxor MM4, MM4;
+                pxor MM5, MM5;
+                punpckldq MM4, MM0;
+                punpckldq MM5, MM2;
+                add ESI, 16;
+                add ECX, 16;
+                pmuludq MM4, MM5;
+                pshufd MM4, MM4, 8;     // ?
+                movq [ESI  -16], MM4;
+                pxor MM4, MM4;
+                pxor MM5, MM5;
+                punpckldq MM4, MM1;
+                punpckldq MM5, MM3;
+                pmuludq MM4, MM5;
+                pshufd MM4, MM4, 8;     // ?
+                movq [ESI+8-16], MM4;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
++/
+    }
+  }
+
+    while (aptr < aend)
+        *aptr++ *= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = a[];
+            a[] *= c[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(b[i] * c[i]))
+                {
+                    printf("[%d]: %d != %d * %d\n", i, a[i], b[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arrayreal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,234 @@
+/***************************
+ * D programming language http://www.digitalmars.com/d/
+ * Runtime support for double array operations.
+ * Placed in public domain.
+ */
+
+module rt.arrayreal;
+
+import util.cpuid;
+
+version (Unittest)
+{
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 1;
+    bool mmx()      { return cpuid == 1 && util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias util.cpuid.mmx mmx;
+    alias util.cpuid.sse sse;
+    alias util.cpuid.sse2 sse2;
+    alias util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias real T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_r(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    for (int i = 0; i < a.length; i++)
+        a[i] = b[i] + c[i];
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_r unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %Lg != %Lg + %Lg\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_r(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    for (int i = 0; i < a.length; i++)
+        a[i] = b[i] - c[i];
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_r unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %Lg != %Lg - %Lg\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[] * value
+ */
+
+T[] _arraySliceExpMulSliceMinass_r(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAddass_r(a, -value, b);
+}
+
+/***********************
+ * Computes:
+ *      a[] += b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAddass_r(T[] a, T value, T[] b)
+in
+{
+        assert(a.length == b.length);
+        assert(disjoint(a, b));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ += *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAddass_r unittest\n");
+
+    cpuid = 1;
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 1; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]);
+                if (c[i] != cast(T)(b[i] + a[i] * 6))
+                {
+                    printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/arrayshort.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,2300 @@
+/***************************
+ * D programming language http://www.digitalmars.com/d/
+ * Runtime support for byte array operations.
+ * Based on code originally written by Burton Radons.
+ * Placed in public domain.
+ */
+
+/* Contains SSE2 and MMX versions of certain operations for wchar, short,
+ * and ushort ('u', 's' and 't' suffixes).
+ */
+
+module rt.arrayshort;
+
+private import util.cpuid;
+
+version (Unittest)
+{
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 4;
+    bool mmx()      { return cpuid == 1 && util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias util.cpuid.mmx mmx;
+    alias util.cpuid.sse sse;
+    alias util.cpuid.sse2 sse2;
+    alias util.cpuid.sse2 sse2;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias short T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_u(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_t(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_s(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 3343% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 3343% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                paddw MM0, MM2;
+                paddw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ + value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_u(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_t(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_s(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceAddSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 3777% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    movdqu XMM2, [ECX];
+                    movdqu XMM3, [ECX+16];
+                    add ECX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    movdqa XMM2, [ECX];
+                    movdqa XMM3, [ECX+16];
+                    add ECX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 2068% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                movq MM2, [ECX];
+                movq MM3, [ECX+8];
+                add ECX, 16;
+                paddw MM0, MM2;
+                paddw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ + *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_u(T[] a, T value)
+{
+    return _arrayExpSliceAddass_s(a, value);
+}
+
+T[] _arrayExpSliceAddass_t(T[] a, T value)
+{
+    return _arrayExpSliceAddass_s(a, value);
+}
+
+T[] _arrayExpSliceAddass_s(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 832% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 826% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                paddw MM0, MM2;
+                paddw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            a[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(c[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, a[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_u(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_s(a, b);
+}
+
+T[] _arraySliceSliceAddass_t(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_s(a, b);
+}
+
+T[] _arraySliceSliceAddass_s(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2085% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    movdqu XMM2, [ECX];
+                    movdqu XMM3, [ECX+16];
+                    add ECX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    movdqa XMM2, [ECX];
+                    movdqa XMM3, [ECX+16];
+                    add ECX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 1022% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                movq MM2, [ECX];
+                movq MM3, [ECX+8];
+                add ECX, 16;
+                paddw MM0, MM2;
+                paddw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] + a[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_u(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_t(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_s(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 3695% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 3049% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ - value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_u(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_s(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_t(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_s(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_s(T[] a, T[] b, T value)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 4995% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+
+                    align 4;
+                startaddsse2u:
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+                    movd XMM3, l;
+                    pshufd XMM3, XMM3, 0;
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubw XMM2, XMM0;
+                    psubw XMM3, XMM1;
+                    movdqu [ESI   -32], XMM2;
+                    movdqu [ESI+16-32], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+
+                    align 4;
+                startaddsse2a:
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+                    movd XMM3, l;
+                    pshufd XMM3, XMM3, 0;
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubw XMM2, XMM0;
+                    psubw XMM3, XMM1;
+                    movdqa [ESI   -32], XMM2;
+                    movdqa [ESI+16-32], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 4562% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM2, [EAX];
+                movq MM3, [EAX+8];
+                movq MM0, MM4;
+                movq MM1, MM4;
+                add EAX, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(value - *bptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = 6 - a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - a[i]))
+                {
+                    printf("[%d]: %d != 6 - %d\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_u(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_t(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_s(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 4129% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    movdqu XMM2, [ECX];
+                    movdqu XMM3, [ECX+16];
+                    add ECX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    movdqa XMM2, [ECX];
+                    movdqa XMM3, [ECX+16];
+                    add ECX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 2018% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                movq MM2, [ECX];
+                movq MM3, [ECX+8];
+                add ECX, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ - *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_u(T[] a, T value)
+{
+    return _arrayExpSliceMinass_s(a, value);
+}
+
+T[] _arrayExpSliceMinass_t(T[] a, T value)
+{
+    return _arrayExpSliceMinass_s(a, value);
+}
+
+T[] _arrayExpSliceMinass_s(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 835% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 835% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            a[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(c[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, a[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_u(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_s(a, b);
+}
+
+T[] _arraySliceSliceMinass_t(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_s(a, b);
+}
+
+T[] _arraySliceSliceMinass_s(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2121% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    movdqu XMM2, [ECX];
+                    movdqu XMM3, [ECX+16];
+                    add ECX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    movdqa XMM2, [ECX];
+                    movdqa XMM3, [ECX+16];
+                    add ECX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 1116% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                movq MM2, [ECX];
+                movq MM3, [ECX+8];
+                add ECX, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] -= a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] - a[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAssign_u(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpMulSliceAssign_t(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpMulSliceAssign_s(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMulSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 3733% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= l << 16;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 3733% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                pmullw MM0, MM2;
+                pmullw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ * value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %d != %d * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * c[]
+ */
+
+T[] _arraySliceSliceMulSliceAssign_u(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMulSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceMulSliceAssign_t(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMulSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceMulSliceAssign_s(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceMulSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2515% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+               }
+            }
+        }
+        else
+        // MMX version is 2515% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM2, [ECX];
+                movq MM1, [EAX+8];
+                movq MM3, [ECX+8];
+                add EAX, 16;
+                add ECX, 16;
+                pmullw MM0, MM2;
+                pmullw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ * *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * b[i]))
+                {
+                    printf("[%d]: %d != %d * %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= value
+ */
+
+T[] _arrayExpSliceMulass_u(T[] a, T value)
+{
+    return _arrayExpSliceMulass_s(a, value);
+}
+
+T[] _arrayExpSliceMulass_t(T[] a, T value)
+{
+    return _arrayExpSliceMulass_s(a, value);
+}
+
+T[] _arrayExpSliceMulass_s(T[] a, T value)
+{
+    //printf("_arrayExpSliceMulass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2044% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= l << 16;
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 2056% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                pmullw MM0, MM2;
+                pmullw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = a[];
+            a[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(b[i] * 6))
+                {
+                    printf("[%d]: %d != %d * 6\n", i, a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= b[]
+ */
+
+T[] _arraySliceSliceMulass_u(T[] a, T[] b)
+{
+    return _arraySliceSliceMulass_s(a, b);
+}
+
+T[] _arraySliceSliceMulass_t(T[] a, T[] b)
+{
+    return _arraySliceSliceMulass_s(a, b);
+}
+
+T[] _arraySliceSliceMulass_s(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMulass_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2519% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+               }
+            }
+        }
+        else
+        // MMX version is 1712% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM2, [ECX];
+                movq MM1, [ESI+8];
+                movq MM3, [ECX+8];
+                add ESI, 16;
+                add ECX, 16;
+                pmullw MM0, MM2;
+                pmullw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = a[];
+            a[] *= c[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(b[i] * c[i]))
+                {
+                    printf("[%d]: %d != %d * %d\n", i, a[i], b[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/cast_.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,184 @@
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.cast_;
+
+extern (C):
+
+/******************************************
+ * Given a pointer:
+ *      If it is an Object, return that Object.
+ *      If it is an interface, return the Object implementing the interface.
+ *      If it is null, return null.
+ *      Else, undefined crash
+ */
+
+Object _d_toObject(void* p)
+{   Object o;
+
+    if (p)
+    {
+        o = cast(Object)p;
+        ClassInfo oc = o.classinfo;
+        Interface *pi = **cast(Interface ***)p;
+
+        /* Interface.offset lines up with ClassInfo.name.ptr,
+         * so we rely on pointers never being less than 64K,
+         * and Objects never being greater.
+         */
+        if (pi.offset < 0x10000)
+        {
+            //printf("\tpi.offset = %d\n", pi.offset);
+            o = cast(Object)(p - pi.offset);
+        }
+    }
+    return o;
+}
+
+
+/*************************************
+ * Attempts to cast Object o to class c.
+ * Returns o if successful, null if not.
+ */
+
+Object _d_interface_cast(void* p, ClassInfo c)
+{   Object o;
+
+    //printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
+    if (p)
+    {
+        Interface *pi = **cast(Interface ***)p;
+
+        //printf("\tpi.offset = %d\n", pi.offset);
+        o = cast(Object)(p - pi.offset);
+        return _d_dynamic_cast(o, c);
+    }
+    return o;
+}
+
+Object _d_dynamic_cast(Object o, ClassInfo c)
+{   ClassInfo oc;
+    size_t offset = 0;
+
+    //printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
+
+    if (o)
+    {
+        oc = o.classinfo;
+        if (_d_isbaseof2(oc, c, offset))
+        {
+            //printf("\toffset = %d\n", offset);
+            o = cast(Object)(cast(void*)o + offset);
+        }
+        else
+            o = null;
+    }
+    //printf("\tresult = %p\n", o);
+    return o;
+}
+
+int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout size_t offset)
+{   int i;
+
+    if (oc is c)
+        return 1;
+    do
+    {
+        if (oc.base is c)
+            return 1;
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            if (ic is c)
+            {   offset = oc.interfaces[i].offset;
+                return 1;
+            }
+        }
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            if (_d_isbaseof2(ic, c, offset))
+            {   offset = oc.interfaces[i].offset;
+                return 1;
+            }
+        }
+        oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+int _d_isbaseof(ClassInfo oc, ClassInfo c)
+{   int i;
+
+    if (oc is c)
+        return 1;
+    do
+    {
+        if (oc.base is c)
+            return 1;
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            if (ic is c || _d_isbaseof(ic, c))
+                return 1;
+        }
+        oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+/*********************************
+ * Find the vtbl[] associated with Interface ic.
+ */
+
+void *_d_interface_vtbl(ClassInfo ic, Object o)
+{   int i;
+    ClassInfo oc;
+
+    //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
+
+    assert(o);
+
+    oc = o.classinfo;
+    for (i = 0; i < oc.interfaces.length; i++)
+    {
+        ClassInfo oic;
+
+        oic = oc.interfaces[i].classinfo;
+        if (oic is ic)
+        {
+            return cast(void *)oc.interfaces[i].vtbl;
+        }
+    }
+    assert(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/cmath2.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,218 @@
+
+// Copyright (C) 2001-2003 by Digital Mars
+// All Rights Reserved
+// www.digitalmars.com
+
+// Runtime support for complex arithmetic code generation
+// (for linux)
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.cmath2;
+
+private import stdc.math;
+
+extern (C):
+
+/****************************
+ * Multiply two complex floating point numbers, x and y.
+ * Input:
+ *      x.re    ST3
+ *      x.im    ST2
+ *      y.re    ST1
+ *      y.im    ST0
+ * Output:
+ *      ST1     real part
+ *      ST0     imaginary part
+ */
+
+void _Cmul()
+{
+    // p.re = x.re * y.re - x.im * y.im;
+    // p.im = x.im * y.re + x.re * y.im;
+    asm
+    {   naked                   ;
+        fld     ST(1)           ; // x.re
+        fmul    ST,ST(4)        ; // ST0 = x.re * y.re
+
+        fld     ST(1)           ; // y.im
+        fmul    ST,ST(4)        ; // ST0 = x.im * y.im
+
+        fsubp   ST(1),ST        ; // ST0 = x.re * y.re - x.im * y.im
+
+        fld     ST(3)           ; // x.im
+        fmul    ST,ST(3)        ; // ST0 = x.im * y.re
+
+        fld     ST(5)           ; // x.re
+        fmul    ST,ST(3)        ; // ST0 = x.re * y.im
+
+        faddp   ST(1),ST        ; // ST0 = x.im * y.re + x.re * y.im
+
+        fxch    ST(4),ST        ;
+        fstp    ST(0)           ;
+        fxch    ST(4),ST        ;
+        fstp    ST(0)           ;
+        fstp    ST(0)           ;
+        fstp    ST(0)           ;
+
+        ret                     ;
+    }
+/+
+    if (isnan(x) && isnan(y))
+    {
+        // Recover infinities that computed as NaN+ iNaN ...
+        int recalc = 0;
+        if ( isinf( a) || isinf( b) )
+        {   // z is infinite
+            // "Box" the infinity and change NaNs in the other factor to 0
+            a = copysignl( isinf( a) ? 1.0 : 0.0, a);
+            b = copysignl( isinf( b) ? 1.0 : 0.0, b);
+            if (isnan( c)) c = copysignl( 0.0, c);
+            if (isnan( d)) d = copysignl( 0.0, d);
+            recalc = 1;
+        }
+        if (isinf(c) || isinf(d))
+        {   // w is infinite
+            // "Box" the infinity and change NaNs in the other factor to 0
+            c = copysignl( isinf( c) ? 1.0 : 0.0, c);
+            d = copysignl( isinf( d) ? 1.0 : 0.0, d);
+            if (isnan( a)) a = copysignl( 0.0, a);
+            if (isnan( b)) b = copysignl( 0.0, b);
+            recalc = 1;
+        }
+        if (!recalc && (isinf(ac) || isinf(bd) ||
+            isinf(ad) || isinf(bc)))
+        {
+            // Recover infinities from overflow by changing NaNs to 0 ...
+            if (isnan( a)) a = copysignl( 0.0, a);
+            if (isnan( b)) b = copysignl( 0.0, b);
+            if (isnan( c)) c = copysignl( 0.0, c);
+            if (isnan( d)) d = copysignl( 0.0, d);
+            recalc = 1;
+        }
+        if (recalc)
+        {
+            x = INFINITY * (a * c - b * d);
+            y = INFINITY * (a * d + b * c);
+        }
+    }
++/
+}
+
+/****************************
+ * Divide two complex floating point numbers, x / y.
+ * Input:
+ *      x.re    ST3
+ *      x.im    ST2
+ *      y.re    ST1
+ *      y.im    ST0
+ * Output:
+ *      ST1     real part
+ *      ST0     imaginary part
+ */
+
+void _Cdiv()
+{
+    real x_re, x_im;
+    real y_re, y_im;
+    real q_re, q_im;
+    real r;
+    real den;
+
+    asm
+    {
+        fstp    y_im    ;
+        fstp    y_re    ;
+        fstp    x_im    ;
+        fstp    x_re    ;
+    }
+
+    if (fabs(y_re) < fabs(y_im))
+    {
+        r = y_re / y_im;
+        den = y_im + r * y_re;
+        q_re = (x_re * r + x_im) / den;
+        q_im = (x_im * r - x_re) / den;
+    }
+    else
+    {
+        r = y_im / y_re;
+        den = y_re + r * y_im;
+        q_re = (x_re + r * x_im) / den;
+        q_im = (x_im - r * x_re) / den;
+    }
+//printf("q.re = %g, q.im = %g\n", (double)q_re, (double)q_im);
+/+
+    if (isnan(q_re) && isnan(q_im))
+    {
+        real denom = y_re * y_re + y_im * y_im;
+
+        // non-zero / zero
+        if (denom == 0.0 && (!isnan(x_re) || !isnan(x_im)))
+        {
+            q_re = copysignl(INFINITY, y_re) * x_re;
+            q_im = copysignl(INFINITY, y_re) * x_im;
+        }
+        // infinite / finite
+        else if ((isinf(x_re) || isinf(x_im)) && isfinite(y_re) && isfinite(y_im))
+        {
+            x_re = copysignl(isinf(x_re) ? 1.0 : 0.0, x_re);
+            x_im = copysignl(isinf(x_im) ? 1.0 : 0.0, x_im);
+            q_re = INFINITY * (x_re * y_re + x_im * y_im);
+            q_im = INFINITY * (x_im * y_re - x_re * y_im);
+        }
+        // finite / infinite
+        else if (isinf(logbw) && isfinite(x_re) && isfinite(x_im))
+        {
+            y_re = copysignl(isinf(y_re) ? 1.0 : 0.0, y_re);
+            y_im = copysignl(isinf(y_im) ? 1.0 : 0.0, y_im);
+            q_re = 0.0 * (x_re * y_re + x_im * y_im);
+            q_im = 0.0 * (x_im * y_re - x_re * y_im);
+        }
+    }
+    return q_re + q_im * 1.0i;
++/
+    asm
+    {
+        fld     q_re;
+        fld     q_im;
+    }
+}
+
+/****************************
+ * Compare two complex floating point numbers, x and y.
+ * Input:
+ *      x.re    ST3
+ *      x.im    ST2
+ *      y.re    ST1
+ *      y.im    ST0
+ * Output:
+ *      8087 stack is cleared
+ *      flags set
+ */
+
+void _Ccmp()
+{
+    asm
+    {   naked                   ;
+        fucomp  ST(2)           ; // compare x.im and y.im
+        fstsw   AX              ;
+        sahf                    ;
+        jne     L1              ;
+        jp      L1              ; // jmp if NAN
+        fucomp  ST(2)           ; // compare x.re and y.re
+        fstsw   AX              ;
+        sahf                    ;
+        fstp    ST(0)           ; // pop
+        fstp    ST(0)           ; // pop
+        ret                     ;
+
+      L1:
+        fstp    ST(0)           ; // pop
+        fstp    ST(0)           ; // pop
+        fstp    ST(0)           ; // pop
+        ret                     ;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/compiler.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,36 @@
+
+/* Written by Walter Bright
+ * www.digitalmars.com
+ * Placed into Public Domain
+ */
+
+module rt.compiler;
+
+// Identify the compiler used and its various features.
+
+const
+{
+    // Vendor specific string naming the compiler
+    char[] name = "Digital Mars D";
+
+    // Master list of D compiler vendors
+    enum Vendor
+    {
+        DigitalMars = 1
+    }
+
+    // Which vendor we are
+    Vendor vendor = Vendor.DigitalMars;
+
+
+    // The vendor specific version number, as in
+    // version_major.version_minor
+    uint version_major = 0;
+    uint version_minor = 0;
+
+
+    // The version of the D Programming Language Specification
+    // Supported by the compiler
+    uint D_major = 0;
+    uint D_minor = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/complex.c	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,107 @@
+/*
+ *  Placed into the public domain.
+ *  Written by Walter Bright
+ *  www.digitalmars.com
+ */
+
+
+#include <math.h>
+
+typedef struct Complex
+{
+    long double re;
+    long double im;
+} Complex;
+
+Complex _complex_div(Complex x, Complex y)
+{
+    Complex q;
+    long double r;
+    long double den;
+
+    if (fabs(y.re) < fabs(y.im))
+    {
+        r = y.re / y.im;
+        den = y.im + r * y.re;
+        q.re = (x.re * r + x.im) / den;
+        q.im = (x.im * r - x.re) / den;
+    }
+    else
+    {
+        r = y.im / y.re;
+        den = y.re + r * y.im;
+        q.re = (x.re + r * x.im) / den;
+        q.im = (x.im - r * x.re) / den;
+    }
+    return q;
+}
+
+Complex _complex_mul(Complex x, Complex y)
+{
+    Complex p;
+
+    p.re = x.re * y.re - x.im * y.im;
+    p.im = x.im * y.re + x.re * y.im;
+    return p;
+}
+
+long double _complex_abs(Complex z)
+{
+    long double x,y,ans,temp;
+
+    x = fabs(z.re);
+    y = fabs(z.im);
+    if (x == 0)
+        ans = y;
+    else if (y == 0)
+        ans = x;
+    else if (x > y)
+    {
+        temp = y / x;
+        ans = x * sqrt(1 + temp * temp);
+    }
+    else
+    {
+        temp = x / y;
+        ans = y * sqrt(1 + temp * temp);
+    }
+    return ans;
+}
+
+Complex _complex_sqrt(Complex z)
+{
+    Complex c;
+    long double x,y,w,r;
+
+    if (z.re == 0 && z.im == 0)
+    {
+        c.re = 0;
+        c.im = 0;
+    }
+    else
+    {
+        x = fabs(z.re);
+        y = fabs(z.im);
+        if (x >= y)
+        {
+            r = y / x;
+            w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
+        }
+        else
+        {
+            r = x / y;
+            w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
+        }
+        if (z.re >= 0)
+        {
+            c.re = w;
+            c.im = z.im / (w + w);
+        }
+        else
+        {
+            c.im = (z.im >= 0) ? w : -w;
+            c.re = z.im / (c.im + c.im);
+        }
+    }
+    return c;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/cover.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,373 @@
+/**
+ * Code coverage analyzer.
+ *
+ * Bugs:
+ *      $(UL
+ *          $(LI the execution counters are 32 bits in size, and can overflow)
+ *          $(LI inline asm statements are not counted)
+ *      )
+ *
+ * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.  All rights reserved.
+ * License:   BSD style: $(LICENSE)
+ * Authors:   Walter Bright, Sean Kelly
+ */
+
+module rt.cover;
+
+private
+{
+    version( Windows )
+        import sys.windows.windows;
+    else version( Posix )
+    {
+        import stdc.posix.fcntl;
+        import stdc.posix.unistd;
+    }
+    import core.bitmanip;
+    import stdc.stdio;
+    import util.utf;
+
+    struct BitArray
+    {
+        size_t  len;
+        uint*   ptr;
+
+        bool opIndex( size_t i )
+        in
+        {
+            assert( i < len );
+        }
+        body
+        {
+            return cast(bool) bt( ptr, i );
+        }
+    }
+
+    struct Cover
+    {
+        char[]      filename;
+        BitArray    valid;
+        uint[]      data;
+    }
+
+    Cover[] gdata;
+    char[]  srcpath;
+    char[]  dstpath;
+    bool    merge;
+}
+
+
+/**
+ * Set path to where source files are located.
+ *
+ * Params:
+ *  pathname = The new path name.
+ */
+extern (C) void dmd_coverSourcePath( char[] pathname )
+{
+    srcpath = pathname;
+}
+
+
+/**
+ * Set path to where listing files are to be written.
+ *
+ * Params:
+ *  pathname = The new path name.
+ */
+extern (C) void dmd_coverDestPath( char[] pathname )
+{
+    dstpath = pathname;
+}
+
+
+/**
+ * Set merge mode.
+ *
+ * Params:
+ *      flag = true means new data is summed with existing data in the listing
+ *         file; false means a new listing file is always created.
+ */
+extern (C) void dmd_coverSetMerge( bool flag )
+{
+    merge = flag;
+}
+
+
+/**
+ * The coverage callback.
+ *
+ * Params:
+ *  filename = The name of the coverage file.
+ *  valid    = ???
+ *  data     = ???
+ */
+extern (C) void _d_cover_register( char[] filename, BitArray valid, uint[] data )
+{
+    Cover c;
+
+    c.filename  = filename;
+    c.valid     = valid;
+    c.data      = data;
+    gdata      ~= c;
+}
+
+
+static ~this()
+{
+    const NUMLINES = 16384 - 1;
+    const NUMCHARS = 16384 * 16 - 1;
+
+    char[]      srcbuf      = new char[NUMCHARS];
+    char[][]    srclines    = new char[][NUMLINES];
+    char[]      lstbuf      = new char[NUMCHARS];
+    char[][]    lstlines    = new char[][NUMLINES];
+
+    foreach( Cover c; gdata )
+    {
+        if( !readFile( appendFN( srcpath, c.filename ), srcbuf ) )
+            continue;
+        splitLines( srcbuf, srclines );
+
+        if( merge )
+        {
+            if( !readFile( c.filename ~ ".lst", lstbuf ) )
+                break;
+            splitLines( lstbuf, lstlines );
+
+            for( size_t i = 0; i < lstlines.length; ++i )
+            {
+                if( i >= c.data.length )
+                    break;
+
+                int count = 0;
+
+                foreach( char c2; lstlines[i] )
+                {
+                    switch( c2 )
+                    {
+                    case ' ':
+                        continue;
+                    case '0': case '1': case '2': case '3': case '4':
+                    case '5': case '6': case '7': case '8': case '9':
+                        count = count * 10 + c2 - '0';
+                        continue;
+                    default:
+                        break;
+                    }
+                }
+                c.data[i] += count;
+            }
+        }
+
+        FILE* flst = fopen( (c.filename ~ ".lst").ptr, "wb" );
+
+        if( !flst )
+            continue; //throw new Exception( "Error opening file for write: " ~ lstfn );
+
+        uint nno;
+        uint nyes;
+
+        for( int i = 0; i < c.data.length; i++ )
+        {
+            if( i < srclines.length )
+            {
+                uint    n    = c.data[i];
+                char[]  line = srclines[i];
+
+                line = expandTabs( line );
+
+                if( n == 0 )
+                {
+                    if( c.valid[i] )
+                    {
+                        nno++;
+                        fprintf( flst, "0000000|%.*s\n", line );
+                    }
+                    else
+                    {
+                        fprintf( flst, "       |%.*s\n", line );
+                    }
+                }
+                else
+                {
+                    nyes++;
+                    fprintf( flst, "%7u|%.*s\n", n, line );
+                }
+            }
+        }
+        if( nyes + nno ) // no divide by 0 bugs
+        {
+            fprintf( flst, "%.*s is %d%% covered\n", c.filename, ( nyes * 100 ) / ( nyes + nno ) );
+        }
+        fclose( flst );
+    }
+}
+
+
+char[] appendFN( char[] path, char[] name )
+{
+    version( Windows )
+        const char sep = '\\';
+    else
+        const char sep = '/';
+
+    char[] dest = path;
+
+    if( dest && dest[$ - 1] != sep )
+        dest ~= sep;
+    dest ~= name;
+    return dest;
+}
+
+
+bool readFile( char[] name, inout char[] buf )
+{
+    version( Windows )
+    {
+        auto    wnamez  = toUTF16z( name );
+        HANDLE  file    = CreateFileW( wnamez,
+                                       GENERIC_READ,
+                                       FILE_SHARE_READ,
+                                       null,
+                                       OPEN_EXISTING,
+                                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+                                       cast(HANDLE) null );
+
+        delete wnamez;
+        if( file == INVALID_HANDLE_VALUE )
+            return false;
+        scope( exit ) CloseHandle( file );
+
+        DWORD   num = 0;
+        DWORD   pos = 0;
+
+        buf.length = 4096;
+        while( true )
+        {
+            if( !ReadFile( file, &buf[pos], cast(DWORD)( buf.length - pos ), &num, null ) )
+                return false;
+            if( !num )
+                break;
+            pos += num;
+            buf.length = pos * 2;
+        }
+        buf.length = pos;
+        return true;
+    }
+    else version( linux )
+    {
+        char[]  namez = new char[name.length + 1];
+                        namez[0 .. name.length] = name;
+                        namez[$ - 1] = 0;
+        int     file = open( namez.ptr, O_RDONLY );
+
+        delete namez;
+        if( file == -1 )
+            return false;
+        scope( exit ) close( file );
+
+        int     num = 0;
+        uint    pos = 0;
+
+        buf.length = 4096;
+        while( true )
+        {
+            num = read( file, &buf[pos], cast(uint)( buf.length - pos ) );
+            if( num == -1 )
+                return false;
+            if( !num )
+                break;
+            pos += num;
+            buf.length = pos * 2;
+        }
+        buf.length = pos;
+        return true;
+    }
+}
+
+
+void splitLines( char[] buf, inout char[][] lines )
+{
+    size_t  beg = 0,
+            pos = 0;
+
+    lines.length = 0;
+    for( ; pos < buf.length; ++pos )
+    {
+        char c = buf[pos];
+
+        switch( buf[pos] )
+        {
+        case '\r':
+        case '\n':
+            lines ~= buf[beg .. pos];
+            beg = pos + 1;
+            if( buf[pos] == '\r' && pos < buf.length - 1 && buf[pos + 1] == '\n' )
+                ++pos, ++beg;
+        default:
+            continue;
+        }
+    }
+    if( beg != pos )
+    {
+        lines ~= buf[beg .. pos];
+    }
+}
+
+
+char[] expandTabs( char[] string, int tabsize = 8 )
+{
+    const dchar LS = '\u2028'; // UTF line separator
+    const dchar PS = '\u2029'; // UTF paragraph separator
+
+    bool changes = false;
+    char[] result = string;
+    int column;
+    int nspaces;
+
+    foreach( size_t i, dchar c; string )
+    {
+        switch( c )
+        {
+            case '\t':
+                nspaces = tabsize - (column % tabsize);
+                if( !changes )
+                {
+                    changes = true;
+                    result = null;
+                    result.length = string.length + nspaces - 1;
+                    result.length = i + nspaces;
+                    result[0 .. i] = string[0 .. i];
+                    result[i .. i + nspaces] = ' ';
+                }
+                else
+                {   int j = result.length;
+                    result.length = j + nspaces;
+                    result[j .. j + nspaces] = ' ';
+                }
+                column += nspaces;
+                break;
+
+            case '\r':
+            case '\n':
+            case PS:
+            case LS:
+                column = 0;
+                goto L1;
+
+            default:
+                column++;
+            L1:
+                if (changes)
+                {
+                    if (c <= 0x7F)
+                        result ~= c;
+                    else
+                        encode(result, c);
+                }
+                break;
+        }
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/critical.c	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,159 @@
+/*
+ * Placed into the Public Domain
+ * written by Walter Bright, Digital Mars
+ * www.digitalmars.com
+ */
+
+/* ================================= Win32 ============================ */
+
+#if _WIN32
+
+#include        <windows.h>
+
+/******************************************
+ * Enter/exit critical section.
+ */
+
+/* We don't initialize critical sections unless we actually need them.
+ * So keep a linked list of the ones we do use, and in the static destructor
+ * code, walk the list and release them.
+ */
+
+typedef struct D_CRITICAL_SECTION
+{
+    struct D_CRITICAL_SECTION *next;
+    CRITICAL_SECTION cs;
+} D_CRITICAL_SECTION;
+
+static D_CRITICAL_SECTION *dcs_list;
+static D_CRITICAL_SECTION critical_section;
+static volatile int inited;
+
+void _d_criticalenter(D_CRITICAL_SECTION *dcs)
+{
+    if (!dcs->next)
+    {
+        EnterCriticalSection(&critical_section.cs);
+        if (!dcs->next) // if, in the meantime, another thread didn't set it
+        {
+            dcs->next = dcs_list;
+            dcs_list = dcs;
+            InitializeCriticalSection(&dcs->cs);
+        }
+        LeaveCriticalSection(&critical_section.cs);
+    }
+    EnterCriticalSection(&dcs->cs);
+}
+
+void _d_criticalexit(D_CRITICAL_SECTION *dcs)
+{
+    LeaveCriticalSection(&dcs->cs);
+}
+
+void _STI_critical_init()
+{
+    if (!inited)
+    {   InitializeCriticalSection(&critical_section.cs);
+        dcs_list = &critical_section;
+        inited = 1;
+    }
+}
+
+void _STD_critical_term()
+{
+    if (inited)
+    {   inited = 0;
+        while (dcs_list)
+        {
+            DeleteCriticalSection(&dcs_list->cs);
+            dcs_list = dcs_list->next;
+        }
+    }
+}
+
+#endif
+
+/* ================================= linux ============================ */
+
+#if linux
+
+#include        <stdio.h>
+#include        <stdlib.h>
+#include        <pthread.h>
+
+/******************************************
+ * Enter/exit critical section.
+ */
+
+/* We don't initialize critical sections unless we actually need them.
+ * So keep a linked list of the ones we do use, and in the static destructor
+ * code, walk the list and release them.
+ */
+
+typedef struct D_CRITICAL_SECTION
+{
+    struct D_CRITICAL_SECTION *next;
+    pthread_mutex_t cs;
+} D_CRITICAL_SECTION;
+
+static D_CRITICAL_SECTION *dcs_list;
+static D_CRITICAL_SECTION critical_section;
+static pthread_mutexattr_t _criticals_attr;
+
+void _STI_critical_init(void);
+void _STD_critical_term(void);
+
+void _d_criticalenter(D_CRITICAL_SECTION *dcs)
+{
+    if (!dcs_list)
+    {   _STI_critical_init();
+        atexit(_STD_critical_term);
+    }
+    //printf("_d_criticalenter(dcs = x%x)\n", dcs);
+    if (!dcs->next)
+    {
+        pthread_mutex_lock(&critical_section.cs);
+        if (!dcs->next) // if, in the meantime, another thread didn't set it
+        {
+            dcs->next = dcs_list;
+            dcs_list = dcs;
+            pthread_mutex_init(&dcs->cs, &_criticals_attr);
+        }
+        pthread_mutex_unlock(&critical_section.cs);
+    }
+    pthread_mutex_lock(&dcs->cs);
+}
+
+void _d_criticalexit(D_CRITICAL_SECTION *dcs)
+{
+    //printf("_d_criticalexit(dcs = x%x)\n", dcs);
+    pthread_mutex_unlock(&dcs->cs);
+}
+
+void _STI_critical_init()
+{
+    if (!dcs_list)
+    {   //printf("_STI_critical_init()\n");
+        pthread_mutexattr_init(&_criticals_attr);
+        pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE_NP);
+
+        // The global critical section doesn't need to be recursive
+        pthread_mutex_init(&critical_section.cs, 0);
+        dcs_list = &critical_section;
+    }
+}
+
+void _STD_critical_term()
+{
+    if (dcs_list)
+    {   //printf("_STI_critical_term()\n");
+        while (dcs_list)
+        {
+            //printf("\tlooping... %x\n", dcs_list);
+            pthread_mutex_destroy(&dcs_list->cs);
+            dcs_list = dcs_list->next;
+        }
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/deh.c	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,662 @@
+//
+// Copyright (c) 1999-2003 by Digital Mars, www.digitalmars.com
+// All Rights Reserved
+// Written by Walter Bright
+
+// Exception handling support
+
+#include        <stdio.h>
+#include        <string.h>
+#include        <assert.h>
+#include        <stdlib.h>
+
+/* ======================== Win32 =============================== */
+
+#if _WIN32
+
+#include        <excpt.h>
+#include        <windows.h>
+
+//#include      "\sc\src\include\ehsup.h"
+
+/*** From Digital Mars C runtime library ***/
+EXCEPTION_DISPOSITION __cdecl _local_except_handler (EXCEPTION_RECORD *ExceptionRecord,
+    void* EstablisherFrame,
+        void *ContextRecord,
+        void *DispatcherContext
+        );
+void __cdecl _global_unwind(void *frame,EXCEPTION_RECORD *eRecord);
+#define EXCEPTION_UNWIND  6  // Flag to indicate if the system is unwinding
+
+extern DWORD _except_list;
+/*** ***/
+
+#include        "mars.h"
+
+extern ClassInfo D6object9Throwable7__ClassZ;
+#define _Class_9Throwable D6object9Throwable7__ClassZ;
+
+extern ClassInfo D6object5Error7__ClassZ;
+#define _Class_5Error D6object5Error7__ClassZ
+
+typedef int (__pascal *fp_t)();   // function pointer in ambient memory model
+
+// The layout of DEstablisherFrame is the same for C++
+
+struct DEstablisherFrame
+{
+    void *prev;                 // pointer to previous exception list
+    void *handler;              // pointer to routine for exception handler
+    DWORD table_index;          // current index into handler_info[]
+    DWORD ebp;                  // this is EBP of routine
+};
+
+struct DHandlerInfo
+{
+    int prev_index;             // previous table index
+    unsigned cioffset;          // offset to DCatchInfo data from start of table (!=0 if try-catch)
+    void *finally_code;         // pointer to finally code to execute
+                                // (!=0 if try-finally)
+};
+
+// Address of DHandlerTable is passed in EAX to _d_framehandler()
+
+struct DHandlerTable
+{
+    void *fptr;                 // pointer to start of function
+    unsigned espoffset;         // offset of ESP from EBP
+    unsigned retoffset;         // offset from start of function to return code
+    struct DHandlerInfo handler_info[1];
+};
+
+struct DCatchBlock
+{
+    ClassInfo *type;            // catch type
+    unsigned bpoffset;          // EBP offset of catch var
+    void *code;                 // catch handler code
+};
+
+// Create one of these for each try-catch
+struct DCatchInfo
+{
+    unsigned ncatches;                  // number of catch blocks
+    struct DCatchBlock catch_block[1];  // data for each catch block
+};
+
+// Macro to make our own exception code
+#define MAKE_EXCEPTION_CODE(severity, facility, exception)      \
+        (((severity) << 30) | (1 << 29) | (0 << 28) | ((facility) << 16) | (exception))
+
+#define STATUS_DIGITAL_MARS_D_EXCEPTION         MAKE_EXCEPTION_CODE(3,'D',1)
+
+Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record);
+void __cdecl _d_local_unwind(struct DHandlerTable *handler_table, struct DEstablisherFrame *frame, int stop_index);
+
+
+/***********************************
+ * The frame handler, this is called for each frame that has been registered
+ * in the OS except_list.
+ * Input:
+ *      EAX     the handler table for the frame
+ */
+
+EXCEPTION_DISPOSITION _d_framehandler(
+            EXCEPTION_RECORD *exception_record,
+            struct DEstablisherFrame *frame,
+            CONTEXT context,
+            void *dispatcher_context)
+{
+    struct DHandlerTable *handler_table;
+
+    __asm { mov handler_table,EAX }
+
+    if (exception_record->ExceptionFlags & EXCEPTION_UNWIND)
+    {
+         // Call all the finally blocks in this frame
+         _d_local_unwind(handler_table, frame, -1);
+    }
+    else
+    {
+        // Jump to catch block if matching one is found
+
+        int ndx,prev_ndx,i;
+        struct DHandlerInfo *phi;
+        struct DCatchInfo *pci;
+        struct DCatchBlock *pcb;
+        unsigned ncatches;              // number of catches in the current handler
+        Object *pti;
+        ClassInfo *ci;
+
+        ci = NULL;                      // only compute it if we need it
+
+        // walk through handler table, checking each handler
+        // with an index smaller than the current table_index
+        for (ndx = frame->table_index; ndx != -1; ndx = prev_ndx)
+        {
+            phi = &handler_table->handler_info[ndx];
+            prev_ndx = phi->prev_index;
+            if (phi->cioffset)
+            {
+                // this is a catch handler (no finally)
+                pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
+                ncatches = pci->ncatches;
+                for (i = 0; i < ncatches; i++)
+                {
+                    pcb = &pci->catch_block[i];
+
+                    if (!ci)
+                    {
+                        // This code must match the translation code
+                        if (exception_record->ExceptionCode == STATUS_DIGITAL_MARS_D_EXCEPTION)
+                        {
+                            //printf("ei[0] = %p\n", exception_record->ExceptionInformation[0]);
+                            ci = **(ClassInfo ***)(exception_record->ExceptionInformation[0]);
+                        }
+                        else
+                            ci = &_Class_9Throwable;
+                    }
+
+                    if (_d_isbaseof(ci, pcb->type))
+                    {
+                        // Matched the catch type, so we've found the handler.
+                        int regebp;
+
+                        pti = _d_translate_se_to_d_exception(exception_record);
+
+                        // Initialize catch variable
+                        regebp = (int)&frame->ebp;              // EBP for this frame
+                        *(void **)(regebp + (pcb->bpoffset)) = pti;
+
+                        // Have system call all finally blocks in intervening frames
+                        _global_unwind(frame, exception_record);
+
+                        // Call all the finally blocks skipped in this frame
+                        _d_local_unwind(handler_table, frame, ndx);
+
+                        frame->table_index = prev_ndx;  // we are out of this handler
+
+                        // Jump to catch block. Does not return.
+                        {
+                            unsigned catch_esp;
+                            fp_t catch_addr;
+
+                            catch_addr = (fp_t)(pcb->code);
+                            catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
+                            _asm
+                            {
+                                mov     EAX,catch_esp
+                                mov     ECX,catch_addr
+                                mov     [EAX],ECX
+                                mov     EBP,regebp
+                                mov     ESP,EAX         // reset stack
+                                ret                     // jump to catch block
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return ExceptionContinueSearch;
+}
+
+/***********************************
+ * Exception filter for use in __try..__except block
+ * surrounding call to Dmain()
+ */
+
+int _d_exception_filter(struct _EXCEPTION_POINTERS *eptrs,
+                        int retval,
+                        Object **exception_object)
+{
+    *exception_object = _d_translate_se_to_d_exception(eptrs->ExceptionRecord);
+    return retval;
+}
+
+/***********************************
+ * Throw a D object.
+ */
+
+void __stdcall _d_throw(Object *h)
+{
+    //printf("_d_throw(h = %p, &h = %p)\n", h, &h);
+    //printf("\tvptr = %p\n", *(void **)h);
+    RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION,
+                   EXCEPTION_NONCONTINUABLE,
+                   1, (DWORD *)&h);
+}
+
+/***********************************
+ * Create an exception object
+ */
+
+Object *_d_create_exception_object(ClassInfo *ci, char *msg)
+{
+    Throwable *exc;
+
+    exc = (Throwable *)_d_newclass(ci);
+    // BUG: what if _d_newclass() throws an out of memory exception?
+
+    if (msg)
+    {
+        exc->msglen = strlen(msg);
+        exc->msg = msg;
+    }
+    return (Object *)exc;
+}
+
+/***********************************
+ * Converts a Windows Structured Exception code to a D Exception Object.
+ */
+
+Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record)
+{
+    Object *pti;
+
+    switch (exception_record->ExceptionCode) {
+        case STATUS_DIGITAL_MARS_D_EXCEPTION:
+            // Generated D exception
+            pti = (Object *)(exception_record->ExceptionInformation[0]);
+            break;
+
+        case STATUS_INTEGER_DIVIDE_BY_ZERO:
+            pti = _d_create_exception_object(&_Class_5Error, "Integer Divide by Zero");
+            break;
+
+        case STATUS_FLOAT_DIVIDE_BY_ZERO:
+            pti = _d_create_exception_object(&_Class_5Error, "Float Divide by Zero");
+            break;
+
+        case STATUS_ACCESS_VIOLATION:
+            pti = _d_create_exception_object(&_Class_5Error, "Access Violation");
+            break;
+
+        case STATUS_STACK_OVERFLOW:
+            pti = _d_create_exception_object(&_Class_5Error, "Stack Overflow");
+            break;
+
+        // convert all other exception codes into a Win32Exception
+        default:
+            pti = _d_create_exception_object(&_Class_5Error, "Win32 Exception");
+            break;
+    }
+
+    return pti;
+}
+
+/**************************************
+ * Call finally blocks in the current stack frame until stop_index.
+ * This is roughly equivalent to _local_unwind() for C in \src\win32\ehsup.c
+ */
+
+void __cdecl _d_local_unwind(struct DHandlerTable *handler_table,
+        struct DEstablisherFrame *frame, int stop_index)
+{
+    struct DHandlerInfo *phi;
+    struct DCatchInfo *pci;
+    int i;
+
+    // Set up a special exception handler to catch double-fault exceptions.
+    __asm
+    {
+        push    dword ptr -1
+        push    dword ptr 0
+        push    offset _local_except_handler    // defined in src\win32\ehsup.c
+        push    dword ptr fs:_except_list
+        mov     FS:_except_list,ESP
+    }
+
+    for (i = frame->table_index; i != -1 && i != stop_index; i = phi->prev_index)
+    {
+        phi = &handler_table->handler_info[i];
+        if (phi->finally_code)
+        {
+            // Note that it is unnecessary to adjust the ESP, as the finally block
+            // accesses all items on the stack as relative to EBP.
+
+            DWORD *catch_ebp = &frame->ebp;
+            void *blockaddr = phi->finally_code;
+
+            _asm
+            {
+                push    EBX
+                mov     EBX,blockaddr
+                push    EBP
+                mov     EBP,catch_ebp
+                call    EBX
+                pop     EBP
+                pop     EBX
+            }
+        }
+    }
+
+    _asm
+    {
+        pop     FS:_except_list
+        add     ESP,12
+    }
+}
+
+/***********************************
+ * external version of the unwinder
+ */
+
+__declspec(naked) void __cdecl _d_local_unwind2()
+{
+    __asm
+    {
+        jmp     _d_local_unwind
+    }
+}
+
+/***********************************
+ * The frame handler, this is called for each frame that has been registered
+ * in the OS except_list.
+ * Input:
+ *      EAX     the handler table for the frame
+ */
+
+EXCEPTION_DISPOSITION _d_monitor_handler(
+            EXCEPTION_RECORD *exception_record,
+            struct DEstablisherFrame *frame,
+            CONTEXT context,
+            void *dispatcher_context)
+{
+    if (exception_record->ExceptionFlags & EXCEPTION_UNWIND)
+    {
+        _d_monitorexit((Object *)frame->table_index);
+    }
+    else
+    {
+    }
+    return ExceptionContinueSearch;
+}
+
+/***********************************
+ */
+
+void _d_monitor_prolog(void *x, void *y, Object *h)
+{
+    __asm
+    {
+        push    EAX
+    }
+    //printf("_d_monitor_prolog(x=%p, y=%p, h=%p)\n", x, y, h);
+    _d_monitorenter(h);
+    __asm
+    {
+        pop     EAX
+    }
+}
+
+/***********************************
+ */
+
+void _d_monitor_epilog(void *x, void *y, Object *h)
+{
+    //printf("_d_monitor_epilog(x=%p, y=%p, h=%p)\n", x, y, h);
+    __asm
+    {
+        push    EAX
+        push    EDX
+    }
+    _d_monitorexit(h);
+    __asm
+    {
+        pop     EDX
+        pop     EAX
+    }
+}
+
+#endif
+
+/* ======================== linux =============================== */
+
+#if linux
+
+#include        "mars.h"
+
+extern ClassInfo D6object9Throwable7__ClassZ;
+#define _Class_9Throwable D6object9Throwable7__ClassZ;
+
+extern ClassInfo D6object5Error7__ClassZ;
+#define _Class_5Error D6object5Error7__ClassZ
+
+typedef int (*fp_t)();   // function pointer in ambient memory model
+
+struct DHandlerInfo
+{
+    unsigned offset;            // offset from function address to start of guarded section
+    int prev_index;             // previous table index
+    unsigned cioffset;          // offset to DCatchInfo data from start of table (!=0 if try-catch)
+    void *finally_code;         // pointer to finally code to execute
+                                // (!=0 if try-finally)
+};
+
+// Address of DHandlerTable, searched for by eh_finddata()
+
+struct DHandlerTable
+{
+    void *fptr;                 // pointer to start of function
+    unsigned espoffset;         // offset of ESP from EBP
+    unsigned retoffset;         // offset from start of function to return code
+    unsigned nhandlers;         // dimension of handler_info[]
+    struct DHandlerInfo handler_info[1];
+};
+
+struct DCatchBlock
+{
+    ClassInfo *type;            // catch type
+    unsigned bpoffset;          // EBP offset of catch var
+    void *code;                 // catch handler code
+};
+
+// Create one of these for each try-catch
+struct DCatchInfo
+{
+    unsigned ncatches;                  // number of catch blocks
+    struct DCatchBlock catch_block[1];  // data for each catch block
+};
+
+// One of these is generated for each function with try-catch or try-finally
+
+struct FuncTable
+{
+    void *fptr;                 // pointer to start of function
+    struct DHandlerTable *handlertable; // eh data for this function
+    unsigned size;              // size of function in bytes
+};
+
+extern struct FuncTable *table_start;
+extern struct FuncTable *table_end;
+
+void terminate()
+{
+//    _asm
+//    {
+//      hlt
+//    }
+}
+
+/*******************************************
+ * Given address that is inside a function,
+ * figure out which function it is in.
+ * Return DHandlerTable if there is one, NULL if not.
+ */
+
+struct DHandlerTable *__eh_finddata(void *address)
+{
+    struct FuncTable *ft;
+
+    for (ft = (struct FuncTable *)table_start;
+         ft < (struct FuncTable *)table_end;
+         ft++)
+    {
+        if (ft->fptr <= address &&
+            address < (void *)((char *)ft->fptr + ft->size))
+        {
+            return ft->handlertable;
+        }
+    }
+    return NULL;
+}
+
+
+/******************************
+ * Given EBP, find return address to caller, and caller's EBP.
+ * Input:
+ *   regbp       Value of EBP for current function
+ *   *pretaddr   Return address
+ * Output:
+ *   *pretaddr   return address to caller
+ * Returns:
+ *   caller's EBP
+ */
+
+unsigned __eh_find_caller(unsigned regbp, unsigned *pretaddr)
+{
+    unsigned bp = *(unsigned *)regbp;
+
+    if (bp)         // if not end of call chain
+    {
+        // Perform sanity checks on new EBP.
+        // If it is screwed up, terminate() hopefully before we do more damage.
+        if (bp <= regbp)
+            // stack should grow to smaller values
+            terminate();
+
+        *pretaddr = *(unsigned *)(regbp + sizeof(int));
+    }
+    return bp;
+}
+
+/***********************************
+ * Throw a D object.
+ */
+
+void __stdcall _d_throw(Object *h)
+{
+    unsigned regebp;
+
+    //printf("_d_throw(h = %p, &h = %p)\n", h, &h);
+    //printf("\tvptr = %p\n", *(void **)h);
+
+    regebp = _EBP;
+
+    while (1)           // for each function on the stack
+    {
+        struct DHandlerTable *handler_table;
+        struct FuncTable *pfunc;
+        struct DHandlerInfo *phi;
+        unsigned retaddr;
+        unsigned funcoffset;
+        unsigned spoff;
+        unsigned retoffset;
+        int index;
+        int dim;
+        int ndx;
+        int prev_ndx;
+
+        regebp = __eh_find_caller(regebp,&retaddr);
+        if (!regebp)
+            // if end of call chain
+            break;
+
+        handler_table = __eh_finddata((void *)retaddr);   // find static data associated with function
+        if (!handler_table)         // if no static data
+        {
+            continue;
+        }
+        funcoffset = (unsigned)handler_table->fptr;
+        spoff = handler_table->espoffset;
+        retoffset = handler_table->retoffset;
+
+#ifdef DEBUG
+        printf("retaddr = x%x\n",(unsigned)retaddr);
+        printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
+        regebp,funcoffset,spoff,retoffset);
+#endif
+
+        // Find start index for retaddr in static data
+        dim = handler_table->nhandlers;
+        index = -1;
+        for (int i = 0; i < dim; i++)
+        {
+            phi = &handler_table->handler_info[i];
+
+            if ((unsigned)retaddr >= funcoffset + phi->offset)
+                index = i;
+        }
+
+        // walk through handler table, checking each handler
+        // with an index smaller than the current table_index
+        for (ndx = index; ndx != -1; ndx = prev_ndx)
+        {
+            phi = &handler_table->handler_info[ndx];
+            prev_ndx = phi->prev_index;
+            if (phi->cioffset)
+            {
+                // this is a catch handler (no finally)
+                struct DCatchInfo *pci;
+                int ncatches;
+                int i;
+
+                pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
+                ncatches = pci->ncatches;
+                for (i = 0; i < ncatches; i++)
+                {
+                    struct DCatchBlock *pcb;
+                    ClassInfo *ci = **(ClassInfo ***)h;
+
+                    pcb = &pci->catch_block[i];
+
+                    if (_d_isbaseof(ci, pcb->type))
+                    {   // Matched the catch type, so we've found the handler.
+
+                        // Initialize catch variable
+                        *(void **)(regebp + (pcb->bpoffset)) = h;
+
+                        // Jump to catch block. Does not return.
+                        {
+                            unsigned catch_esp;
+                            fp_t catch_addr;
+
+                            catch_addr = (fp_t)(pcb->code);
+                            catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
+                            _asm
+                            {
+                                mov     EAX,catch_esp
+                                mov     ECX,catch_addr
+                                mov     [EAX],ECX
+                                mov     EBP,regebp
+                                mov     ESP,EAX         // reset stack
+                                ret                     // jump to catch block
+                            }
+                        }
+                    }
+                }
+            }
+            else if (phi->finally_code)
+            {   // Call finally block
+                // Note that it is unnecessary to adjust the ESP, as the finally block
+                // accesses all items on the stack as relative to EBP.
+
+                void *blockaddr = phi->finally_code;
+
+                _asm
+                {
+                    push        EBX
+                    mov         EBX,blockaddr
+                    push        EBP
+                    mov         EBP,regebp
+                    call        EBX
+                    pop         EBP
+                    pop         EBX
+                }
+            }
+        }
+    }
+}
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/deh2.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,308 @@
+/*
+ *  Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.deh2;
+
+// Exception handling support for linux
+
+//debug=1;
+
+extern (C)
+{
+    extern void* _deh_beg;
+    extern void* _deh_end;
+
+    int _d_isbaseof(ClassInfo oc, ClassInfo c);
+}
+
+alias int (*fp_t)();   // function pointer in ambient memory model
+
+struct DHandlerInfo
+{
+    uint offset;                // offset from function address to start of guarded section
+    uint endoffset;             // offset of end of guarded section
+    int prev_index;             // previous table index
+    uint cioffset;              // offset to DCatchInfo data from start of table (!=0 if try-catch)
+    void *finally_code;         // pointer to finally code to execute
+                                // (!=0 if try-finally)
+}
+
+// Address of DHandlerTable, searched for by eh_finddata()
+
+struct DHandlerTable
+{
+    void *fptr;                 // pointer to start of function
+    uint espoffset;             // offset of ESP from EBP
+    uint retoffset;             // offset from start of function to return code
+    uint nhandlers;             // dimension of handler_info[]
+    DHandlerInfo handler_info[1];
+}
+
+struct DCatchBlock
+{
+    ClassInfo type;             // catch type
+    uint bpoffset;              // EBP offset of catch var
+    void *code;                 // catch handler code
+}
+
+// Create one of these for each try-catch
+struct DCatchInfo
+{
+    uint ncatches;                      // number of catch blocks
+    DCatchBlock catch_block[1];         // data for each catch block
+}
+
+// One of these is generated for each function with try-catch or try-finally
+
+struct FuncTable
+{
+    void *fptr;                 // pointer to start of function
+    DHandlerTable *handlertable; // eh data for this function
+    uint fsize;         // size of function in bytes
+}
+
+void terminate()
+{
+    asm
+    {
+        hlt ;
+    }
+}
+
+/*******************************************
+ * Given address that is inside a function,
+ * figure out which function it is in.
+ * Return DHandlerTable if there is one, NULL if not.
+ */
+
+DHandlerTable *__eh_finddata(void *address)
+{
+    FuncTable *ft;
+
+//    debug printf("__eh_finddata(address = x%x)\n", address);
+//    debug printf("_deh_beg = x%x, _deh_end = x%x\n", &_deh_beg, &_deh_end);
+    for (ft = cast(FuncTable *)&_deh_beg;
+         ft < cast(FuncTable *)&_deh_end;
+         ft++)
+    {
+//      debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n",
+//              ft.fptr, ft.fsize, ft.handlertable);
+
+        if (ft.fptr <= address &&
+            address < cast(void *)(cast(char *)ft.fptr + ft.fsize))
+        {
+//          debug printf("\tfound handler table\n");
+            return ft.handlertable;
+        }
+    }
+//    debug printf("\tnot found\n");
+    return null;
+}
+
+
+/******************************
+ * Given EBP, find return address to caller, and caller's EBP.
+ * Input:
+ *   regbp       Value of EBP for current function
+ *   *pretaddr   Return address
+ * Output:
+ *   *pretaddr   return address to caller
+ * Returns:
+ *   caller's EBP
+ */
+
+uint __eh_find_caller(uint regbp, uint *pretaddr)
+{
+    uint bp = *cast(uint *)regbp;
+
+    if (bp)         // if not end of call chain
+    {
+        // Perform sanity checks on new EBP.
+        // If it is screwed up, terminate() hopefully before we do more damage.
+        if (bp <= regbp)
+            // stack should grow to smaller values
+            terminate();
+
+        *pretaddr = *cast(uint *)(regbp + int.sizeof);
+    }
+    return bp;
+}
+
+/***********************************
+ * Throw a D object.
+ */
+
+extern (Windows) void _d_throw(Object *h)
+{
+    uint regebp;
+
+    debug
+    {
+        printf("_d_throw(h = %p, &h = %p)\n", h, &h);
+        printf("\tvptr = %p\n", *cast(void **)h);
+    }
+
+    asm
+    {
+        mov regebp,EBP  ;
+    }
+
+//static uint abc;
+//if (++abc == 2) *(char *)0=0;
+
+//int count = 0;
+    while (1)           // for each function on the stack
+    {
+        DHandlerTable *handler_table;
+        FuncTable *pfunc;
+        DHandlerInfo *phi;
+        uint retaddr;
+        uint funcoffset;
+        uint spoff;
+        uint retoffset;
+        int index;
+        int dim;
+        int ndx;
+        int prev_ndx;
+
+        regebp = __eh_find_caller(regebp,&retaddr);
+        if (!regebp)
+        {   // if end of call chain
+            debug printf("end of call chain\n");
+            break;
+        }
+
+        debug printf("found caller, EBP = x%x, retaddr = x%x\n", regebp, retaddr);
+//if (++count == 12) *(char*)0=0;
+        handler_table = __eh_finddata(cast(void *)retaddr);   // find static data associated with function
+        if (!handler_table)         // if no static data
+        {
+            debug printf("no handler table\n");
+            continue;
+        }
+        funcoffset = cast(uint)handler_table.fptr;
+        spoff = handler_table.espoffset;
+        retoffset = handler_table.retoffset;
+
+        debug
+        {
+            printf("retaddr = x%x\n",cast(uint)retaddr);
+            printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
+            regebp,funcoffset,spoff,retoffset);
+        }
+
+        // Find start index for retaddr in static data
+        dim = handler_table.nhandlers;
+
+        debug
+        {
+            printf("handler_info[]:\n");
+            for (int i = 0; i < dim; i++)
+            {
+                phi = &handler_table.handler_info[i];
+                printf("\t[%d]: offset = x%04x, endoffset = x%04x, prev_index = %d, cioffset = x%04x, finally_code = %x\n",
+                        i, phi.offset, phi.endoffset, phi.prev_index, phi.cioffset, phi.finally_code);
+            }
+        }
+
+        index = -1;
+        for (int i = 0; i < dim; i++)
+        {
+            phi = &handler_table.handler_info[i];
+
+            debug printf("i = %d, phi.offset = %04x\n", i, funcoffset + phi.offset);
+            if (cast(uint)retaddr > funcoffset + phi.offset &&
+                cast(uint)retaddr <= funcoffset + phi.endoffset)
+                index = i;
+        }
+        debug printf("index = %d\n", index);
+
+        // walk through handler table, checking each handler
+        // with an index smaller than the current table_index
+        for (ndx = index; ndx != -1; ndx = prev_ndx)
+        {
+            phi = &handler_table.handler_info[ndx];
+            prev_ndx = phi.prev_index;
+            if (phi.cioffset)
+            {
+                // this is a catch handler (no finally)
+                DCatchInfo *pci;
+                int ncatches;
+                int i;
+
+                pci = cast(DCatchInfo *)(cast(char *)handler_table + phi.cioffset);
+                ncatches = pci.ncatches;
+                for (i = 0; i < ncatches; i++)
+                {
+                    DCatchBlock *pcb;
+                    ClassInfo ci = **cast(ClassInfo **)h;
+
+                    pcb = &pci.catch_block[i];
+
+                    if (_d_isbaseof(ci, pcb.type))
+                    {   // Matched the catch type, so we've found the handler.
+
+                        // Initialize catch variable
+                        *cast(void **)(regebp + (pcb.bpoffset)) = h;
+
+                        // Jump to catch block. Does not return.
+                        {
+                            uint catch_esp;
+                            fp_t catch_addr;
+
+                            catch_addr = cast(fp_t)(pcb.code);
+                            catch_esp = regebp - handler_table.espoffset - fp_t.sizeof;
+                            asm
+                            {
+                                mov     EAX,catch_esp   ;
+                                mov     ECX,catch_addr  ;
+                                mov     [EAX],ECX       ;
+                                mov     EBP,regebp      ;
+                                mov     ESP,EAX         ; // reset stack
+                                ret                     ; // jump to catch block
+                            }
+                        }
+                    }
+                }
+            }
+            else if (phi.finally_code)
+            {   // Call finally block
+                // Note that it is unnecessary to adjust the ESP, as the finally block
+                // accesses all items on the stack as relative to EBP.
+
+                void *blockaddr = phi.finally_code;
+
+                asm
+                {
+                    push        EBX             ;
+                    mov         EBX,blockaddr   ;
+                    push        EBP             ;
+                    mov         EBP,regebp      ;
+                    call        EBX             ;
+                    pop         EBP             ;
+                    pop         EBX             ;
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/dmain2.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,315 @@
+/*
+ * Placed into the Public Domain.
+ * written by Walter Bright
+ * www.digitalmars.com
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.dmain2;
+
+private
+{
+    import util.console;
+    import stdc.stddef;
+    import stdc.stdlib;
+    import stdc.string;
+}
+
+version(Windows)
+{
+    extern (Windows) void*      LocalFree(void*);
+    extern (Windows) wchar_t*   GetCommandLineW();
+    extern (Windows) wchar_t**  CommandLineToArgvW(wchar_t*, int*);
+    extern (Windows) export int WideCharToMultiByte(uint, uint, wchar_t*, int, char*, int, char*, int);
+    pragma(lib, "shell32.lib");   // needed for CommandLineToArgvW
+}
+
+extern (C) void _STI_monitor_staticctor();
+extern (C) void _STD_monitor_staticdtor();
+extern (C) void _STI_critical_init();
+extern (C) void _STD_critical_term();
+extern (C) void gc_init();
+extern (C) void gc_term();
+extern (C) void _minit();
+extern (C) void _moduleCtor();
+extern (C) void _moduleDtor();
+extern (C) void thread_joinAll();
+
+/***********************************
+ * These functions must be defined for any D program linked
+ * against this library.
+ */
+extern (C) void onAssertError(string file, size_t line);
+extern (C) void onAssertErrorMsg(string file, size_t line, string msg);
+extern (C) void onArrayBoundsError(string file, size_t line);
+extern (C) void onHiddenFuncError(Object o);
+extern (C) void onSwitchError(string file, size_t line);
+extern (C) bool runModuleUnitTests();
+
+// this function is called from the utf module
+//extern (C) void onUnicodeError(string msg, size_t idx);
+
+/***********************************
+ * These are internal callbacks for various language errors.
+ */
+extern (C) void _d_assert(string file, uint line)
+{
+    onAssertError(file, line);
+}
+
+extern (C) static void _d_assert_msg(string msg, string file, uint line)
+{
+    onAssertErrorMsg(file, line, msg);
+}
+
+extern (C) void _d_array_bounds(string file, uint line)
+{
+    onArrayBoundsError(file, line);
+}
+
+extern (C) void _d_switch_error(string file, uint line)
+{
+    onSwitchError(file, line);
+}
+
+extern (C) void _d_hidden_func()
+{
+    Object o;
+    asm
+    {
+        mov o, EAX;
+    }
+    onHiddenFuncError(o);
+}
+
+bool _d_isHalting = false;
+
+extern (C) bool rt_isHalting()
+{
+    return _d_isHalting;
+}
+
+extern (C) bool rt_trapExceptions = true;
+
+void _d_criticalInit()
+{
+    version (linux)
+    {
+        _STI_monitor_staticctor();
+        _STI_critical_init();
+    }
+}
+
+alias void delegate(Throwable) ExceptionHandler;
+
+extern (C) bool rt_init(ExceptionHandler dg = null)
+{
+    _d_criticalInit();
+
+    try
+    {
+        gc_init();
+        version (Windows)
+            _minit();
+        _moduleCtor();
+        return true;
+    }
+    catch (Throwable e)
+    {
+        if (dg)
+            dg(e);
+    }
+    catch
+    {
+
+    }
+    _d_criticalTerm();
+    return false;
+}
+
+void _d_criticalTerm()
+{
+    version (linux)
+    {
+        _STD_critical_term();
+        _STD_monitor_staticdtor();
+    }
+}
+
+extern (C) bool rt_term(ExceptionHandler dg = null)
+{
+    try
+    {
+        thread_joinAll();
+        _d_isHalting = true;
+        _moduleDtor();
+        gc_term();
+        return true;
+    }
+    catch (Throwable e)
+    {
+        if (dg)
+            dg(e);
+    }
+    catch
+    {
+
+    }
+    finally
+    {
+        _d_criticalTerm();
+    }
+    return false;
+}
+
+/***********************************
+ * The D main() function supplied by the user's program
+ */
+int main(char[][] args);
+
+/***********************************
+ * Substitutes for the C main() function.
+ * It's purpose is to wrap the call to the D main()
+ * function and catch any unhandled exceptions.
+ */
+
+extern (C) int main(int argc, char **argv)
+{
+    char[][] args;
+    int result;
+
+    version (linux)
+    {
+        _STI_monitor_staticctor();
+        _STI_critical_init();
+    }
+
+    version (Windows)
+    {
+        wchar_t*  wcbuf = GetCommandLineW();
+        size_t    wclen = wcslen(wcbuf);
+        int       wargc = 0;
+        wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc);
+        assert(wargc == argc);
+
+        char*     cargp = null;
+        size_t    cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0);
+
+        cargp = cast(char*) alloca(cargl);
+        args  = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc];
+
+        for (size_t i = 0, p = 0; i < wargc; i++)
+        {
+            int wlen = wcslen(wargs[i]);
+            int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0);
+            args[i]  = cargp[p .. p+clen];
+            p += clen; assert(p <= cargl);
+            WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0);
+        }
+        LocalFree(wargs);
+        wargs = null;
+        wargc = 0;
+    }
+    else version (linux)
+    {
+        char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof);
+        scope(exit) free(am);
+
+        for (size_t i = 0; i < argc; i++)
+        {
+            auto len = strlen(argv[i]);
+            am[i] = argv[i][0 .. len];
+        }
+        args = am[0 .. argc];
+    }
+
+    bool trapExceptions = rt_trapExceptions;
+
+    void tryExec(void delegate() dg)
+    {
+
+        if (trapExceptions)
+        {
+            try
+            {
+                dg();
+            }
+            catch (Throwable e)
+            {
+                while (e)
+                {
+                    if (e.file)
+                    {
+                        // fprintf(stderr, "%.*s(%u): %.*s\n", e.file, e.line, e.msg);
+                        console (e.classinfo.name)("@")(e.file)("(")(e.line)("): ")(e.msg)("\n");
+                    }
+                    else
+                    {
+                        // fprintf(stderr, "%.*s\n", e.toString());
+                        console (e.toString)("\n");
+                    }
+                    if (e.info)
+                    {
+                        console ("----------------\n");
+                        foreach (t; e.info)
+                            console (t)("\n");
+                    }
+                    if (e.next)
+                        console ("\n");
+                    e = e.next;
+                }
+                result = EXIT_FAILURE;
+            }
+            catch (Object o)
+            {
+                // fprintf(stderr, "%.*s\n", o.toString());
+                console (o.toString)("\n");
+                result = EXIT_FAILURE;
+            }
+        }
+        else
+        {
+            dg();
+        }
+    }
+
+    // NOTE: The lifetime of a process is much like the lifetime of an object:
+    //       it is initialized, then used, then destroyed.  If initialization
+    //       fails, the successive two steps are never reached.  However, if
+    //       initialization succeeds, then cleanup will occur even if the use
+    //       step fails in some way.  Here, the use phase consists of running
+    //       the user's main function.  If main terminates with an exception,
+    //       the exception is handled and then cleanup begins.  An exception
+    //       thrown during cleanup, however, will abort the cleanup process.
+
+    void runMain()
+    {
+        result = main(args);
+    }
+
+    void runAll()
+    {
+        gc_init();
+        version (Windows)
+            _minit();
+        _moduleCtor();
+        if (runModuleUnitTests())
+            tryExec(&runMain);
+        thread_joinAll();
+        _d_isHalting = true;
+        _moduleDtor();
+        gc_term();
+    }
+
+    tryExec(&runAll);
+
+    version (linux)
+    {
+        _STD_critical_term();
+        _STD_monitor_staticdtor();
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/invariant.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,24 @@
+/*
+ * Placed into the Public Domain
+ * written by Walter Bright
+ * www.digitalmars.com
+ */
+
+void _d_invariant(Object o)
+{   ClassInfo c;
+
+    //printf("__d_invariant(%p)\n", o);
+
+    // BUG: needs to be filename/line of caller, not library routine
+    assert(o !is null); // just do null check, not invariant check
+
+    c = o.classinfo;
+    do
+    {
+        if (c.classInvariant)
+        {
+            (*c.classInvariant)(o);
+        }
+        c = c.base;
+    } while (c);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/invariant_.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,25 @@
+/*
+ * Placed into the Public Domain
+ * written by Walter Bright
+ * www.digitalmars.com
+ */
+module rt.invariant_;
+
+extern (C) void _d_invariant(Object o)
+{   ClassInfo c;
+
+    //printf("__d_invariant(%p)\n", o);
+
+    // BUG: needs to be filename/line of caller, not library routine
+    assert(o !is null); // just do null check, not invariant check
+
+    c = o.classinfo;
+    do
+    {
+        if (c.classInvariant)
+        {
+            (*c.classInvariant)(o);
+        }
+        c = c.base;
+    } while (c);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/lifetime.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,1081 @@
+/**
+ * This module contains all functions related to an object's lifetime:
+ * allocation, resizing, deallocation, and finalization.
+ *
+ * Copyright: Copyright (C) 2004-2007 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, Sean Kelly
+ */
+module rt.lifetime;
+
+
+private
+{
+    import stdc.stdlib;
+    import stdc.string;
+    import stdc.stdarg;
+    debug(PRINTF) import stdc.stdio;
+}
+
+
+private
+{
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    struct BlkInfo
+    {
+        void*  base;
+        size_t size;
+        uint   attr;
+    }
+
+    extern (C) uint gc_getAttr( void* p );
+    extern (C) uint gc_setAttr( void* p, uint a );
+    extern (C) uint gc_clrAttr( void* p, uint a );
+
+    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
+    extern (C) void   gc_free( void* p );
+
+    extern (C) void*   gc_addrOf( void* p );
+    extern (C) size_t  gc_sizeOf( void* p );
+    extern (C) BlkInfo gc_query( void* p );
+
+    extern (C) void onFinalizeError( ClassInfo c, Throwable e );
+    extern (C) void onOutOfMemoryError();
+
+    extern (C) void _d_monitordelete(Object h, bool det = true);
+
+    enum
+    {
+        PAGESIZE = 4096
+    }
+
+    alias bool function(Object) CollectHandler;
+    CollectHandler collectHandler = null;
+}
+
+
+/**
+ *
+ */
+extern (C) void* _d_allocmemory(size_t sz)
+{
+    return gc_malloc(sz);
+}
+
+
+/**
+ *
+ */
+extern (C) Object _d_newclass(ClassInfo ci)
+{
+    void* p;
+
+    debug(PRINTF) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name);
+    if (ci.flags & 1) // if COM object
+    {   /* COM objects are not garbage collected, they are reference counted
+         * using AddRef() and Release().  They get free'd by C's free()
+         * function called by Release() when Release()'s reference count goes
+         * to zero.
+     */
+        p = malloc(ci.init.length);
+        if (!p)
+            onOutOfMemoryError();
+    }
+    else
+    {
+        p = gc_malloc(ci.init.length,
+                      BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0));
+        debug(PRINTF) printf(" p = %p\n", p);
+    }
+
+    debug(PRINTF)
+    {
+        printf("p = %p\n", p);
+        printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length);
+        printf("vptr = %p\n", *cast(void**) ci.init);
+        printf("vtbl[0] = %p\n", (*cast(void***) ci.init)[0]);
+        printf("vtbl[1] = %p\n", (*cast(void***) ci.init)[1]);
+        printf("init[0] = %x\n", (cast(uint*) ci.init)[0]);
+        printf("init[1] = %x\n", (cast(uint*) ci.init)[1]);
+        printf("init[2] = %x\n", (cast(uint*) ci.init)[2]);
+        printf("init[3] = %x\n", (cast(uint*) ci.init)[3]);
+        printf("init[4] = %x\n", (cast(uint*) ci.init)[4]);
+    }
+
+    // initialize it
+    (cast(byte*) p)[0 .. ci.init.length] = ci.init[];
+
+    debug(PRINTF) printf("initialization done\n");
+    return cast(Object) p;
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_delinterface(void** p)
+{
+    if (*p)
+    {
+        Interface* pi = **cast(Interface ***)*p;
+        Object     o  = cast(Object)(*p - pi.offset);
+
+        _d_delclass(&o);
+        *p = null;
+    }
+}
+
+
+// used for deletion
+private extern (D) alias void (*fp_t)(Object);
+
+
+/**
+ *
+ */
+extern (C) void _d_delclass(Object* p)
+{
+    if (*p)
+    {
+        debug(PRINTF) printf("_d_delclass(%p)\n", *p);
+
+        ClassInfo **pc = cast(ClassInfo **)*p;
+        if (*pc)
+        {
+            ClassInfo c = **pc;
+
+            rt_finalize(cast(void*) *p);
+
+            if (c.deallocator)
+            {
+                fp_t fp = cast(fp_t)c.deallocator;
+                (*fp)(*p); // call deallocator
+                *p = null;
+                return;
+            }
+        }
+        else
+        {
+            rt_finalize(cast(void*) *p);
+        }
+        gc_free(cast(void*) *p);
+        *p = null;
+    }
+}
+
+
+/**
+ * Allocate a new array of length elements.
+ * ti is the type of the resulting array, or pointer to element.
+ * (For when the array is initialized to 0)
+ */
+extern (C) ulong _d_newarrayT(TypeInfo ti, size_t length)
+{
+    void* p;
+    ulong result;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size);
+    if (length == 0 || size == 0)
+        result = 0;
+    else
+    {
+        version (D_InlineAsm_X86)
+        {
+            asm
+            {
+                mov     EAX,size        ;
+                mul     EAX,length      ;
+                mov     size,EAX        ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+            size *= length;
+        p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        debug(PRINTF) printf(" p = %p\n", p);
+        memset(p, 0, size);
+        result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
+    }
+    return result;
+
+Loverflow:
+    onOutOfMemoryError();
+}
+
+/**
+ * For when the array has a non-zero initializer.
+ */
+extern (C) ulong _d_newarrayiT(TypeInfo ti, size_t length)
+{
+    ulong result;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayiT(length = %d, size = %d)\n", length, size);
+
+    if (length == 0 || size == 0)
+        result = 0;
+    else
+    {
+        auto initializer = ti.next.init();
+        auto isize = initializer.length;
+        auto q = initializer.ptr;
+        version (D_InlineAsm_X86)
+        {
+            asm
+            {
+                mov     EAX,size        ;
+                mul     EAX,length      ;
+                mov     size,EAX        ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+            size *= length;
+        auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        debug(PRINTF) printf(" p = %p\n", p);
+        if (isize == 1)
+            memset(p, *cast(ubyte*)q, size);
+        else if (isize == int.sizeof)
+        {
+            int init = *cast(int*)q;
+            size /= int.sizeof;
+            for (size_t u = 0; u < size; u++)
+            {
+                (cast(int*)p)[u] = init;
+            }
+        }
+        else
+        {
+            for (size_t u = 0; u < size; u += isize)
+            {
+                memcpy(p + u, q, isize);
+            }
+        }
+        va_end(q);
+        result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
+    }
+    return result;
+
+Loverflow:
+    onOutOfMemoryError();
+}
+
+/**
+ *
+ */
+extern (C) ulong _d_newarraymT(TypeInfo ti, int ndims, ...)
+{
+    ulong result;
+
+    debug(PRINTF) printf("_d_newarraymT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = 0;
+    else
+    {   va_list q;
+        va_start!(int)(q, ndims);
+
+        void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayT(ti, dim);
+                p = *cast(void[]*)(&r);
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        size_t* pdim = cast(size_t *)q;
+        result = cast(ulong)foo(ti, pdim, ndims);
+        debug(PRINTF) printf("result = %llx\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, va_arg!(int)(q));
+            }
+        }
+        va_end(q);
+    }
+    return result;
+}
+
+
+/**
+ *
+ */
+extern (C) ulong _d_newarraymiT(TypeInfo ti, int ndims, ...)
+{
+    ulong result;
+
+    debug(PRINTF) printf("_d_newarraymiT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = 0;
+    else
+    {
+        va_list q;
+        va_start!(int)(q, ndims);
+
+        void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayiT(ti, dim);
+                p = *cast(void[]*)(&r);
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        size_t* pdim = cast(size_t *)q;
+        result = cast(ulong)foo(ti, pdim, ndims);
+        debug(PRINTF) printf("result = %llx\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, va_arg!(int)(q));
+                printf("init = %d\n", va_arg!(int)(q));
+            }
+        }
+        va_end(q);
+    }
+    return result;
+}
+
+
+/**
+ *
+ */
+struct Array
+{
+    size_t length;
+    byte*  data;
+}
+
+
+/**
+ * This function has been replaced by _d_delarray_t
+ */
+extern (C) void _d_delarray(Array *p)
+{
+    if (p)
+    {
+        assert(!p.length || p.data);
+
+        if (p.data)
+            gc_free(p.data);
+        p.data = null;
+        p.length = 0;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_delarray_t(Array *p, TypeInfo ti)
+{
+    if (p)
+    {
+        assert(!p.length || p.data);
+        if (p.data)
+        {
+            if (ti)
+            {
+                // Call destructors on all the sub-objects
+                auto sz = ti.tsize();
+                auto pe = p.data;
+                auto pend = pe + p.length * sz;
+                while (pe != pend)
+                {
+                    pend -= sz;
+                    ti.destroy(pend);
+                }
+            }
+            gc_free(p.data);
+        }
+        p.data = null;
+        p.length = 0;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_delmemory(void* *p)
+{
+    if (*p)
+    {
+        gc_free(*p);
+        *p = null;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_callinterfacefinalizer(void *p)
+{
+    if (p)
+    {
+        Interface *pi = **cast(Interface ***)p;
+        Object o = cast(Object)(p - pi.offset);
+        rt_finalize(cast(void*)o);
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_callfinalizer(void* p)
+{
+    rt_finalize( p );
+}
+
+
+/**
+ *
+ */
+extern (C) void  rt_setCollectHandler(CollectHandler h)
+{
+    collectHandler = h;
+}
+
+
+/**
+ *
+ */
+extern (C) void rt_finalize(void* p, bool det = true)
+{
+    debug(PRINTF) printf("rt_finalize(p = %p)\n", p);
+
+    if (p) // not necessary if called from gc
+    {
+        ClassInfo** pc = cast(ClassInfo**)p;
+
+        if (*pc)
+        {
+            ClassInfo c = **pc;
+
+            try
+            {
+                if (det || collectHandler is null || collectHandler(cast(Object)p))
+                {
+                    do
+                    {
+                        if (c.destructor)
+                        {
+                            fp_t fp = cast(fp_t)c.destructor;
+                            (*fp)(cast(Object)p); // call destructor
+                        }
+                        c = c.base;
+                    } while (c);
+                }
+                if ((cast(void**)p)[1]) // if monitor is not null
+                    _d_monitordelete(cast(Object)p, det);
+            }
+            catch (Throwable e)
+            {
+                onFinalizeError(**pc, e);
+            }
+            finally
+            {
+                *pc = null; // zero vptr
+            }
+        }
+    }
+}
+
+
+/**
+ * Resize dynamic arrays with 0 initializers.
+ */
+extern (C) byte[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, Array *p)
+in
+{
+    assert(ti);
+    assert(!p.length || p.data);
+}
+body
+{
+    byte* newdata;
+    size_t sizeelem = ti.next.tsize();
+
+    debug(PRINTF)
+    {
+        printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
+        if (p)
+            printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
+    }
+
+    if (newlength)
+    {
+        version (D_InlineAsm_X86)
+        {
+            size_t newsize = void;
+
+            asm
+            {
+                mov EAX, newlength;
+                mul EAX, sizeelem;
+                mov newsize, EAX;
+                jc  Loverflow;
+            }
+        }
+        else
+        {
+            size_t newsize = sizeelem * newlength;
+
+            if (newsize / newlength != sizeelem)
+                goto Loverflow;
+        }
+
+        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+        if (p.data)
+        {
+            newdata = p.data;
+            if (newlength > p.length)
+            {
+                size_t size = p.length * sizeelem;
+                auto   info = gc_query(p.data);
+
+                if (info.size <= newsize || info.base != p.data)
+                {
+                    if (info.size >= PAGESIZE && info.base == p.data)
+                    {   // Try to extend in-place
+                        auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+                        if (u)
+                        {
+                            goto L1;
+                        }
+                    }
+                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
+                    newdata[0 .. size] = p.data[0 .. size];
+                }
+             L1:
+                newdata[size .. newsize] = 0;
+            }
+        }
+        else
+        {
+            newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        }
+    }
+    else
+    {
+        newdata = p.data;
+    }
+
+    p.data = newdata;
+    p.length = newlength;
+    return newdata[0 .. newlength];
+
+Loverflow:
+    onOutOfMemoryError();
+}
+
+
+/**
+ * Resize arrays for non-zero initializers.
+ *      p               pointer to array lvalue to be updated
+ *      newlength       new .length property of array
+ *      sizeelem        size of each element of array
+ *      initsize        size of initializer
+ *      ...             initializer
+ */
+extern (C) byte[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, Array *p)
+in
+{
+    assert(!p.length || p.data);
+}
+body
+{
+    byte* newdata;
+    size_t sizeelem = ti.next.tsize();
+    void[] initializer = ti.next.init();
+    size_t initsize = initializer.length;
+
+    assert(sizeelem);
+    assert(initsize);
+    assert(initsize <= sizeelem);
+    assert((sizeelem / initsize) * initsize == sizeelem);
+
+    debug(PRINTF)
+    {
+        printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize);
+        if (p)
+            printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
+    }
+
+    if (newlength)
+    {
+        version (D_InlineAsm_X86)
+        {
+            size_t newsize = void;
+
+            asm
+            {
+                mov     EAX,newlength   ;
+                mul     EAX,sizeelem    ;
+                mov     newsize,EAX     ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+        {
+            size_t newsize = sizeelem * newlength;
+
+            if (newsize / newlength != sizeelem)
+                goto Loverflow;
+        }
+        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+        size_t size = p.length * sizeelem;
+
+        if (p.data)
+        {
+            newdata = p.data;
+            if (newlength > p.length)
+            {
+                auto info = gc_query(p.data);
+
+                if (info.size <= newsize || info.base != p.data)
+                {
+                    if (info.size >= PAGESIZE && info.base == p.data)
+                    {   // Try to extend in-place
+                        auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+                        if (u)
+                        {
+                            goto L1;
+                        }
+                    }
+                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
+                    newdata[0 .. size] = p.data[0 .. size];
+                L1: ;
+                }
+            }
+        }
+        else
+        {
+            newdata = cast(byte *)gc_malloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        }
+
+        auto q = initializer.ptr; // pointer to initializer
+
+        if (newsize > size)
+        {
+            if (initsize == 1)
+            {
+                debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q);
+                newdata[size .. newsize] = *(cast(byte*)q);
+            }
+            else
+            {
+                for (size_t u = size; u < newsize; u += initsize)
+                {
+                    memcpy(newdata + u, q, initsize);
+                }
+            }
+        }
+    }
+    else
+    {
+        newdata = p.data;
+    }
+
+    p.data = newdata;
+    p.length = newlength;
+    return newdata[0 .. newlength];
+
+Loverflow:
+    onOutOfMemoryError();
+}
+
+
+/**
+ * Append y[] to array x[].
+ * size is size of each array element.
+ */
+extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    auto info = gc_query(px.data);
+    auto length = px.length;
+    auto newlength = length + y.length;
+    auto newsize = newlength * sizeelem;
+
+    if (info.size < newsize || info.base != px.data)
+    {   byte* newdata;
+
+        if (info.size >= PAGESIZE && info.base == px.data)
+        {   // Try to extend in-place
+            auto u = gc_extend(px.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+            if (u)
+            {
+                goto L1;
+            }
+        }
+        newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr);
+        memcpy(newdata, px.data, length * sizeelem);
+        px.data = newdata;
+    }
+  L1:
+    px.length = newlength;
+    memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem);
+    return *cast(long*)px;
+}
+
+
+/**
+ *
+ */
+size_t newCapacity(size_t newlength, size_t size)
+{
+    version(none)
+    {
+        size_t newcap = newlength * size;
+    }
+    else
+    {
+        /*
+         * Better version by Dave Fladebo:
+         * This uses an inverse logorithmic algorithm to pre-allocate a bit more
+         * space for larger arrays.
+         * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most
+         * common cases, memory allocation is 1 to 1. The small overhead added
+         * doesn't affect small array perf. (it's virtually the same as
+         * current).
+         * - Larger arrays have some space pre-allocated.
+         * - As the arrays grow, the relative pre-allocated space shrinks.
+         * - The logorithmic algorithm allocates relatively more space for
+         * mid-size arrays, making it very fast for medium arrays (for
+         * mid-to-large arrays, this turns out to be quite a bit faster than the
+         * equivalent realloc() code in C, on Linux at least. Small arrays are
+         * just as fast as GCC).
+         * - Perhaps most importantly, overall memory usage and stress on the GC
+         * is decreased significantly for demanding environments.
+         */
+        size_t newcap = newlength * size;
+        size_t newext = 0;
+
+        if (newcap > PAGESIZE)
+        {
+            //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0)));
+
+            // redo above line using only integer math
+
+            static int log2plus1(size_t c)
+            {   int i;
+
+                if (c == 0)
+                    i = -1;
+                else
+                    for (i = 1; c >>= 1; i++)
+                    {
+                    }
+                return i;
+            }
+
+            /* The following setting for mult sets how much bigger
+             * the new size will be over what is actually needed.
+             * 100 means the same size, more means proportionally more.
+             * More means faster but more memory consumption.
+             */
+            //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap));
+            long mult = 100 + (1000L * size) / log2plus1(newcap);
+
+            // testing shows 1.02 for large arrays is about the point of diminishing return
+            if (mult < 102)
+                mult = 102;
+            newext = cast(size_t)((newcap * mult) / 100);
+            newext -= newext % size;
+            debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size);
+        }
+        newcap = newext > newcap ? newext : newcap;
+        debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
+    }
+    return newcap;
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arrayappendcT(TypeInfo ti, inout byte[] x, ...)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    auto info = gc_query(x.ptr);
+    auto length = x.length;
+    auto newlength = length + 1;
+    auto newsize = newlength * sizeelem;
+
+    assert(info.size == 0 || length * sizeelem <= info.size);
+
+    debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size);
+
+    if (info.size <= newsize || info.base != x.ptr)
+    {   byte* newdata;
+
+        if (info.size >= PAGESIZE && info.base == x.ptr)
+        {   // Try to extend in-place
+            auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size);
+            if (u)
+            {
+                goto L1;
+            }
+        }
+        debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size);
+        auto newcap = newCapacity(newlength, sizeelem);
+        assert(newcap >= newlength * sizeelem);
+        newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
+        memcpy(newdata, x.ptr, length * sizeelem);
+        (cast(void**)(&x))[1] = newdata;
+    }
+  L1:
+    byte *argp = cast(byte *)(&ti + 2);
+
+    *cast(size_t *)&x = newlength;
+    x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
+    assert((cast(size_t)x.ptr & 15) == 0);
+    assert(gc_sizeOf(x.ptr) > x.length * sizeelem);
+    return x;
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr);
+    assert(result.length == x.length + y.length);
+    for (size_t i = 0; i < x.length * sizeelem; i++)
+        assert((cast(byte*)result)[i] == (cast(byte*)x)[i]);
+    for (size_t i = 0; i < y.length * sizeelem; i++)
+        assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]);
+
+    size_t cap = gc_sizeOf(result.ptr);
+    assert(!cap || cap > result.length * sizeelem);
+}
+body
+{
+    version (none)
+    {
+        /* Cannot use this optimization because:
+         *  char[] a, b;
+         *  char c = 'a';
+         *  b = a ~ c;
+         *  c = 'b';
+         * will change the contents of b.
+         */
+        if (!y.length)
+            return x;
+        if (!x.length)
+            return y;
+    }
+
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr);
+    auto sizeelem = ti.next.tsize();            // array element size
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem);
+    size_t xlen = x.length * sizeelem;
+    size_t ylen = y.length * sizeelem;
+    size_t len  = xlen + ylen;
+
+    if (!len)
+        return null;
+
+    byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    memcpy(p, x.ptr, xlen);
+    memcpy(p + xlen, y.ptr, ylen);
+    p[len] = 0;
+    return p[0 .. x.length + y.length];
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
+{   void* a;
+    size_t length;
+    byte[]* p;
+    uint i;
+    byte[] b;
+    auto size = ti.next.tsize(); // array element size
+
+    p = cast(byte[]*)(&n + 1);
+
+    for (i = 0; i < n; i++)
+    {
+        b = *p++;
+        length += b.length;
+    }
+    if (!length)
+        return null;
+
+    a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    p = cast(byte[]*)(&n + 1);
+
+    uint j = 0;
+    for (i = 0; i < n; i++)
+    {
+        b = *p++;
+        if (b.length)
+        {
+            memcpy(a + j, b.ptr, b.length * size);
+            j += b.length * size;
+        }
+    }
+
+    byte[] result;
+    *cast(int *)&result = length;       // jam length
+    (cast(void **)&result)[1] = a;      // jam ptr
+    return result;
+}
+
+
+/**
+ *
+ */
+extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    void* result;
+
+    debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length);
+    if (length == 0 || sizeelem == 0)
+        result = null;
+    else
+    {
+        result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+
+        va_list q;
+        va_start!(size_t)(q, length);
+
+        size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1);
+
+        if (stacksize == sizeelem)
+        {
+            memcpy(result, q, length * sizeelem);
+        }
+        else
+        {
+            for (size_t i = 0; i < length; i++)
+            {
+                memcpy(result + i * sizeelem, q, sizeelem);
+                q += stacksize;
+            }
+        }
+
+        va_end(q);
+    }
+    return result;
+}
+
+
+/**
+ * Support for array.dup property.
+ */
+struct Array2
+{
+    size_t length;
+    void*  ptr;
+}
+
+
+/**
+ *
+ */
+extern (C) long _adDupT(TypeInfo ti, Array2 a)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    assert(memcmp((*cast(Array2*)&result).ptr, a.ptr, a.length * sizeelem) == 0);
+}
+body
+{
+    Array2 r;
+
+    if (a.length)
+    {
+        auto sizeelem = ti.next.tsize();                // array element size
+        auto size = a.length * sizeelem;
+        r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        r.length = a.length;
+        memcpy(r.ptr, a.ptr, size);
+    }
+    return *cast(long*)(&r);
+}
+
+
+unittest
+{
+    int[] a;
+    int[] b;
+    int i;
+
+    a = new int[3];
+    a[0] = 1; a[1] = 2; a[2] = 3;
+    b = a.dup;
+    assert(b.length == 3);
+    for (i = 0; i < 3; i++)
+        assert(b[i] == i + 1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/llmath.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,295 @@
+// llmath.d
+// Copyright (C) 1993-2003 by Digital Mars, www.digitalmars.com
+// All Rights Reserved
+// Written by Walter Bright
+
+module rt.llmath;
+
+// Compiler runtime support for 64 bit longs
+
+extern (C):
+
+
+/***************************************
+ * Unsigned long divide.
+ * Input:
+ *      [EDX,EAX],[ECX,EBX]
+ * Output:
+ *      [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
+ *      [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
+ *      ESI,EDI destroyed
+ */
+
+void __ULDIV__()
+{
+    asm
+    {
+        naked                   ;
+        test    ECX,ECX         ;
+        jz      uldiv           ;
+
+        push    EBP             ;
+
+        // left justify [ECX,EBX] and leave count of shifts + 1 in EBP
+
+        mov     EBP,1           ;       // at least 1 shift
+        test    ECX,ECX         ;       // left justified?
+        js      L1              ;       // yes
+        jnz     L2              ;
+        add     EBP,8           ;
+        mov     CH,CL           ;
+        mov     CL,BH           ;
+        mov     BH,BL           ;
+        xor     BL,BL           ;       // [ECX,EBX] <<= 8
+        test    ECX,ECX         ;
+        js      L1              ;
+        even                    ;
+L2:     inc     EBP             ;       // another shift
+        shl     EBX,1           ;
+        rcl     ECX,1           ;       // [ECX,EBX] <<= 1
+        jno     L2              ;       // not left justified yet
+
+L1:     mov     ESI,ECX         ;
+        mov     EDI,EBX         ;       // [ESI,EDI] = divisor
+
+        mov     ECX,EDX         ;
+        mov     EBX,EAX         ;       // [ECX,EBX] = [EDX,EAX]
+        xor     EAX,EAX         ;
+        cdq                     ;       // [EDX,EAX] = 0
+        even                    ;
+L4:     cmp     ESI,ECX         ;       // is [ECX,EBX] > [ESI,EDI]?
+        ja      L3              ;       // yes
+        jb      L5              ;       // definitely less than
+        cmp     EDI,EBX         ;       // check low order word
+        ja      L3              ;
+L5:     sub     EBX,EDI         ;
+        sbb     ECX,ESI         ;       // [ECX,EBX] -= [ESI,EDI]
+        stc                     ;       // rotate in a 1
+L3:     rcl     EAX,1           ;
+        rcl     EDX,1           ;       // [EDX,EAX] = ([EDX,EAX] << 1) + C
+        shr     ESI,1           ;
+        rcr     EDI,1           ;       // [ESI,EDI] >>= 1
+        dec     EBP             ;       // control count
+        jne     L4              ;
+        pop     EBP             ;
+        ret                     ;
+
+div0:   mov     EAX,-1          ;
+        cwd                     ;       // quotient is -1
+//      xor     ECX,ECX         ;
+//      mov     EBX,ECX         ;       // remainder is 0 (ECX and EBX already 0)
+        pop     EBP             ;
+        ret                     ;
+
+uldiv:  test    EDX,EDX         ;
+        jnz     D3              ;
+        // Both high words are 0, we can use the DIV instruction
+        div     EBX             ;
+        mov     EBX,EDX         ;
+        mov     EDX,ECX         ;       // EDX = ECX = 0
+        ret                     ;
+
+        even                    ;
+D3:     // Divide [EDX,EAX] by EBX
+        mov     ECX,EAX         ;
+        mov     EAX,EDX         ;
+        xor     EDX,EDX         ;
+        div     EBX             ;
+        xchg    ECX,EAX         ;
+        div     EBX             ;
+        // ECX,EAX = result
+        // EDX = remainder
+        mov     EBX,EDX         ;
+        mov     EDX,ECX         ;
+        xor     ECX,ECX         ;
+        ret                     ;
+    }
+}
+
+
+/***************************************
+ * Signed long divide.
+ * Input:
+ *      [EDX,EAX],[ECX,EBX]
+ * Output:
+ *      [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
+ *      [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
+ *      ESI,EDI destroyed
+ */
+
+void __LDIV__()
+{
+    asm
+    {
+        naked                   ;
+        test    EDX,EDX         ;       // [EDX,EAX] negative?
+        jns     L10             ;       // no
+        //neg64 EDX,EAX         ;       // [EDX,EAX] = -[EDX,EAX]
+          neg   EDX             ;
+          neg   EAX             ;
+          sbb   EDX,0           ;
+        test    ECX,ECX         ;       // [ECX,EBX] negative?
+        jns     L11             ;       // no
+        //neg64 ECX,EBX         ;
+          neg   ECX             ;
+          neg   EBX             ;
+          sbb   ECX,0           ;
+        call    __ULDIV__       ;
+        //neg64 ECX,EBX         ;       // remainder same sign as dividend
+          neg   ECX             ;
+          neg   EBX             ;
+          sbb   ECX,0           ;
+        ret                     ;
+
+L11:    call    __ULDIV__       ;
+        //neg64 ECX,EBX         ;       // remainder same sign as dividend
+          neg   ECX             ;
+          neg   EBX             ;
+          sbb   ECX,0           ;
+        //neg64 EDX,EAX         ;       // quotient is negative
+          neg   EDX             ;
+          neg   EAX             ;
+          sbb   EDX,0           ;
+        ret                     ;
+
+L10:    test    ECX,ECX         ;       // [ECX,EBX] negative?
+        jns     L12             ;       // no (all is positive)
+        //neg64 ECX,EBX         ;
+          neg   ECX             ;
+          neg   EBX             ;
+          sbb   ECX,0           ;
+        call    __ULDIV__       ;
+        //neg64 EDX,EAX         ;       // quotient is negative
+          neg   EDX             ;
+          neg   EAX             ;
+          sbb   EDX,0           ;
+        ret                     ;
+
+L12:    jmp     __ULDIV__       ;
+    }
+}
+
+
+/***************************************
+ * Compare [EDX,EAX] with [ECX,EBX]
+ * Signed
+ * Returns result in flags
+ */
+
+void __LCMP__()
+{
+    asm
+    {
+        naked                   ;
+        cmp     EDX,ECX         ;
+        jne     C1              ;
+        push    EDX             ;
+        xor     EDX,EDX         ;
+        cmp     EAX,EBX         ;
+        jz      C2              ;
+        ja      C3              ;
+        dec     EDX             ;
+        pop     EDX             ;
+        ret                     ;
+
+C3:     inc     EDX             ;
+C2:     pop     EDX             ;
+C1:     ret                     ;
+    }
+}
+
+
+
+
+// Convert ulong to real
+
+private real adjust = cast(real)0x800_0000_0000_0000 * 0x10;
+
+real __U64_LDBL()
+{
+    asm
+    {   naked                                   ;
+        push    EDX                             ;
+        push    EAX                             ;
+        and     dword ptr 4[ESP], 0x7FFFFFFF    ;
+        fild    qword ptr [ESP]                 ;
+        test    EDX,EDX                         ;
+        jns     L1                              ;
+        fld     real ptr adjust                 ;
+        faddp   ST(1), ST                       ;
+    L1:                                         ;
+        add     ESP, 8                          ;
+        ret                                     ;
+    }
+}
+
+// Same as __U64_LDBL, but return result as double in [EDX,EAX]
+ulong __ULLNGDBL()
+{
+    asm
+    {   naked                                   ;
+        call __U64_LDBL                         ;
+        sub  ESP,8                              ;
+        fstp double ptr [ESP]                   ;
+        pop  EAX                                ;
+        pop  EDX                                ;
+        ret                                     ;
+    }
+}
+
+// Convert double to ulong
+
+private short roundTo0 = 0xFBF;
+
+ulong __DBLULLNG()
+{
+    // BUG: should handle NAN's and overflows
+    asm
+    {   naked                                   ;
+        push    EDX                             ;
+        push    EAX                             ;
+        fld     double ptr [ESP]                ;
+        sub     ESP,8                           ;
+        fld     real ptr adjust                 ;
+        fcomp                                   ;
+        fstsw   AX                              ;
+        fstcw   8[ESP]                          ;
+        fldcw   roundTo0                        ;
+        sahf                                    ;
+        jae     L1                              ;
+        fld     real ptr adjust                 ;
+        fsubp   ST(1), ST                       ;
+        fistp   qword ptr [ESP]                 ;
+        pop     EAX                             ;
+        pop     EDX                             ;
+        fldcw   [ESP]                           ;
+        add     ESP,8                           ;
+        add     EDX,0x8000_0000                 ;
+        ret                                     ;
+    L1:                                         ;
+        fistp   qword ptr [ESP]                 ;
+        pop     EAX                             ;
+        pop     EDX                             ;
+        fldcw   [ESP]                           ;
+        add     ESP,8                           ;
+        ret                                     ;
+    }
+}
+
+// Convert double in ST0 to uint
+
+uint __DBLULNG()
+{
+    // BUG: should handle NAN's and overflows
+    asm
+    {   naked                                   ;
+        sub     ESP,16                          ;
+        fstcw   8[ESP]                          ;
+        fldcw   roundTo0                        ;
+        fistp   qword ptr [ESP]                 ;
+        fldcw   8[ESP]                          ;
+        pop     EAX                             ;
+        add     ESP,12                          ;
+        ret                                     ;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/mars.h	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,104 @@
+
+/*
+ * Placed into the Public Domain
+ * written by Walter Bright, Digital Mars
+ * www.digitalmars.com
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+#include <stddef.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+struct ClassInfo;
+struct Vtbl;
+
+typedef struct Vtbl
+{
+    size_t len;
+    void **vptr;
+} Vtbl;
+
+typedef struct Interface
+{
+    struct ClassInfo *classinfo;
+    struct Vtbl vtbl;
+    int offset;
+} Interface;
+
+typedef struct Object
+{
+    void **vptr;
+    void *monitor;
+} Object;
+
+typedef struct ClassInfo
+{
+    Object object;
+
+    size_t initlen;
+    void *init;
+
+    size_t namelen;
+    char *name;
+
+    Vtbl vtbl;
+
+    size_t interfacelen;
+    Interface *interfaces;
+
+    struct ClassInfo *baseClass;
+
+    void *destructor;
+    void *invariant;
+
+    int flags;
+} ClassInfo;
+
+typedef struct Throwable
+{
+    Object object;
+
+    size_t msglen;
+    char*  msg;
+
+    size_t filelen;
+    char*  file;
+
+    size_t line;
+
+    struct Interface *info;
+    struct Throwable *next;
+} Throwable;
+
+typedef struct Array
+{
+    size_t length;
+    void *ptr;
+} Array;
+
+typedef struct Delegate
+{
+    void *thisptr;
+    void (*funcptr)();
+} Delegate;
+
+void _d_monitorenter(Object *h);
+void _d_monitorexit(Object *h);
+
+int _d_isbaseof(ClassInfo *b, ClassInfo *c);
+Object *_d_dynamic_cast(Object *o, ClassInfo *ci);
+
+Object * _d_newclass(ClassInfo *ci);
+void _d_delclass(Object **p);
+
+void _d_OutOfMemory();
+
+#if __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/memory.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,184 @@
+/**
+ * This module exposes functionality for inspecting and manipulating memory.
+ *
+ * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, Sean Kelly
+ */
+module rt.memory;
+
+
+private
+{
+    version( linux )
+    {
+        version = SimpleLibcStackEnd;
+
+        version( SimpleLibcStackEnd )
+        {
+            extern (C) extern void* __libc_stack_end;
+        }
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void* rt_stackBottom()
+{
+    version( Windows )
+    {
+        asm
+        {
+            naked;
+            mov EAX,FS:4;
+            ret;
+        }
+    }
+    else version( linux )
+    {
+        version( SimpleLibcStackEnd )
+        {
+            return __libc_stack_end;
+        }
+        else
+        {
+            // See discussion: http://autopackage.org/forums/viewtopic.php?t=22
+                static void** libc_stack_end;
+
+                if( libc_stack_end == libc_stack_end.init )
+                {
+                    void* handle = dlopen( null, RTLD_NOW );
+                    libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" );
+                    dlclose( handle );
+                }
+                return *libc_stack_end;
+        }
+    }
+    else
+    {
+        static assert( false, "Operating system not supported." );
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void* rt_stackTop()
+{
+    version( D_InlineAsm_X86 )
+    {
+        asm
+        {
+            naked;
+            mov EAX, ESP;
+            ret;
+        }
+    }
+    else
+    {
+            static assert( false, "Architecture not supported." );
+    }
+}
+
+
+private
+{
+    version( Windows )
+    {
+        extern (C)
+        {
+            extern int _xi_a;   // &_xi_a just happens to be start of data segment
+            extern int _edata;  // &_edata is start of BSS segment
+            extern int _end;    // &_end is past end of BSS
+        }
+    }
+    else version( linux )
+    {
+        extern (C)
+        {
+            extern int _data;
+            extern int __data_start;
+            extern int _end;
+            extern int _data_start__;
+            extern int _data_end__;
+            extern int _bss_start__;
+            extern int _bss_end__;
+            extern int __fini_array_end;
+        }
+
+            alias __data_start  Data_Start;
+            alias _end          Data_End;
+    }
+
+    alias void delegate( void*, void* ) scanFn;
+}
+
+
+/**
+ *
+ */
+extern (C) void rt_scanStaticData( scanFn scan )
+{
+    scan(rt_staticDataBottom(), rt_staticDataTop());
+}
+
+/**
+ *
+ */
+extern (C) void* rt_staticDataBottom()
+{
+    version( Windows )
+    {
+        return &_xi_a;
+    }
+    else version( linux )
+    {
+        return &__data_start;
+    }
+    else
+    {
+        static assert( false, "Operating system not supported." );
+    }
+}
+
+/**
+ *
+ */
+extern (C) void* rt_staticDataTop()
+{
+    version( Windows )
+    {
+        return &_end;
+    }
+    else version( linux )
+    {
+        return &_end;
+    }
+    else
+    {
+        static assert( false, "Operating system not supported." );
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/memset.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,120 @@
+/*
+ *  Copyright (C) 2004 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+module rt.memset;
+
+
+extern (C)
+{
+    // Functions from the C library.
+    void *memcpy(void *, void *, size_t);
+}
+
+extern (C):
+
+short *_memset16(short *p, short value, size_t count)
+{
+    short *pstart = p;
+    short *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+int *_memset32(int *p, int value, size_t count)
+{
+version (X86)
+{
+    asm
+    {
+        mov     EDI,p           ;
+        mov     EAX,value       ;
+        mov     ECX,count       ;
+        mov     EDX,EDI         ;
+        rep                     ;
+        stosd                   ;
+        mov     EAX,EDX         ;
+    }
+}
+else
+{
+    int *pstart = p;
+    int *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+}
+
+long *_memset64(long *p, long value, size_t count)
+{
+    long *pstart = p;
+    long *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+cdouble *_memset128(cdouble *p, cdouble value, size_t count)
+{
+    cdouble *pstart = p;
+    cdouble *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+real *_memset80(real *p, real value, size_t count)
+{
+    real *pstart = p;
+    real *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+creal *_memset160(creal *p, creal value, size_t count)
+{
+    creal *pstart = p;
+    creal *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+void *_memsetn(void *p, void *value, int count, size_t sizelem)
+{   void *pstart = p;
+    int i;
+
+    for (i = 0; i < count; i++)
+    {
+        memcpy(p, value, sizelem);
+        p = cast(void *)(cast(char *)p + sizelem);
+    }
+    return pstart;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/minit.asm	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,79 @@
+;_ minit.asm
+; Written by Walter Bright
+; Digital Mars
+; http://www.digitalmars.com/d/
+; Placed into the Public Domain
+
+include macros.asm
+
+ifdef _WIN32
+  DATAGRP      EQU     FLAT
+else
+  DATAGRP      EQU     DGROUP
+endif
+
+; Provide a default resolution for weak extern records, no way in C
+; to define an omf symbol with a specific value
+public __nullext
+__nullext   equ 0
+
+    extrn   __moduleinfo_array:near
+
+; This bit of assembler is needed because, from C or D, one cannot
+; specify the names of data segments. Why does this matter?
+; All the ModuleInfo pointers are placed into a segment named 'FM'.
+; The order in which they are placed in 'FM' is arbitrarily up to the linker.
+; In order to walk all the pointers, we need to be able to find the
+; beginning and the end of the 'FM' segment.
+; This is done by bracketing the 'FM' segment with two other, empty,
+; segments named 'FMB' and 'FME'. Since this module is the only one that
+; ever refers to 'FMB' and 'FME', we get to control the order in which
+; these segments appear relative to 'FM' by using a GROUP statement.
+; So, we have in memory:
+;   FMB empty segment
+;   FM  contains all the pointers
+;   FME empty segment
+; and finding the limits of FM is as easy as taking the address of FMB
+; and the address of FME.
+
+; These segments bracket FM, which contains the list of ModuleInfo pointers
+FMB     segment dword use32 public 'DATA'
+FMB     ends
+FM      segment dword use32 public 'DATA'
+FM      ends
+FME     segment dword use32 public 'DATA'
+FME     ends
+
+; This leaves room in the _fatexit() list for _moduleDtor()
+XOB     segment dword use32 public 'BSS'
+XOB     ends
+XO      segment dword use32 public 'BSS'
+    dd  ?
+XO      ends
+XOE     segment dword use32 public 'BSS'
+XOE     ends
+
+DGROUP         group   FMB,FM,FME
+
+    begcode minit
+
+; extern (C) void _minit();
+; Converts array of ModuleInfo pointers to a D dynamic array of them,
+; so they can be accessed via D.
+; Result is written to:
+; extern (C) ModuleInfo[] _moduleinfo_array;
+
+    public  __minit
+__minit proc    near
+    mov EDX,offset DATAGRP:FMB
+    mov EAX,offset DATAGRP:FME
+    mov dword ptr __moduleinfo_array+4,EDX
+    sub EAX,EDX         ; size in bytes of FM segment
+    shr EAX,2           ; convert to array length
+    mov dword ptr __moduleinfo_array,EAX
+    ret
+__minit endp
+
+    endcode minit
+
+    end
Binary file druntime/src/compiler/dmd/minit.obj has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/monitor.c	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,208 @@
+// D programming language runtime library
+// Public Domain
+// written by Walter Bright, Digital Mars
+// www.digitalmars.com
+
+// This is written in C because nobody has written a pthreads interface
+// to D yet.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if _WIN32
+#elif linux
+#define USE_PTHREADS    1
+#else
+#endif
+
+#if _WIN32
+#include <windows.h>
+#endif
+
+#if USE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include "mars.h"
+
+// This is what the monitor reference in Object points to
+typedef struct Monitor
+{
+    void* impl; // for user-level monitors
+    Array devt; // for internal monitors
+
+#if _WIN32
+    CRITICAL_SECTION mon;
+#endif
+
+#if USE_PTHREADS
+    pthread_mutex_t mon;
+#endif
+} Monitor;
+
+#define MONPTR(h)       (&((Monitor *)(h)->monitor)->mon)
+
+static volatile int inited;
+
+/* =============================== Win32 ============================ */
+
+#if _WIN32
+
+static CRITICAL_SECTION _monitor_critsec;
+
+void _STI_monitor_staticctor()
+{
+    if (!inited)
+    {   InitializeCriticalSection(&_monitor_critsec);
+        inited = 1;
+    }
+}
+
+void _STD_monitor_staticdtor()
+{
+    if (inited)
+    {   inited = 0;
+        DeleteCriticalSection(&_monitor_critsec);
+    }
+}
+
+void _d_monitor_create(Object *h)
+{
+    /*
+     * NOTE: Assume this is only called when h->monitor is null prior to the
+     * call.  However, please note that another thread may call this function
+     * at the same time, so we can not assert this here.  Instead, try and
+     * create a lock, and if one already exists then forget about it.
+     */
+
+    //printf("+_d_monitor_create(%p)\n", h);
+    assert(h);
+    Monitor *cs = NULL;
+    EnterCriticalSection(&_monitor_critsec);
+    if (!h->monitor)
+    {
+        cs = (Monitor *)calloc(sizeof(Monitor), 1);
+        assert(cs);
+        InitializeCriticalSection(&cs->mon);
+        h->monitor = (void *)cs;
+        cs = NULL;
+    }
+    LeaveCriticalSection(&_monitor_critsec);
+    if (cs)
+        free(cs);
+    //printf("-_d_monitor_create(%p)\n", h);
+}
+
+void _d_monitor_destroy(Object *h)
+{
+    //printf("+_d_monitor_destroy(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    DeleteCriticalSection(MONPTR(h));
+    free((void *)h->monitor);
+    h->monitor = NULL;
+    //printf("-_d_monitor_destroy(%p)\n", h);
+}
+
+int _d_monitor_lock(Object *h)
+{
+    //printf("+_d_monitor_acquire(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    EnterCriticalSection(MONPTR(h));
+    //printf("-_d_monitor_acquire(%p)\n", h);
+}
+
+void _d_monitor_unlock(Object *h)
+{
+    //printf("+_d_monitor_release(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    LeaveCriticalSection(MONPTR(h));
+    //printf("-_d_monitor_release(%p)\n", h);
+}
+
+#endif
+
+/* =============================== linux ============================ */
+
+#if USE_PTHREADS
+
+// Includes attribute fixes from David Friedman's GDC port
+
+static pthread_mutex_t _monitor_critsec;
+static pthread_mutexattr_t _monitors_attr;
+
+void _STI_monitor_staticctor()
+{
+    if (!inited)
+    {
+        pthread_mutexattr_init(&_monitors_attr);
+        pthread_mutexattr_settype(&_monitors_attr, PTHREAD_MUTEX_RECURSIVE_NP);
+        pthread_mutex_init(&_monitor_critsec, 0);
+        inited = 1;
+    }
+}
+
+void _STD_monitor_staticdtor()
+{
+    if (inited)
+    {   inited = 0;
+        pthread_mutex_destroy(&_monitor_critsec);
+        pthread_mutexattr_destroy(&_monitors_attr);
+    }
+}
+
+void _d_monitor_create(Object *h)
+{
+    /*
+     * NOTE: Assume this is only called when h->monitor is null prior to the
+     * call.  However, please note that another thread may call this function
+     * at the same time, so we can not assert this here.  Instead, try and
+     * create a lock, and if one already exists then forget about it.
+     */
+
+    //printf("+_d_monitor_create(%p)\n", h);
+    assert(h);
+    Monitor *cs = NULL;
+    pthread_mutex_lock(&_monitor_critsec);
+    if (!h->monitor)
+    {
+        cs = (Monitor *)calloc(sizeof(Monitor), 1);
+        assert(cs);
+        pthread_mutex_init(&cs->mon, & _monitors_attr);
+        h->monitor = (void *)cs;
+        cs = NULL;
+    }
+    pthread_mutex_unlock(&_monitor_critsec);
+    if (cs)
+        free(cs);
+    //printf("-_d_monitor_create(%p)\n", h);
+}
+
+void _d_monitor_destroy(Object *h)
+{
+    //printf("+_d_monitor_destroy(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_destroy(MONPTR(h));
+    free((void *)h->monitor);
+    h->monitor = NULL;
+    //printf("-_d_monitor_destroy(%p)\n", h);
+}
+
+int _d_monitor_lock(Object *h)
+{
+    //printf("+_d_monitor_acquire(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_lock(MONPTR(h));
+    //printf("-_d_monitor_acquire(%p)\n", h);
+}
+
+void _d_monitor_unlock(Object *h)
+{
+    //printf("+_d_monitor_release(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_unlock(MONPTR(h));
+    //printf("-_d_monitor_release(%p)\n", h);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/obj.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,27 @@
+// Copyright (c) 2002 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+
+module rt.obj;
+
+extern (C):
+
+/********************************
+ * Compiler helper for operator == for class objects.
+ */
+
+int _d_obj_eq(Object o1, Object o2)
+{
+    return o1 is o2 || (o1 && o1.opEquals(o2));
+}
+
+
+/********************************
+ * Compiler helper for operator <, <=, >, >= for class objects.
+ */
+
+int _d_obj_cmp(Object o1, Object o2)
+{
+    return o1.opCmp(o2);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/object_.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,1517 @@
+/**
+ * Part of the D programming language runtime library.
+ * Forms the symbols available to all D programs. Includes
+ * Object, which is the root of the class object hierarchy.
+ *
+ * This module is implicitly imported.
+ * Macros:
+ *      WIKI = Object
+ */
+
+/*
+ *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module object;
+
+private
+{
+    import stdc.string;
+    import stdc.stdlib;
+    import util.string;
+    debug(PRINTF) import stdc.stdio;
+
+    extern (C) void onOutOfMemoryError();
+    extern (C) Object _d_newclass(ClassInfo ci);
+}
+
+// NOTE: For some reason, this declaration method doesn't work
+//       in this particular file (and this file only).  It must
+//       be a DMD thing.
+//alias typeof(int.sizeof)                    size_t;
+//alias typeof(cast(void*)0 - cast(void*)0)   ptrdiff_t;
+
+version(X86_64)
+{
+    alias ulong size_t;
+    alias long  ptrdiff_t;
+}
+else
+{
+    alias uint  size_t;
+    alias int   ptrdiff_t;
+}
+
+alias size_t hash_t;
+alias bool equals_t;
+
+alias invariant(char)[]  string;
+alias invariant(wchar)[] wstring;
+alias invariant(dchar)[] dstring;
+
+/**
+ * All D class objects inherit from Object.
+ */
+class Object
+{
+    /**
+     * Convert Object to a human readable string.
+     */
+    string toString()
+    {
+        return this.classinfo.name;
+    }
+
+    /**
+     * Compute hash function for Object.
+     */
+    hash_t toHash()
+    {
+        // BUG: this prevents a compacting GC from working, needs to be fixed
+        return cast(hash_t)cast(void*)this;
+    }
+
+    /**
+     * Compare with another Object obj.
+     * Returns:
+     *  $(TABLE
+     *  $(TR $(TD this &lt; obj) $(TD &lt; 0))
+     *  $(TR $(TD this == obj) $(TD 0))
+     *  $(TR $(TD this &gt; obj) $(TD &gt; 0))
+     *  )
+     */
+    int opCmp(Object o)
+    {
+        // BUG: this prevents a compacting GC from working, needs to be fixed
+        //return cast(int)cast(void*)this - cast(int)cast(void*)o;
+
+        throw new Exception("need opCmp for class " ~ this.classinfo.name);
+        //return this !is o;
+    }
+
+    /**
+     * Returns !=0 if this object does have the same contents as obj.
+     */
+    equals_t opEquals(Object o)
+    {
+        return this is o;
+    }
+
+    interface Monitor
+    {
+        void lock();
+        void unlock();
+    }
+
+    /**
+     * Create instance of class specified by classname.
+     * The class must either have no constructors or have
+     * a default constructor.
+     * Returns:
+     *   null if failed
+     */
+    static Object factory(string classname)
+    {
+        auto ci = ClassInfo.find(classname);
+        if (ci)
+        {
+            return ci.create();
+        }
+        return null;
+    }
+}
+
+/**
+ * Information about an interface.
+ * When an object is accessed via an interface, an Interface* appears as the
+ * first entry in its vtbl.
+ */
+struct Interface
+{
+    ClassInfo   classinfo;  /// .classinfo for this interface (not for containing class)
+    void*[]     vtbl;
+    ptrdiff_t   offset;     /// offset to Interface 'this' from Object 'this'
+}
+
+/**
+ * Runtime type information about a class. Can be retrieved for any class type
+ * or instance by using the .classinfo property.
+ * A pointer to this appears as the first entry in the class's vtbl[].
+ */
+class ClassInfo : Object
+{
+    byte[]      init;           /** class static initializer
+                                 * (init.length gives size in bytes of class)
+                                 */
+    string      name;           /// class name
+    void*[]     vtbl;           /// virtual function pointer table
+    Interface[] interfaces;     /// interfaces this class implements
+    ClassInfo   base;           /// base class
+    void*       destructor;
+    void function(Object) classInvariant;
+    uint        flags;
+    //  1:                      // is IUnknown or is derived from IUnknown
+    //  2:                      // has no possible pointers into GC memory
+    //  4:                      // has offTi[] member
+    //  8:                      // has constructors
+    // 16:                      // has xgetMembers member
+    void*       deallocator;
+    OffsetTypeInfo[] offTi;
+    void function(Object) defaultConstructor;   // default Constructor
+    const(MemberInfo[]) function(in char[]) xgetMembers;
+
+    /**
+     * Search all modules for ClassInfo corresponding to classname.
+     * Returns: null if not found
+     */
+    static ClassInfo find(in char[] classname)
+    {
+        foreach (m; ModuleInfo)
+        {
+            //writefln("module %s, %d", m.name, m.localClasses.length);
+            foreach (c; m.localClasses)
+            {
+                //writefln("\tclass %s", c.name);
+                if (c.name == classname)
+                    return c;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create instance of Object represented by 'this'.
+     */
+    Object create()
+    {
+        if (flags & 8 && !defaultConstructor)
+            return null;
+        Object o = _d_newclass(this);
+        if (flags & 8 && defaultConstructor)
+        {
+            defaultConstructor(o);
+        }
+        return o;
+    }
+
+    /**
+     * Search for all members with the name 'name'.
+     * If name[] is null, return all members.
+     */
+    const(MemberInfo[]) getMembers(in char[] name)
+    {
+        if (flags & 16 && xgetMembers)
+            return xgetMembers(name);
+        return null;
+    }
+}
+
+/**
+ * Array of pairs giving the offset and type information for each
+ * member in an aggregate.
+ */
+struct OffsetTypeInfo
+{
+    size_t   offset;    /// Offset of member from start of object
+    TypeInfo ti;        /// TypeInfo for this member
+}
+
+/**
+ * Runtime type information about a type.
+ * Can be retrieved for any type using a
+ * <a href="../expression.html#typeidexpression">TypeidExpression</a>.
+ */
+class TypeInfo
+{
+    override hash_t toHash()
+    {
+        hash_t hash;
+
+        foreach (char c; this.toString())
+            hash = hash * 9 + c;
+        return hash;
+    }
+
+    override int opCmp(Object o)
+    {
+        if (this is o)
+            return 0;
+        TypeInfo ti = cast(TypeInfo)o;
+        if (ti is null)
+            return 1;
+        return dstrcmp(this.toString(), ti.toString());
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        /* TypeInfo instances are singletons, but duplicates can exist
+         * across DLL's. Therefore, comparing for a name match is
+         * sufficient.
+         */
+        if (this is o)
+            return true;
+        TypeInfo ti = cast(TypeInfo)o;
+        return ti && this.toString() == ti.toString();
+    }
+
+    /// Returns a hash of the instance of a type.
+    hash_t getHash(in void* p) { return cast(hash_t)p; }
+
+    /// Compares two instances for equality.
+    equals_t equals(in void* p1, in void* p2) { return p1 == p2; }
+
+    /// Compares two instances for &lt;, ==, or &gt;.
+    int compare(in void* p1, in void* p2) { return 0; }
+
+    /// Returns size of the type.
+    size_t tsize() { return 0; }
+
+    /// Swaps two instances of the type.
+    void swap(void* p1, void* p2)
+    {
+        size_t n = tsize();
+        for (size_t i = 0; i < n; i++)
+        {
+            byte t = (cast(byte *)p1)[i];
+            (cast(byte*)p1)[i] = (cast(byte*)p2)[i];
+            (cast(byte*)p2)[i] = t;
+        }
+    }
+
+    /// Get TypeInfo for 'next' type, as defined by what kind of type this is,
+    /// null if none.
+    TypeInfo next() { return null; }
+
+    /// Return default initializer, null if default initialize to 0
+    void[] init() { return null; }
+
+    /// Get flags for type: 1 means GC should scan for pointers
+    uint flags() { return 0; }
+
+    /// Get type information on the contents of the type; null if not available
+    OffsetTypeInfo[] offTi() { return null; }
+    /// Run the destructor on the object and all its sub-objects
+    void destroy(void* p) {}
+    /// Run the postblit on the object and all its sub-objects
+    void postblit(void* p) {}
+}
+
+class TypeInfo_Typedef : TypeInfo
+{
+    override string toString() { return name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Typedef c;
+        return this is o ||
+               ((c = cast(TypeInfo_Typedef)o) !is null &&
+                this.name == c.name &&
+                this.base == c.base);
+    }
+
+    override hash_t getHash(in void* p) { return base.getHash(p); }
+    override equals_t equals(in void* p1, in void* p2) { return base.equals(p1, p2); }
+    override int compare(in void* p1, in void* p2) { return base.compare(p1, p2); }
+    override size_t tsize() { return base.tsize(); }
+    override void swap(void* p1, void* p2) { return base.swap(p1, p2); }
+
+    override TypeInfo next() { return base.next(); }
+    override uint flags() { return base.flags(); }
+    override void[] init() { return m_init.length ? m_init : base.init(); }
+
+    TypeInfo base;
+    string   name;
+    void[]   m_init;
+}
+
+class TypeInfo_Enum : TypeInfo_Typedef
+{
+
+}
+
+class TypeInfo_Pointer : TypeInfo
+{
+    override string toString() { return m_next.toString() ~ "*"; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Pointer c;
+        return this is o ||
+                ((c = cast(TypeInfo_Pointer)o) !is null &&
+                 this.m_next == c.m_next);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        return cast(hash_t)*cast(void**)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(void**)p1 == *cast(void**)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(void**)p1 < *cast(void**)p2)
+            return -1;
+        else if (*cast(void**)p1 > *cast(void**)p2)
+            return 1;
+        else
+            return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (void*).sizeof;
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void* tmp = *cast(void**)p1;
+        *cast(void**)p1 = *cast(void**)p2;
+        *cast(void**)p2 = tmp;
+    }
+
+    override TypeInfo next() { return m_next; }
+    override uint flags() { return 1; }
+
+    TypeInfo m_next;
+}
+
+class TypeInfo_Array : TypeInfo
+{
+    override string toString() { return value.toString() ~ "[]"; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Array c;
+        return this is o ||
+               ((c = cast(TypeInfo_Array)o) !is null &&
+                this.value == c.value);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        size_t sz = value.tsize();
+        hash_t hash = 0;
+        void[] a = *cast(void[]*)p;
+        for (size_t i = 0; i < a.length; i++)
+            hash += value.getHash(a.ptr + i * sz);
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        void[] a1 = *cast(void[]*)p1;
+        void[] a2 = *cast(void[]*)p2;
+        if (a1.length != a2.length)
+            return false;
+        size_t sz = value.tsize();
+        for (size_t i = 0; i < a1.length; i++)
+        {
+            if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        void[] a1 = *cast(void[]*)p1;
+        void[] a2 = *cast(void[]*)p2;
+        size_t sz = value.tsize();
+        size_t len = a1.length;
+
+        if (a2.length < len)
+            len = a2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
+            if (result)
+                return result;
+        }
+        return cast(int)a1.length - cast(int)a2.length;
+    }
+
+    override size_t tsize()
+    {
+        return (void[]).sizeof;
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void[] tmp = *cast(void[]*)p1;
+        *cast(void[]*)p1 = *cast(void[]*)p2;
+        *cast(void[]*)p2 = tmp;
+    }
+
+    TypeInfo value;
+
+    override TypeInfo next()
+    {
+        return value;
+    }
+
+    override uint flags() { return 1; }
+}
+
+class TypeInfo_StaticArray : TypeInfo
+{
+    override string toString()
+    {
+        char[10] tmp = void;
+        return cast(string)(value.toString() ~ "[" ~ tmp.intToString(len) ~ "]");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_StaticArray c;
+        return this is o ||
+               ((c = cast(TypeInfo_StaticArray)o) !is null &&
+                this.len == c.len &&
+                this.value == c.value);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        size_t sz = value.tsize();
+        hash_t hash = 0;
+        for (size_t i = 0; i < len; i++)
+            hash += value.getHash(p + i * sz);
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        size_t sz = value.tsize();
+
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!value.equals(p1 + u * sz, p2 + u * sz))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        size_t sz = value.tsize();
+
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = value.compare(p1 + u * sz, p2 + u * sz);
+            if (result)
+                return result;
+        }
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return len * value.tsize();
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void* tmp;
+        size_t sz = value.tsize();
+        ubyte[16] buffer;
+        void* pbuffer;
+
+        if (sz < buffer.sizeof)
+            tmp = buffer.ptr;
+        else
+            tmp = pbuffer = (new void[sz]).ptr;
+
+        for (size_t u = 0; u < len; u += sz)
+        {   size_t o = u * sz;
+            memcpy(tmp, p1 + o, sz);
+            memcpy(p1 + o, p2 + o, sz);
+            memcpy(p2 + o, tmp, sz);
+        }
+        if (pbuffer)
+            delete pbuffer;
+    }
+
+    override void[] init() { return value.init(); }
+    override TypeInfo next() { return value; }
+    override uint flags() { return value.flags(); }
+
+    override void destroy(void* p)
+    {
+        auto sz = value.tsize();
+        p += sz * len;
+        foreach (i; 0 .. len)
+        {
+            p -= sz;
+            value.destroy(p);
+        }
+    }
+
+    override void postblit(void* p)
+    {
+        auto sz = value.tsize();
+        foreach (i; 0 .. len)
+        {
+            value.postblit(p);
+            p += sz;
+        }
+    }
+
+    TypeInfo value;
+    size_t   len;
+}
+
+class TypeInfo_AssociativeArray : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ "[" ~ key.toString() ~ "]");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_AssociativeArray c;
+        return this is o ||
+                ((c = cast(TypeInfo_AssociativeArray)o) !is null &&
+                 this.key == c.key &&
+                 this.value == c.value);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    override size_t tsize()
+    {
+        return (char[int]).sizeof;
+    }
+
+    override TypeInfo next() { return value; }
+    override uint flags() { return 1; }
+
+    TypeInfo value;
+    TypeInfo key;
+}
+
+class TypeInfo_Function : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ "()");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Function c;
+        return this is o ||
+                ((c = cast(TypeInfo_Function)o) !is null &&
+                 this.next == c.next);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    override size_t tsize()
+    {
+        return 0;       // no size for functions
+    }
+
+    TypeInfo next;
+}
+
+class TypeInfo_Delegate : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ " delegate()");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Delegate c;
+        return this is o ||
+                ((c = cast(TypeInfo_Delegate)o) !is null &&
+                 this.next == c.next);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    override size_t tsize()
+    {
+        alias int delegate() dg;
+        return dg.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    TypeInfo next;
+}
+
+class TypeInfo_Class : TypeInfo
+{
+    override string toString() { return info.name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Class c;
+        return this is o ||
+                ((c = cast(TypeInfo_Class)o) !is null &&
+                 this.info.name == c.classinfo.name);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        Object o = *cast(Object*)p;
+        return o ? o.toHash() : 0;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+
+        return (o1 is o2) || (o1 && o1.opEquals(o2));
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (o1 !is o2)
+        {
+            if (o1)
+            {
+                if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    override OffsetTypeInfo[] offTi()
+    {
+        return (info.flags & 4) ? info.offTi : null;
+    }
+
+    ClassInfo info;
+}
+
+class TypeInfo_Interface : TypeInfo
+{
+    override string toString() { return info.name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Interface c;
+        return this is o ||
+                ((c = cast(TypeInfo_Interface)o) !is null &&
+                 this.info.name == c.classinfo.name);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p;
+        Object o = cast(Object)(*cast(void**)p - pi.offset);
+        assert(o);
+        return o.toHash();
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p1;
+        Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
+        pi = **cast(Interface ***)*cast(void**)p2;
+        Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
+
+        return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p1;
+        Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
+        pi = **cast(Interface ***)*cast(void**)p2;
+        Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (o1 != o2)
+        {
+            if (o1)
+            {
+                if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    ClassInfo info;
+}
+
+class TypeInfo_Struct : TypeInfo
+{
+    override string toString() { return name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Struct s;
+        return this is o ||
+                ((s = cast(TypeInfo_Struct)o) !is null &&
+                 this.name == s.name &&
+                 this.init.length == s.init.length);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(p);
+        if (xtoHash)
+        {
+            debug(PRINTF) printf("getHash() using xtoHash\n");
+            return (*xtoHash)(p);
+        }
+        else
+        {
+            hash_t h;
+            debug(PRINTF) printf("getHash() using default hash\n");
+            // A sorry hash algorithm.
+            // Should use the one for strings.
+            // BUG: relies on the GC not moving objects
+            auto q = cast(const(ubyte)*)p;
+            for (size_t i = 0; i < init.length; i++)
+            {
+                h = h * 9 + *q;
+                q++;
+            }
+            return h;
+        }
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        if (p1 == p2)
+            return true;
+        else if (!p1 || !p2)
+            return false;
+        else if (xopEquals)
+            return (*xopEquals)(p1, p2);
+        else
+            // BUG: relies on the GC not moving objects
+            return memcmp(p1, p2, init.length) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        // Regard null references as always being "less than"
+        if (p1 != p2)
+        {
+            if (p1)
+            {
+                if (!p2)
+                    return true;
+                else if (xopCmp)
+                    return (*xopCmp)(p2, p1);
+                else
+                    // BUG: relies on the GC not moving objects
+                    return memcmp(p1, p2, init.length);
+            }
+            else
+                return -1;
+        }
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return init.length;
+    }
+
+    override void[] init() { return m_init; }
+
+    override uint flags() { return m_flags; }
+
+    override void destroy(void* p)
+    {
+        if (xdtor)
+            (*xdtor)(p);
+    }
+
+    override void postblit(void* p)
+    {
+        if (xpostblit)
+            (*xpostblit)(p);
+    }
+
+    string name;
+    void[] m_init;      // initializer; init.ptr == null if 0 initialize
+
+    hash_t   function(in void*)           xtoHash;
+    equals_t function(in void*, in void*) xopEquals;
+    int      function(in void*, in void*) xopCmp;
+    char[]   function(in void*)           xtoString;
+
+    uint m_flags;
+
+    const(MemberInfo[]) function(in char[]) xgetMembers;
+    void function(void*)                    xdtor;
+    void function(void*)                    xpostblit;
+}
+
+class TypeInfo_Tuple : TypeInfo
+{
+    TypeInfo[] elements;
+
+    override string toString()
+    {
+        string s = "(";
+        foreach (i, element; elements)
+        {
+            if (i)
+                s ~= ',';
+            s ~= element.toString();
+        }
+        s ~= ")";
+        return s;
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        if (this is o)
+            return true;
+
+        auto t = cast(TypeInfo_Tuple)o;
+        if (t && elements.length == t.elements.length)
+        {
+            for (size_t i = 0; i < elements.length; i++)
+            {
+                if (elements[i] != t.elements[i])
+                    return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(0);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        assert(0);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        assert(0);
+    }
+
+    override size_t tsize()
+    {
+        assert(0);
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        assert(0);
+    }
+
+    override void destroy(void* p)
+    {
+        assert(0);
+    }
+
+    override void postblit(void* p)
+    {
+        assert(0);
+    }
+}
+
+class TypeInfo_Const : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string) ("const(" ~ base.toString() ~ ")");
+    }
+
+    override equals_t opEquals(Object o) { return base.opEquals(o); }
+    override hash_t getHash(in void *p) { return base.getHash(p); }
+    override equals_t equals(in void *p1, in void *p2) { return base.equals(p1, p2); }
+    override int compare(in void *p1, in void *p2) { return base.compare(p1, p2); }
+    override size_t tsize() { return base.tsize(); }
+    override void swap(void *p1, void *p2) { return base.swap(p1, p2); }
+
+    override TypeInfo next() { return base.next(); }
+    override uint flags() { return base.flags(); }
+    override void[] init() { return base.init(); }
+
+    TypeInfo base;
+}
+
+class TypeInfo_Invariant : TypeInfo_Const
+{
+    override string toString()
+    {
+        return cast(string) ("invariant(" ~ base.toString() ~ ")");
+    }
+}
+
+abstract class MemberInfo
+{
+    string name();
+}
+
+class MemberInfo_field : MemberInfo
+{
+    this(string name, TypeInfo ti, size_t offset)
+    {
+        m_name = name;
+        m_typeinfo = ti;
+        m_offset = offset;
+    }
+
+    override string name() { return m_name; }
+    TypeInfo typeInfo() { return m_typeinfo; }
+    size_t offset() { return m_offset; }
+
+    string   m_name;
+    TypeInfo m_typeinfo;
+    size_t   m_offset;
+}
+
+class MemberInfo_function : MemberInfo
+{
+    this(string name, TypeInfo ti, void* fp, uint flags)
+    {
+        m_name = name;
+        m_typeinfo = ti;
+        m_fp = fp;
+        m_flags = flags;
+    }
+
+    override string name() { return m_name; }
+    TypeInfo typeInfo() { return m_typeinfo; }
+    void* fp() { return m_fp; }
+    uint flags() { return m_flags; }
+
+    string   m_name;
+    TypeInfo m_typeinfo;
+    void*    m_fp;
+    uint     m_flags;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Throwable
+///////////////////////////////////////////////////////////////////////////////
+
+
+class Throwable : Object
+{
+    interface TraceInfo
+    {
+        int opApply(int delegate(inout char[]));
+    }
+
+    string      msg;
+    string      file;
+    size_t      line;
+    TraceInfo   info;
+    Throwable   next;
+
+    this(string msg, Throwable next = null)
+    {
+        this.msg = msg;
+        this.next = next;
+        this.info = traceContext();
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        this(msg, next);
+        this.file = file;
+        this.line = line;
+        this.info = traceContext();
+    }
+
+    override string toString()
+    {
+        char[10] tmp = void;
+        char[]   buf;
+
+        for (Throwable e = this; e !is null; e = e.next)
+        {
+            if (e.file)
+            {
+               buf ~= e.classinfo.name ~ "@" ~ e.file ~ "(" ~ tmp.intToString(e.line) ~ "): " ~ e.msg;
+            }
+            else
+            {
+               buf ~= e.classinfo.name ~ ": " ~ e.msg;
+            }
+            if (e.info)
+            {
+                buf ~= "\n----------------";
+                foreach (t; e.info)
+                    buf ~= "\n" ~ t;
+            }
+            if (e.next)
+                buf ~= "\n";
+        }
+        return cast(string) buf;
+    }
+}
+
+
+alias Throwable.TraceInfo function(void* ptr = null) TraceHandler;
+private TraceHandler traceHandler = null;
+
+
+/**
+ * Overrides the default trace hander with a user-supplied version.
+ *
+ * Params:
+ *  h = The new trace handler.  Set to null to use the default handler.
+ */
+extern (C) void  rt_setTraceHandler(TraceHandler h)
+{
+    traceHandler = h;
+}
+
+
+/**
+ * This function will be called when an exception is constructed.  The
+ * user-supplied trace handler will be called if one has been supplied,
+ * otherwise no trace will be generated.
+ *
+ * Params:
+ *  ptr = A pointer to the location from which to generate the trace, or null
+ *        if the trace should be generated from within the trace handler
+ *        itself.
+ *
+ * Returns:
+ *  An object describing the current calling context or null if no handler is
+ *  supplied.
+ */
+Throwable.TraceInfo traceContext(void* ptr = null)
+{
+    if (traceHandler is null)
+        return null;
+    return traceHandler(ptr);
+}
+
+
+class Exception : Throwable
+{
+    this(string msg, Throwable next = null)
+    {
+        super(msg, next);
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        super(msg, file, line, next);
+    }
+}
+
+
+class Error : Throwable
+{
+    this(string msg, Throwable next = null)
+    {
+        super(msg, next);
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        super(msg, file, line, next);
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// ModuleInfo
+///////////////////////////////////////////////////////////////////////////////
+
+
+enum
+{
+    MIctorstart  = 1,   // we've started constructing it
+    MIctordone   = 2,   // finished construction
+    MIstandalone = 4,   // module ctor does not depend on other module
+                        // ctors being done first
+    MIhasictor   = 8,   // has ictor member
+}
+
+
+class ModuleInfo
+{
+    string          name;
+    ModuleInfo[]    importedModules;
+    ClassInfo[]     localClasses;
+    uint            flags;
+
+    void function() ctor;       // module static constructor (order dependent)
+    void function() dtor;       // module static destructor
+    void function() unitTest;   // module unit tests
+
+    void* xgetMembers;          // module getMembers() function
+
+    void function() ictor;      // module static constructor (order independent)
+
+    static int opApply(int delegate(inout ModuleInfo) dg)
+    {
+        int ret = 0;
+
+        foreach (m; _moduleinfo_array)
+        {
+            ret = dg(m);
+            if (ret)
+                break;
+        }
+        return ret;
+    }
+}
+
+
+// Windows: this gets initialized by minit.asm
+// linux: this gets initialized in _moduleCtor()
+extern (C) ModuleInfo[] _moduleinfo_array;
+
+
+version (linux)
+{
+    // This linked list is created by a compiler generated function inserted
+    // into the .ctor list by the compiler.
+    struct ModuleReference
+    {
+        ModuleReference* next;
+        ModuleInfo       mod;
+    }
+
+    extern (C) ModuleReference* _Dmodule_ref;   // start of linked list
+}
+
+ModuleInfo[] _moduleinfo_dtors;
+uint         _moduleinfo_dtors_i;
+
+// Register termination function pointers
+extern (C) int _fatexit(void*);
+
+/**
+ * Initialize the modules.
+ */
+
+extern (C) void _moduleCtor()
+{
+    debug(PRINTF) printf("_moduleCtor()\n");
+    version (linux)
+    {
+        int len = 0;
+        ModuleReference *mr;
+
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+            len++;
+        _moduleinfo_array = new ModuleInfo[len];
+        len = 0;
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+        {   _moduleinfo_array[len] = mr.mod;
+            len++;
+        }
+    }
+
+    version (Windows)
+    {
+        // Ensure module destructors also get called on program termination
+        //_fatexit(&_STD_moduleDtor);
+    }
+
+    _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length];
+    debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void*)_moduleinfo_dtors);
+    _moduleIndependentCtors();
+    _moduleCtor2(_moduleinfo_array, 0);
+}
+
+extern (C) void _moduleIndependentCtors()
+{
+    debug(PRINTF) printf("_moduleIndependentCtors()\n");
+    foreach (m; _moduleinfo_array)
+    {
+        if (m && m.flags & MIhasictor && m.ictor)
+        {
+            (*m.ictor)();
+        }
+    }
+}
+
+void _moduleCtor2(ModuleInfo[] mi, int skip)
+{
+    debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length);
+    for (uint i = 0; i < mi.length; i++)
+    {
+        ModuleInfo m = mi[i];
+
+        debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m);
+        if (!m)
+            continue;
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name);
+        if (m.flags & MIctordone)
+            continue;
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m);
+
+        if (m.ctor || m.dtor)
+        {
+            if (m.flags & MIctorstart)
+            {   if (skip || m.flags & MIstandalone)
+                    continue;
+                    throw new Exception("Cyclic dependency in module " ~ m.name);
+            }
+
+            m.flags |= MIctorstart;
+            _moduleCtor2(m.importedModules, 0);
+            if (m.ctor)
+                (*m.ctor)();
+            m.flags &= ~MIctorstart;
+            m.flags |= MIctordone;
+
+            // Now that construction is done, register the destructor
+            //printf("\tadding module dtor x%x\n", m);
+            assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length);
+            _moduleinfo_dtors[_moduleinfo_dtors_i++] = m;
+        }
+        else
+        {
+            m.flags |= MIctordone;
+            _moduleCtor2(m.importedModules, 1);
+        }
+    }
+}
+
+/**
+ * Destruct the modules.
+ */
+
+// Starting the name with "_STD" means under linux a pointer to the
+// function gets put in the .dtors segment.
+
+extern (C) void _moduleDtor()
+{
+    debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i);
+
+    for (uint i = _moduleinfo_dtors_i; i-- != 0;)
+    {
+        ModuleInfo m = _moduleinfo_dtors[i];
+
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m);
+        if (m.dtor)
+        {
+            (*m.dtor)();
+        }
+    }
+    debug(PRINTF) printf("_moduleDtor() done\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Monitor
+///////////////////////////////////////////////////////////////////////////////
+
+alias Object.Monitor        IMonitor;
+alias void delegate(Object) DEvent;
+
+// NOTE: The dtor callback feature is only supported for monitors that are not
+//       supplied by the user.  The assumption is that any object with a user-
+//       supplied monitor may have special storage or lifetime requirements and
+//       that as a result, storing references to local objects within Monitor
+//       may not be safe or desirable.  Thus, devt is only valid if impl is
+//       null.
+struct Monitor
+{
+    IMonitor impl;
+    /* internal */
+    DEvent[] devt;
+    /* stuff */
+}
+
+Monitor* getMonitor(Object h)
+{
+    return cast(Monitor*) (cast(void**) h)[1];
+}
+
+void setMonitor(Object h, Monitor* m)
+{
+    (cast(void**) h)[1] = m;
+}
+
+extern (C) void _d_monitor_create(Object);
+extern (C) void _d_monitor_destroy(Object);
+extern (C) void _d_monitor_lock(Object);
+extern (C) int  _d_monitor_unlock(Object);
+
+extern (C) void _d_monitordelete(Object h, bool det)
+{
+    Monitor* m = getMonitor(h);
+
+    if (m !is null)
+    {
+        IMonitor i = m.impl;
+        if (i is null)
+        {
+            _d_monitor_devt(m, h);
+            _d_monitor_destroy(h);
+            setMonitor(h, null);
+            return;
+        }
+        if (det && (cast(void*) i) !is (cast(void*) h))
+            delete i;
+        setMonitor(h, null);
+    }
+}
+
+extern (C) void _d_monitorenter(Object h)
+{
+    Monitor* m = getMonitor(h);
+
+    if (m is null)
+    {
+        _d_monitor_create(h);
+        m = getMonitor(h);
+    }
+
+    IMonitor i = m.impl;
+
+    if (i is null)
+    {
+        _d_monitor_lock(h);
+        return;
+    }
+    i.lock();
+}
+
+extern (C) void _d_monitorexit(Object h)
+{
+    Monitor* m = getMonitor(h);
+    IMonitor i = m.impl;
+
+    if (i is null)
+    {
+        _d_monitor_unlock(h);
+        return;
+    }
+    i.unlock();
+}
+
+extern (C) void _d_monitor_devt(Monitor* m, Object h)
+{
+    if (m.devt.length)
+    {
+        DEvent[] devt;
+
+        synchronized (h)
+        {
+            devt = m.devt;
+            m.devt = null;
+        }
+        foreach (v; devt)
+        {
+            if (v)
+                v(h);
+        }
+        free(devt.ptr);
+    }
+}
+
+extern (C) void rt_attachDisposeEvent(Object h, DEvent e)
+{
+    synchronized (h)
+    {
+        Monitor* m = getMonitor(h);
+        assert(m.impl is null);
+
+        foreach (inout v; m.devt)
+        {
+            if (v is null || v == e)
+            {
+                v = e;
+                return;
+            }
+        }
+
+        auto len = m.devt.length + 4; // grow by 4 elements
+        auto pos = m.devt.length;     // insert position
+        auto p = realloc(m.devt.ptr, DEvent.sizeof * len);
+        if (!p)
+            onOutOfMemoryError();
+        m.devt = (cast(DEvent*)p)[0 .. len];
+        m.devt[pos+1 .. len] = null;
+        m.devt[pos] = e;
+    }
+}
+
+extern (C) void rt_detachDisposeEvent(Object h, DEvent e)
+{
+    synchronized (h)
+    {
+        Monitor* m = getMonitor(h);
+        assert(m.impl is null);
+
+        foreach (p, v; m.devt)
+        {
+            if (v == e)
+            {
+                memmove(&m.devt[p],
+                        &m.devt[p+1],
+                        (m.devt.length - p - 1) * DEvent.sizeof);
+                m.devt[$ - 1] = null;
+                return;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/posix.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,178 @@
+# Makefile to build the compiler runtime D library for Linux
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the compiler runtime library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=libdruntime-rt-dmd.a
+LIB_MASK=libdruntime-rt-dmd*.a
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+CFLAGS=-O $(ADD_CFLAGS)
+#CFLAGS=-g $(ADD_CFLAGS)
+
+DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
+#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
+#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=gcc
+LC=$(AR) -qsv
+DC=dmd
+
+LIB_DEST=../../../lib
+
+.SUFFIXES: .s .S .c .cpp .d .html .o
+
+.s.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.S.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.o:
+	g++ -c $(CFLAGS) $< -o$@
+
+.d.o:
+	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
+
+targets : lib doc
+all     : lib doc
+lib     : dmd.lib
+doc     : dmd.doc
+
+######################################################
+
+OBJ_BASE= \
+    aaA.o \
+    aApply.o \
+    aApplyR.o \
+    adi.o \
+    alloca.o \
+    arrayassign.o \
+    arraybyte.o \
+    arraycast.o \
+    arraycat.o \
+    arraydouble.o \
+    arrayfloat.o \
+    arrayint.o \
+    arrayreal.o \
+    arrayshort.o \
+    cast_.o \
+    cmath2.o \
+    complex.o \
+    cover.o \
+    critical.o \
+    deh2.o \
+    dmain2.o \
+    invariant.o \
+    invariant_.o \
+    lifetime.o \
+    llmath.o \
+    memory.o \
+    memset.o \
+    monitor.o \
+    obj.o \
+    object_.o \
+    qsort.o \
+    switch_.o \
+    trace.o
+# NOTE: trace.obj and cover.obj are not necessary for a successful build
+#       as both are used for debugging features (profiling and coverage)
+# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and
+#       minit.asm is not used by dmd for linux
+# NOTE: deh.o is only needed for Win32, linux uses deh2.o
+
+OBJ_UTIL= \
+    util/console.o \
+    util/cpuid.o \
+    util/ctype.o \
+    util/string.o \
+    util/utf.o
+
+OBJ_TI= \
+    typeinfo/ti_AC.o \
+    typeinfo/ti_Acdouble.o \
+    typeinfo/ti_Acfloat.o \
+    typeinfo/ti_Acreal.o \
+    typeinfo/ti_Adouble.o \
+    typeinfo/ti_Afloat.o \
+    typeinfo/ti_Ag.o \
+    typeinfo/ti_Aint.o \
+    typeinfo/ti_Along.o \
+    typeinfo/ti_Areal.o \
+    typeinfo/ti_Ashort.o \
+    typeinfo/ti_byte.o \
+    typeinfo/ti_C.o \
+    typeinfo/ti_cdouble.o \
+    typeinfo/ti_cfloat.o \
+    typeinfo/ti_char.o \
+    typeinfo/ti_creal.o \
+    typeinfo/ti_dchar.o \
+    typeinfo/ti_delegate.o \
+    typeinfo/ti_double.o \
+    typeinfo/ti_float.o \
+    typeinfo/ti_idouble.o \
+    typeinfo/ti_ifloat.o \
+    typeinfo/ti_int.o \
+    typeinfo/ti_ireal.o \
+    typeinfo/ti_long.o \
+    typeinfo/ti_ptr.o \
+    typeinfo/ti_real.o \
+    typeinfo/ti_short.o \
+    typeinfo/ti_ubyte.o \
+    typeinfo/ti_uint.o \
+    typeinfo/ti_ulong.o \
+    typeinfo/ti_ushort.o \
+    typeinfo/ti_void.o \
+    typeinfo/ti_wchar.o
+
+ALL_OBJS= \
+    $(OBJ_BASE) \
+    $(OBJ_UTIL) \
+    $(OBJ_TI)
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+dmd.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) $@ $(ALL_OBJS)
+
+dmd.doc : $(ALL_DOCS)
+	echo No documentation available.
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/qsort.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,158 @@
+/*
+        Portions of this file are:
+        Copyright Prototronics, 1987
+        Totem Lake P.O. 8117
+        Kirkland, Washington 98034
+        (206) 820-1972
+        Licensed to Digital Mars.
+
+        June 11, 1987 from Ray Gardner's
+        Denver, Colorado) public domain version
+
+        Use qsort2.d instead of this file if a redistributable version of
+        _adSort() is required.
+*/
+
+module rt.qsort;
+
+/*
+**    Sorts an array starting at base, of length nbr_elements, each
+**    element of size width_bytes, ordered via compare_function; which
+**    is called as  (*comp_fp)(ptr_to_element1, ptr_to_element2)
+**    and returns < 0 if element1 < element2, 0 if element1 = element2,
+**    > 0 if element1 > element2.  Most of the refinements are due to
+**    R. Sedgewick.  See "Implementing Quicksort Programs", Comm. ACM,
+**    Oct. 1978, and Corrigendum, Comm. ACM, June 1979.
+*/
+
+//debug=qsort;          // uncomment to turn on debugging printf's
+
+
+struct Array
+{
+    size_t length;
+    void*  ptr;
+}
+
+
+private const int _maxspan = 7; // subarrays of _maxspan or fewer elements
+                                // will be sorted by a simple insertion sort
+
+/* Adjust _maxspan according to relative cost of a swap and a compare.  Reduce
+_maxspan (not less than 1) if a swap is very expensive such as when you have
+an array of large structures to be sorted, rather than an array of pointers to
+structures.  The default value is optimized for a high cost for compares. */
+
+
+extern (C) long _adSort(Array a, TypeInfo ti)
+{
+  byte* base;
+  byte*[40] stack;              // stack
+  byte** sp;                    // stack pointer
+  byte* i, j, limit;            // scan and limit pointers
+  uint thresh;                  // size of _maxspan elements in bytes
+  uint width = ti.tsize();
+
+  base = cast(byte *)a.ptr;
+  thresh = _maxspan * width;             // init threshold
+  sp = stack.ptr;                        // init stack pointer
+  limit = base + a.length * width;       // pointer past end of array
+  while (1)                              // repeat until done then return
+  {
+    while (limit - base > thresh)        // if more than _maxspan elements
+    {
+      //swap middle, base
+      ti.swap((cast(uint)(limit - base) >> 1) -
+           (((cast(uint)(limit - base) >> 1)) % width) + base, base);
+
+      i = base + width;                 // i scans from left to right
+      j = limit - width;                // j scans from right to left
+
+      if (ti.compare(i, j) > 0)         // Sedgewick's
+        ti.swap(i, j);                  //    three-element sort
+      if (ti.compare(base, j) > 0)      // sets things up
+        ti.swap(base, j);               // so that
+      if (ti.compare(i, base) > 0)      // *i <= *base <= *j
+        ti.swap(i, base);               // *base is the pivot element
+
+      while (1)
+      {
+        do                              // move i right until *i >= pivot
+          i += width;
+        while (ti.compare(i, base) < 0);
+        do                              // move j left until *j <= pivot
+          j -= width;
+        while (ti.compare(j, base) > 0);
+        if (i > j)                      // break loop if pointers crossed
+          break;
+        ti.swap(i, j);                  // else swap elements, keep scanning
+      }
+      ti.swap(base, j);                 // move pivot into correct place
+      if (j - base > limit - i)         // if left subarray is larger...
+      {
+        sp[0] = base;                   // stack left subarray base
+        sp[1] = j;                      //    and limit
+        base = i;                       // sort the right subarray
+      }
+      else                              // else right subarray is larger
+      {
+        sp[0] = i;                      // stack right subarray base
+        sp[1] = limit;                  //    and limit
+        limit = j;                      // sort the left subarray
+      }
+      sp += 2;                          // increment stack pointer
+      assert(sp < cast(byte**)stack + stack.length);
+    }
+
+    // Insertion sort on remaining subarray
+    i = base + width;
+    while (i < limit)
+    {
+      j = i;
+      while (j > base && ti.compare(j - width, j) > 0)
+      {
+        ti.swap(j - width, j);
+        j -= width;
+      }
+      i += width;
+    }
+
+    if (sp > stack.ptr)                 // if any entries on stack...
+    {
+      sp -= 2;                          // pop the base and limit
+      base = sp[0];
+      limit = sp[1];
+    }
+    else                                // else stack empty, all done
+      return *cast(long*)(&a);
+  }
+  assert(0);
+}
+
+
+unittest
+{
+    debug(qsort) printf("array.sort.unittest()\n");
+
+    int a[] = new int[10];
+
+    a[0] = 23;
+    a[1] = 1;
+    a[2] = 64;
+    a[3] = 5;
+    a[4] = 6;
+    a[5] = 5;
+    a[6] = 17;
+    a[7] = 3;
+    a[8] = 0;
+    a[9] = -1;
+
+    a.sort;
+
+    for (int i = 0; i < a.length - 1; i++)
+    {
+        //printf("i = %d", i);
+        //printf(" %d %d\n", a[i], a[i + 1]);
+        assert(a[i] <= a[i + 1]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/qsort2.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,72 @@
+
+/*
+ * Placed into Public Domain
+ * written by Walter Bright
+ * www.digitalmars.com
+ *
+ * This is a public domain version of qsort.d.
+ * All it does is call C's qsort(), but runs a little slower since
+ * it needs to synchronize a global variable.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.qsort2;
+
+//debug=qsort;
+
+private import stdc.stdlib;
+
+struct Array
+{
+    size_t length;
+    void*  ptr;
+}
+
+private TypeInfo tiglobal;
+
+extern (C) int cmp(void* p1, void* p2)
+{
+    return tiglobal.compare(p1, p2);
+}
+
+extern (C) long _adSort(Array a, TypeInfo ti)
+{
+    synchronized
+    {
+        tiglobal = ti;
+        qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp);
+    }
+    return *cast(long*)(&a);
+}
+
+
+
+unittest
+{
+    debug(qsort) printf("array.sort.unittest()\n");
+
+    int a[] = new int[10];
+
+    a[0] = 23;
+    a[1] = 1;
+    a[2] = 64;
+    a[3] = 5;
+    a[4] = 6;
+    a[5] = 5;
+    a[6] = 17;
+    a[7] = 3;
+    a[8] = 0;
+    a[9] = -1;
+
+    a.sort;
+
+    for (int i = 0; i < a.length - 1; i++)
+    {
+        //printf("i = %d", i);
+        //printf(" %d %d\n", a[i], a[i + 1]);
+        assert(a[i] <= a[i + 1]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/switch_.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,426 @@
+/*
+ *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.switch_;
+
+private import stdc.string;
+
+/******************************************************
+ * Support for switch statements switching on strings.
+ * Input:
+ *      table[]         sorted array of strings generated by compiler
+ *      ca              string to look up in table
+ * Output:
+ *      result          index of match in table[]
+ *                      -1 if not in table
+ */
+
+extern (C):
+
+int _d_switch_string(char[][] table, char[] ca)
+in
+{
+    //printf("in _d_switch_string()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        int len1 = table[j - 1].length;
+        int len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int ci;
+
+            ci = memcmp(table[j - 1].ptr, table[j].ptr, len1);
+            assert(ci < 0); // ci==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int cj;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   cj = memcmp(table[i].ptr, ca.ptr, ca.length);
+                assert(cj != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                cj = memcmp(table[i].ptr, ca.ptr, ca.length);
+                if (cj == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_string(%.*s)\n", ca);
+    int low;
+    int high;
+    int mid;
+    int c;
+    char[] pca;
+
+    low = 0;
+    high = table.length;
+
+    version (none)
+    {
+        // Print table
+        printf("ca[] = '%s'\n", cast(char *)ca);
+        for (mid = 0; mid < high; mid++)
+        {
+            pca = table[mid];
+            printf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+        }
+    }
+    if (high &&
+        ca.length >= table[0].length &&
+        ca.length <= table[high - 1].length)
+    {
+        // Looking for 0 length string, which would only be at the beginning
+        if (ca.length == 0)
+            return 0;
+
+        char c1 = ca[0];
+
+        // Do binary search
+        while (low < high)
+        {
+            mid = (low + high) >> 1;
+            pca = table[mid];
+            c = ca.length - pca.length;
+            if (c == 0)
+            {
+                c = cast(ubyte)c1 - cast(ubyte)pca[0];
+                if (c == 0)
+                {
+                    c = memcmp(ca.ptr, pca.ptr, ca.length);
+                    if (c == 0)
+                    {   //printf("found %d\n", mid);
+                        return mid;
+                    }
+                }
+            }
+            if (c < 0)
+            {
+                high = mid;
+            }
+            else
+            {
+                low = mid + 1;
+            }
+        }
+    }
+
+    //printf("not found\n");
+    return -1; // not found
+}
+
+unittest
+{
+    switch (cast(char []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
+
+/**********************************
+ * Same thing, but for wide chars.
+ */
+
+int _d_switch_ustring(wchar[][] table, wchar[] ca)
+in
+{
+    //printf("in _d_switch_ustring()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        int len1 = table[j - 1].length;
+        int len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int c;
+
+            c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof);
+            assert(c < 0);  // c==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int c;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
+                assert(c != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
+                if (c == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_ustring()\n");
+    int low;
+    int high;
+    int mid;
+    int c;
+    wchar[] pca;
+
+    low = 0;
+    high = table.length;
+
+/*
+    // Print table
+    wprintf("ca[] = '%.*s'\n", ca);
+    for (mid = 0; mid < high; mid++)
+    {
+        pca = table[mid];
+        wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+    }
+*/
+
+    // Do binary search
+    while (low < high)
+    {
+        mid = (low + high) >> 1;
+        pca = table[mid];
+        c = ca.length - pca.length;
+        if (c == 0)
+        {
+            c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof);
+            if (c == 0)
+            {   //printf("found %d\n", mid);
+                return mid;
+            }
+        }
+        if (c < 0)
+        {
+            high = mid;
+        }
+        else
+        {
+            low = mid + 1;
+        }
+    }
+    //printf("not found\n");
+    return -1;              // not found
+}
+
+
+unittest
+{
+    switch (cast(wchar []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
+
+
+/**********************************
+ * Same thing, but for wide chars.
+ */
+
+int _d_switch_dstring(dchar[][] table, dchar[] ca)
+in
+{
+    //printf("in _d_switch_dstring()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        int len1 = table[j - 1].length;
+        int len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int c;
+
+            c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof);
+            assert(c < 0);  // c==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int c;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
+                assert(c != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
+                if (c == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_ustring()\n");
+    int low;
+    int high;
+    int mid;
+    int c;
+    dchar[] pca;
+
+    low = 0;
+    high = table.length;
+
+/*
+    // Print table
+    wprintf("ca[] = '%.*s'\n", ca);
+    for (mid = 0; mid < high; mid++)
+    {
+        pca = table[mid];
+        wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+    }
+*/
+
+    // Do binary search
+    while (low < high)
+    {
+        mid = (low + high) >> 1;
+        pca = table[mid];
+        c = ca.length - pca.length;
+        if (c == 0)
+        {
+            c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof);
+            if (c == 0)
+            {   //printf("found %d\n", mid);
+                return mid;
+            }
+        }
+        if (c < 0)
+        {
+            high = mid;
+        }
+        else
+        {
+            low = mid + 1;
+        }
+    }
+    //printf("not found\n");
+    return -1; // not found
+}
+
+
+unittest
+{
+    switch (cast(dchar []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/trace.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,867 @@
+
+/* Trace dynamic profiler.
+ * For use with the Digital Mars DMD compiler.
+ * Copyright (C) 1995-2006 by Digital Mars
+ * All Rights Reserved
+ * Written by Walter Bright
+ * www.digitalmars.com
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.trace;
+
+private
+{
+    import util.string;
+    import stdc.ctype;
+    import stdc.stdio;
+    import stdc.string;
+    import stdc.stdlib;
+}
+
+extern (C):
+
+char* unmangle_ident(char*);    // from DMC++ runtime library
+
+alias long timer_t;
+
+/////////////////////////////////////
+//
+
+struct SymPair
+{
+    SymPair* next;
+    Symbol* sym;        // function that is called
+    uint count;         // number of times sym is called
+}
+
+/////////////////////////////////////
+// A Symbol for each function name.
+
+struct Symbol
+{
+        Symbol* Sl, Sr;         // left, right children
+        SymPair* Sfanin;        // list of calling functions
+        SymPair* Sfanout;       // list of called functions
+        timer_t totaltime;      // aggregate time
+        timer_t functime;       // time excluding subfunction calls
+        ubyte Sflags;
+        char[] Sident;          // name of symbol
+}
+
+const ubyte SFvisited = 1;      // visited
+
+static Symbol* root;            // root of symbol table
+
+//////////////////////////////////
+// Build a linked list of these.
+
+struct Stack
+{
+    Stack* prev;
+    Symbol* sym;
+    timer_t starttime;          // time when function was entered
+    timer_t ohd;                // overhead of all the bookkeeping code
+    timer_t subtime;            // time used by all subfunctions
+}
+
+static Stack* stack_freelist;
+static Stack* trace_tos;                // top of stack
+static int trace_inited;                // !=0 if initialized
+static timer_t trace_ohd;
+
+static Symbol** psymbols;
+static uint nsymbols;           // number of symbols
+
+static string trace_logfilename = "trace.log";
+static FILE* fplog;
+
+static string trace_deffilename = "trace.def";
+static FILE* fpdef;
+
+
+////////////////////////////////////////
+// Set file name for output.
+// A file name of "" means write results to stdout.
+// Returns:
+//      0       success
+//      !=0     failure
+
+int trace_setlogfilename(string name)
+{
+    trace_logfilename = name;
+    return 0;
+}
+
+////////////////////////////////////////
+// Set file name for output.
+// A file name of "" means write results to stdout.
+// Returns:
+//      0       success
+//      !=0     failure
+
+int trace_setdeffilename(string name)
+{
+    trace_deffilename = name;
+    return 0;
+}
+
+////////////////////////////////////////
+// Output optimal function link order.
+
+static void trace_order(Symbol *s)
+{
+    while (s)
+    {
+        trace_place(s,0);
+        if (s.Sl)
+            trace_order(s.Sl);
+        s = s.Sr;
+    }
+}
+
+//////////////////////////////////////////////
+//
+
+static Stack* stack_malloc()
+{   Stack *s;
+
+    if (stack_freelist)
+    {   s = stack_freelist;
+        stack_freelist = s.prev;
+    }
+    else
+        s = cast(Stack *)trace_malloc(Stack.sizeof);
+    return s;
+}
+
+//////////////////////////////////////////////
+//
+
+static void stack_free(Stack *s)
+{
+    s.prev = stack_freelist;
+    stack_freelist = s;
+}
+
+//////////////////////////////////////
+// Qsort() comparison routine for array of pointers to SymPair's.
+
+static int sympair_cmp(in void* e1, in void* e2)
+{   SymPair** psp1;
+    SymPair** psp2;
+
+    psp1 = cast(SymPair**)e1;
+    psp2 = cast(SymPair**)e2;
+
+    return (*psp2).count - (*psp1).count;
+}
+
+//////////////////////////////////////
+// Place symbol s, and then place any fan ins or fan outs with
+// counts greater than count.
+
+static void trace_place(Symbol *s, uint count)
+{   SymPair* sp;
+    SymPair** base;
+
+    if (!(s.Sflags & SFvisited))
+    {   size_t num;
+        uint u;
+
+        //printf("\t%.*s\t%u\n", s.Sident, count);
+        fprintf(fpdef,"\t%.*s\n", s.Sident);
+        s.Sflags |= SFvisited;
+
+        // Compute number of items in array
+        num = 0;
+        for (sp = s.Sfanin; sp; sp = sp.next)
+            num++;
+        for (sp = s.Sfanout; sp; sp = sp.next)
+            num++;
+        if (!num)
+            return;
+
+        // Allocate and fill array
+        base = cast(SymPair**)trace_malloc(SymPair.sizeof * num);
+        u = 0;
+        for (sp = s.Sfanin; sp; sp = sp.next)
+            base[u++] = sp;
+        for (sp = s.Sfanout; sp; sp = sp.next)
+            base[u++] = sp;
+
+        // Sort array
+        qsort(base, num, (SymPair *).sizeof, &sympair_cmp);
+
+        //for (u = 0; u < num; u++)
+            //printf("\t\t%.*s\t%u\n", base[u].sym.Sident, base[u].count);
+
+        // Place symbols
+        for (u = 0; u < num; u++)
+        {
+            if (base[u].count >= count)
+            {   uint u2;
+                uint c2;
+
+                u2 = (u + 1 < num) ? u + 1 : u;
+                c2 = base[u2].count;
+                if (c2 < count)
+                    c2 = count;
+                trace_place(base[u].sym,c2);
+            }
+            else
+                break;
+        }
+
+        // Clean up
+        trace_free(base);
+    }
+}
+
+/////////////////////////////////////
+// Initialize and terminate.
+
+static this()
+{
+    trace_init();
+}
+
+static ~this()
+{
+    trace_term();
+}
+
+///////////////////////////////////
+// Report results.
+// Also compute nsymbols.
+
+static void trace_report(Symbol* s)
+{   SymPair* sp;
+    uint count;
+
+    //printf("trace_report()\n");
+    while (s)
+    {   nsymbols++;
+        if (s.Sl)
+            trace_report(s.Sl);
+        fprintf(fplog,"------------------\n");
+        count = 0;
+        for (sp = s.Sfanin; sp; sp = sp.next)
+        {
+            fprintf(fplog,"\t%5d\t%.*s\n", sp.count, sp.sym.Sident);
+            count += sp.count;
+        }
+        fprintf(fplog,"%.*s\t%u\t%lld\t%lld\n",s.Sident,count,s.totaltime,s.functime);
+        for (sp = s.Sfanout; sp; sp = sp.next)
+        {
+            fprintf(fplog,"\t%5d\t%.*s\n",sp.count,sp.sym.Sident);
+        }
+        s = s.Sr;
+    }
+}
+
+////////////////////////////////////
+// Allocate and fill array of symbols.
+
+static void trace_array(Symbol *s)
+{   static uint u;
+
+    if (!psymbols)
+    {   u = 0;
+        psymbols = cast(Symbol **)trace_malloc((Symbol *).sizeof * nsymbols);
+    }
+    while (s)
+    {
+        psymbols[u++] = s;
+        trace_array(s.Sl);
+        s = s.Sr;
+    }
+}
+
+
+//////////////////////////////////////
+// Qsort() comparison routine for array of pointers to Symbol's.
+
+static int symbol_cmp(in void* e1, in void* e2)
+{   Symbol** ps1;
+    Symbol** ps2;
+    timer_t diff;
+
+    ps1 = cast(Symbol **)e1;
+    ps2 = cast(Symbol **)e2;
+
+    diff = (*ps2).functime - (*ps1).functime;
+    return (diff == 0) ? 0 : ((diff > 0) ? 1 : -1);
+}
+
+
+///////////////////////////////////
+// Report function timings
+
+static void trace_times(Symbol* root)
+{   uint u;
+    timer_t freq;
+
+    // Sort array
+    qsort(psymbols, nsymbols, (Symbol *).sizeof, &symbol_cmp);
+
+    // Print array
+    QueryPerformanceFrequency(&freq);
+    fprintf(fplog,"\n======== Timer Is %lld Ticks/Sec, Times are in Microsecs ========\n\n",freq);
+    fprintf(fplog,"  Num          Tree        Func        Per\n");
+    fprintf(fplog,"  Calls        Time        Time        Call\n\n");
+    for (u = 0; u < nsymbols; u++)
+    {   Symbol* s = psymbols[u];
+        timer_t tl,tr;
+        timer_t fl,fr;
+        timer_t pl,pr;
+        timer_t percall;
+        SymPair* sp;
+        uint calls;
+        char[] id;
+
+        version (Windows)
+        {
+            char* p = (s.Sident ~ '\0').ptr;
+            p = unmangle_ident(p);
+            if (p)
+                id = p[0 .. strlen(p)];
+        }
+        if (!id)
+            id = s.Sident;
+        calls = 0;
+        for (sp = s.Sfanin; sp; sp = sp.next)
+            calls += sp.count;
+        if (calls == 0)
+            calls = 1;
+
+version (all)
+{
+        tl = (s.totaltime * 1000000) / freq;
+        fl = (s.functime  * 1000000) / freq;
+        percall = s.functime / calls;
+        pl = (s.functime * 1000000) / calls / freq;
+
+        fprintf(fplog,"%7d%12lld%12lld%12lld     %.*s\n",
+            calls,tl,fl,pl,id);
+}
+else
+{
+        tl = s.totaltime / freq;
+        tr = ((s.totaltime - tl * freq) * 10000000) / freq;
+
+        fl = s.functime  / freq;
+        fr = ((s.functime  - fl * freq) * 10000000) / freq;
+
+        percall = s.functime / calls;
+        pl = percall  / freq;
+        pr = ((percall  - pl * freq) * 10000000) / freq;
+
+        fprintf(fplog,"%7d\t%3lld.%07lld\t%3lld.%07lld\t%3lld.%07lld\t%.*s\n",
+            calls,tl,tr,fl,fr,pl,pr,id);
+}
+        if (id !is s.Sident)
+            free(id.ptr);
+    }
+}
+
+
+///////////////////////////////////
+// Initialize.
+
+static void trace_init()
+{
+    if (!trace_inited)
+    {
+        trace_inited = 1;
+
+        {   // See if we can determine the overhead.
+            uint u;
+            timer_t starttime;
+            timer_t endtime;
+            Stack *st;
+
+            st = trace_tos;
+            trace_tos = null;
+            QueryPerformanceCounter(&starttime);
+            for (u = 0; u < 100; u++)
+            {
+                asm
+                {
+                    call _trace_pro_n   ;
+                    db   0              ;
+                    call _trace_epi_n   ;
+                }
+            }
+            QueryPerformanceCounter(&endtime);
+            trace_ohd = (endtime - starttime) / u;
+            //printf("trace_ohd = %lld\n",trace_ohd);
+            if (trace_ohd > 0)
+                trace_ohd--;            // round down
+            trace_tos = st;
+        }
+    }
+}
+
+/////////////////////////////////
+// Terminate.
+
+void trace_term()
+{
+    //printf("trace_term()\n");
+    if (trace_inited == 1)
+    {   Stack *n;
+
+        trace_inited = 2;
+
+        // Free remainder of the stack
+        while (trace_tos)
+        {
+            n = trace_tos.prev;
+            stack_free(trace_tos);
+            trace_tos = n;
+        }
+
+        while (stack_freelist)
+        {
+            n = stack_freelist.prev;
+            stack_free(stack_freelist);
+            stack_freelist = n;
+        }
+
+        // Merge in data from any existing file
+        trace_merge();
+
+        // Report results
+        fplog = fopen(trace_logfilename.ptr, "w");
+        if (fplog)
+        {   nsymbols = 0;
+            trace_report(root);
+            trace_array(root);
+            trace_times(root);
+            fclose(fplog);
+        }
+
+        // Output function link order
+        fpdef = fopen(trace_deffilename.ptr,"w");
+        if (fpdef)
+        {   fprintf(fpdef,"\nFUNCTIONS\n");
+            trace_order(root);
+            fclose(fpdef);
+        }
+
+        trace_free(psymbols);
+        psymbols = null;
+    }
+}
+
+/////////////////////////////////
+// Our storage allocator.
+
+static void *trace_malloc(size_t nbytes)
+{   void *p;
+
+    p = malloc(nbytes);
+    if (!p)
+        exit(EXIT_FAILURE);
+    return p;
+}
+
+static void trace_free(void *p)
+{
+    free(p);
+}
+
+//////////////////////////////////////////////
+//
+
+static Symbol* trace_addsym(char[] id)
+{
+    Symbol** parent;
+    Symbol* rover;
+    Symbol* s;
+    int cmp;
+    char c;
+
+    //printf("trace_addsym('%s',%d)\n",p,len);
+    parent = &root;
+    rover = *parent;
+    while (rover !is null)               // while we haven't run out of tree
+    {
+        cmp = dstrcmp(id, rover.Sident);
+        if (cmp == 0)
+        {
+            return rover;
+        }
+        parent = (cmp < 0) ?            /* if we go down left side      */
+            &(rover.Sl) :               /* then get left child          */
+            &(rover.Sr);                /* else get right child         */
+        rover = *parent;                /* get child                    */
+    }
+    /* not in table, so insert into table       */
+    s = cast(Symbol *)trace_malloc(Symbol.sizeof);
+    memset(s,0,Symbol.sizeof);
+    s.Sident = id;
+    *parent = s;                        // link new symbol into tree
+    return s;
+}
+
+/***********************************
+ * Add symbol s with count to SymPair list.
+ */
+
+static void trace_sympair_add(SymPair** psp, Symbol* s, uint count)
+{   SymPair* sp;
+
+    for (; 1; psp = &sp.next)
+    {
+        sp = *psp;
+        if (!sp)
+        {
+            sp = cast(SymPair *)trace_malloc(SymPair.sizeof);
+            sp.sym = s;
+            sp.count = 0;
+            sp.next = null;
+            *psp = sp;
+            break;
+        }
+        else if (sp.sym == s)
+        {
+            break;
+        }
+    }
+    sp.count += count;
+}
+
+//////////////////////////////////////////////
+//
+
+static void trace_pro(char[] id)
+{
+    Stack* n;
+    Symbol* s;
+    timer_t starttime;
+    timer_t t;
+
+    QueryPerformanceCounter(&starttime);
+    if (id.length == 0)
+        return;
+    if (!trace_inited)
+        trace_init();                   // initialize package
+    n = stack_malloc();
+    n.prev = trace_tos;
+    trace_tos = n;
+    s = trace_addsym(id);
+    trace_tos.sym = s;
+    if (trace_tos.prev)
+    {
+        Symbol* prev;
+        int i;
+
+        // Accumulate Sfanout and Sfanin
+        prev = trace_tos.prev.sym;
+        trace_sympair_add(&prev.Sfanout,s,1);
+        trace_sympair_add(&s.Sfanin,prev,1);
+    }
+    QueryPerformanceCounter(&t);
+    trace_tos.starttime = starttime;
+    trace_tos.ohd = trace_ohd + t - starttime;
+    trace_tos.subtime = 0;
+    //printf("trace_tos.ohd=%lld, trace_ohd=%lld + t=%lld - starttime=%lld\n",
+    //  trace_tos.ohd,trace_ohd,t,starttime);
+}
+
+/////////////////////////////////////////
+//
+
+static void trace_epi()
+{   Stack* n;
+    timer_t endtime;
+    timer_t t;
+    timer_t ohd;
+
+    //printf("trace_epi()\n");
+    if (trace_tos)
+    {
+        timer_t starttime;
+        timer_t totaltime;
+
+        QueryPerformanceCounter(&endtime);
+        starttime = trace_tos.starttime;
+        totaltime = endtime - starttime - trace_tos.ohd;
+        if (totaltime < 0)
+        {   //printf("endtime=%lld - starttime=%lld - trace_tos.ohd=%lld < 0\n",
+            //  endtime,starttime,trace_tos.ohd);
+            totaltime = 0;              // round off error, just make it 0
+        }
+
+        // totaltime is time spent in this function + all time spent in
+        // subfunctions - bookkeeping overhead.
+        trace_tos.sym.totaltime += totaltime;
+
+        //if (totaltime < trace_tos.subtime)
+        //printf("totaltime=%lld < trace_tos.subtime=%lld\n",totaltime,trace_tos.subtime);
+        trace_tos.sym.functime  += totaltime - trace_tos.subtime;
+        ohd = trace_tos.ohd;
+        n = trace_tos.prev;
+        stack_free(trace_tos);
+        trace_tos = n;
+        if (n)
+        {   QueryPerformanceCounter(&t);
+            n.ohd += ohd + t - endtime;
+            n.subtime += totaltime;
+            //printf("n.ohd = %lld\n",n.ohd);
+        }
+    }
+}
+
+
+////////////////////////// FILE INTERFACE /////////////////////////
+
+/////////////////////////////////////
+// Read line from file fp.
+// Returns:
+//      trace_malloc'd line buffer
+//      null if end of file
+
+static char* trace_readline(FILE* fp)
+{   int c;
+    int dim;
+    int i;
+    char *buf;
+
+    //printf("trace_readline(%p)\n", fp);
+    i = 0;
+    dim = 0;
+    buf = null;
+    while (1)
+    {
+        if (i == dim)
+        {   char *p;
+
+            dim += 80;
+            p = cast(char *)trace_malloc(dim);
+            memcpy(p,buf,i);
+            trace_free(buf);
+            buf = p;
+        }
+        c = fgetc(fp);
+        switch (c)
+        {
+            case EOF:
+                if (i == 0)
+                {   trace_free(buf);
+                    return null;
+                }
+            case '\n':
+                goto L1;
+            default:
+                break;
+        }
+        buf[i] = cast(char)c;
+        i++;
+    }
+L1:
+    buf[i] = 0;
+    //printf("line '%s'\n",buf);
+    return buf;
+}
+
+//////////////////////////////////////
+// Skip space
+
+static char *skipspace(char *p)
+{
+    while (isspace(*p))
+        p++;
+    return p;
+}
+
+////////////////////////////////////////////////////////
+// Merge in profiling data from existing file.
+
+static void trace_merge()
+{   FILE *fp;
+    char *buf;
+    char *p;
+    uint count;
+    Symbol *s;
+    SymPair *sfanin;
+    SymPair **psp;
+
+    if (trace_logfilename && (fp = fopen(trace_logfilename.ptr,"r")) !is null)
+    {
+        buf = null;
+        sfanin = null;
+        psp = &sfanin;
+        while (1)
+        {
+            trace_free(buf);
+            buf = trace_readline(fp);
+            if (!buf)
+                break;
+            switch (*buf)
+            {
+                case '=':               // ignore rest of file
+                    trace_free(buf);
+                    goto L1;
+                case ' ':
+                case '\t':              // fan in or fan out line
+                    count = strtoul(buf,&p,10);
+                    if (p == buf)       // if invalid conversion
+                        continue;
+                    p = skipspace(p);
+                    if (!*p)
+                        continue;
+                    s = trace_addsym(p[0 .. strlen(p)]);
+                    trace_sympair_add(psp,s,count);
+                    break;
+                default:
+                    if (!isalpha(*buf))
+                    {
+                        if (!sfanin)
+                            psp = &sfanin;
+                        continue;       // regard unrecognized line as separator
+                    }
+                case '?':
+                case '_':
+                case '$':
+                case '@':
+                    p = buf;
+                    while (isgraph(*p))
+                        p++;
+                    *p = 0;
+                    //printf("trace_addsym('%s')\n",buf);
+                    s = trace_addsym(buf[0 .. strlen(buf)]);
+                    if (s.Sfanin)
+                    {   SymPair *sp;
+
+                        for (; sfanin; sfanin = sp)
+                        {
+                            trace_sympair_add(&s.Sfanin,sfanin.sym,sfanin.count);
+                            sp = sfanin.next;
+                            trace_free(sfanin);
+                        }
+                    }
+                    else
+                    {   s.Sfanin = sfanin;
+                    }
+                    sfanin = null;
+                    psp = &s.Sfanout;
+
+                    {   timer_t t;
+
+                        p++;
+                        count = strtoul(p,&p,10);
+                        t = cast(long)strtoull(p,&p,10);
+                        s.totaltime += t;
+                        t = cast(long)strtoull(p,&p,10);
+                        s.functime += t;
+                    }
+                    break;
+            }
+        }
+    L1:
+        fclose(fp);
+    }
+}
+
+////////////////////////// COMPILER INTERFACE /////////////////////
+
+/////////////////////////////////////////////
+// Function called by trace code in function prolog.
+
+void _trace_pro_n()
+{
+    /* Length of string is either:
+     *  db      length
+     *  ascii   string
+     * or:
+     *  db      0x0FF
+     *  db      0
+     *  dw      length
+     *  ascii   string
+     */
+
+    asm
+    {   naked                           ;
+        pushad                          ;
+        mov     ECX,8*4[ESP]            ;
+        xor     EAX,EAX                 ;
+        mov     AL,[ECX]                ;
+        cmp     AL,0xFF                 ;
+        jne     L1                      ;
+        cmp     byte ptr 1[ECX],0       ;
+        jne     L1                      ;
+        mov     AX,2[ECX]               ;
+        add     8*4[ESP],3              ;
+        add     ECX,3                   ;
+    L1: inc     EAX                     ;
+        inc     ECX                     ;
+        add     8*4[ESP],EAX            ;
+        dec     EAX                     ;
+        push    ECX                     ;
+        push    EAX                     ;
+        call    trace_pro               ;
+        add     ESP,8                   ;
+        popad                           ;
+        ret                             ;
+    }
+}
+
+/////////////////////////////////////////////
+// Function called by trace code in function epilog.
+
+
+void _trace_epi_n()
+{
+    asm
+    {   naked   ;
+        pushad  ;
+    }
+    trace_epi();
+    asm
+    {
+        popad   ;
+        ret     ;
+    }
+}
+
+
+version (Windows)
+{
+    extern (Windows)
+    {
+        export int QueryPerformanceCounter(timer_t *);
+        export int QueryPerformanceFrequency(timer_t *);
+    }
+}
+else version (X86)
+{
+    extern (D)
+    {
+        void QueryPerformanceCounter(timer_t* ctr)
+        {
+            asm
+            {   naked                   ;
+                mov       ECX,EAX       ;
+                rdtsc                   ;
+                mov   [ECX],EAX         ;
+                mov   4[ECX],EDX        ;
+                ret                     ;
+            }
+        }
+
+        void QueryPerformanceFrequency(timer_t* freq)
+        {
+            *freq = 3579545;
+        }
+    }
+}
+else
+{
+    static assert(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_AC.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,95 @@
+module rt.typeinfo.ti_AC;
+
+// Object[]
+
+class TypeInfo_AC : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {   Object[] s = *cast(Object[]*)p;
+        hash_t hash = 0;
+
+        foreach (Object o; s)
+        {
+            if (o)
+                hash += o.toHash();
+        }
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Object[] s1 = *cast(Object[]*)p1;
+        Object[] s2 = *cast(Object[]*)p2;
+
+        if (s1.length == s2.length)
+        {
+            for (size_t u = 0; u < s1.length; u++)
+            {   Object o1 = s1[u];
+                Object o2 = s2[u];
+
+                // Do not pass null's to Object.opEquals()
+                if (o1 is o2 ||
+                    (!(o1 is null) && !(o2 is null) && o1.opEquals(o2)))
+                    continue;
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object[] s1 = *cast(Object[]*)p1;
+        Object[] s2 = *cast(Object[]*)p2;
+        ptrdiff_t c;
+
+        c = cast(ptrdiff_t)s1.length - cast(ptrdiff_t)s2.length;
+        if (c == 0)
+        {
+            for (size_t u = 0; u < s1.length; u++)
+            {   Object o1 = s1[u];
+                Object o2 = s2[u];
+
+                if (o1 is o2)
+                    continue;
+
+                // Regard null references as always being "less than"
+                if (o1)
+                {
+                    if (!o2)
+                    {   c = 1;
+                        break;
+                    }
+                    c = o1.opCmp(o2);
+                    if (c)
+                        break;
+                }
+                else
+                {   c = -1;
+                    break;
+                }
+            }
+        }
+        if (c < 0)
+            c = -1;
+        else if (c > 0)
+            c = 1;
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return (Object[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(Object);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Acdouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,105 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Acdouble;
+
+private import typeinfo.ti_cdouble;
+
+// cdouble[]
+
+class TypeInfo_Ar : TypeInfo
+{
+    override string toString() { return "cdouble[]"; }
+
+    override hash_t getHash(in void* p)
+    {   cdouble[] s = *cast(cdouble[]*)p;
+        size_t len = s.length;
+        cdouble *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(uint *)str)[2];
+            hash += (cast(uint *)str)[3];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        cdouble[] s1 = *cast(cdouble[]*)p1;
+        cdouble[] s2 = *cast(cdouble[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_r._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        cdouble[] s1 = *cast(cdouble[]*)p1;
+        cdouble[] s2 = *cast(cdouble[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_r._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (cdouble[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(cdouble);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Acfloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Acfloat;
+
+private import typeinfo.ti_cfloat;
+
+// cfloat[]
+
+class TypeInfo_Aq : TypeInfo
+{
+    override string toString() { return "cfloat[]"; }
+
+    override hash_t getHash(in void* p)
+    {   cfloat[] s = *cast(cfloat[]*)p;
+        size_t len = s.length;
+        cfloat *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        cfloat[] s1 = *cast(cfloat[]*)p1;
+        cfloat[] s2 = *cast(cfloat[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_q._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        cfloat[] s1 = *cast(cfloat[]*)p1;
+        cfloat[] s2 = *cast(cfloat[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_q._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (cfloat[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(cfloat);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Acreal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,106 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Acreal;
+
+private import typeinfo.ti_creal;
+
+// creal[]
+
+class TypeInfo_Ac : TypeInfo
+{
+    override string toString() { return "creal[]"; }
+
+    override hash_t getHash(in void* p)
+    {   creal[] s = *cast(creal[]*)p;
+        size_t len = s.length;
+        creal *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(uint *)str)[2];
+            hash += (cast(uint *)str)[3];
+            hash += (cast(uint *)str)[4];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        creal[] s1 = *cast(creal[]*)p1;
+        creal[] s2 = *cast(creal[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_c._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        creal[] s1 = *cast(creal[]*)p1;
+        creal[] s2 = *cast(creal[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_c._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (creal[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(creal);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Adouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Adouble;
+
+private import typeinfo.ti_double;
+
+// double[]
+
+class TypeInfo_Ad : TypeInfo
+{
+    override string toString() { return "double[]"; }
+
+    override hash_t getHash(in void* p)
+    {   double[] s = *cast(double[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        double[] s1 = *cast(double[]*)p1;
+        double[] s2 = *cast(double[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_d._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        double[] s1 = *cast(double[]*)p1;
+        double[] s2 = *cast(double[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_d._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (double[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(double);
+    }
+}
+
+// idouble[]
+
+class TypeInfo_Ap : TypeInfo_Ad
+{
+    override string toString() { return "idouble[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(idouble);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Afloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,114 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Afloat;
+
+private import typeinfo.ti_float;
+
+// float[]
+
+class TypeInfo_Af : TypeInfo
+{
+    override string toString() { return "float[]"; }
+
+    override hash_t getHash(in void* p)
+    {   float[] s = *cast(float[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str;
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        float[] s1 = *cast(float[]*)p1;
+        float[] s2 = *cast(float[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_f._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        float[] s1 = *cast(float[]*)p1;
+        float[] s2 = *cast(float[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_f._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (float[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(float);
+    }
+}
+
+// ifloat[]
+
+class TypeInfo_Ao : TypeInfo_Af
+{
+    override string toString() { return "ifloat[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(ifloat);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Ag.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,204 @@
+
+module rt.typeinfo.ti_Ag;
+
+private import util.string;
+private import stdc.string;
+
+// byte[]
+
+class TypeInfo_Ag : TypeInfo
+{
+    override string toString() { return "byte[]"; }
+
+    override hash_t getHash(in void* p)
+    {   byte[] s = *cast(byte[]*)p;
+        size_t len = s.length;
+        byte *str = s.ptr;
+        hash_t hash = 0;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ubyte *)str;
+                    return hash;
+
+                case 2:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                case 3:
+                    hash *= 9;
+                    hash += (*cast(ushort *)str << 8) +
+                            (cast(ubyte *)str)[2];
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 4;
+                    len -= 4;
+                    break;
+            }
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        byte[] s1 = *cast(byte[]*)p1;
+        byte[] s2 = *cast(byte[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(byte *)s1, cast(byte *)s2, s1.length) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        byte[] s1 = *cast(byte[]*)p1;
+        byte[] s2 = *cast(byte[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (byte[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(byte);
+    }
+}
+
+
+// ubyte[]
+
+class TypeInfo_Ah : TypeInfo_Ag
+{
+    override string toString() { return "ubyte[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        char[] s1 = *cast(char[]*)p1;
+        char[] s2 = *cast(char[]*)p2;
+
+        return dstrcmp(s1, s2);
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ubyte);
+    }
+}
+
+// void[]
+
+class TypeInfo_Av : TypeInfo_Ah
+{
+    override string toString() { return "void[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(void);
+    }
+}
+
+// bool[]
+
+class TypeInfo_Ab : TypeInfo_Ah
+{
+    override string toString() { return "bool[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(bool);
+    }
+}
+
+// char[]
+
+class TypeInfo_Aa : TypeInfo_Ag
+{
+    override string toString() { return "char[]"; }
+
+    override hash_t getHash(in void* p)
+    {   char[] s = *cast(char[]*)p;
+        hash_t hash = 0;
+
+version (all)
+{
+        foreach (char c; s)
+            hash = hash * 11 + c;
+}
+else
+{
+        size_t len = s.length;
+        char *str = s;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ubyte *)str;
+                    return hash;
+
+                case 2:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                case 3:
+                    hash *= 9;
+                    hash += (*cast(ushort *)str << 8) +
+                            (cast(ubyte *)str)[2];
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 4;
+                    len -= 4;
+                    break;
+            }
+        }
+}
+        return hash;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(char);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Aint.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,129 @@
+
+module rt.typeinfo.ti_Aint;
+
+private import stdc.string;
+
+// int[]
+
+class TypeInfo_Ai : TypeInfo
+{
+    override string toString() { return "int[]"; }
+
+    override hash_t getHash(in void* p)
+    {   int[] s = *cast(int[]*)p;
+        auto len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str;
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        int[] s1 = *cast(int[]*)p1;
+        int[] s2 = *cast(int[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * int.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        int[] s1 = *cast(int[]*)p1;
+        int[] s2 = *cast(int[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (int[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(int);
+    }
+}
+
+unittest
+{
+    int[][] a = [[5,3,8,7], [2,5,3,8,7]];
+    a.sort;
+    assert(a == [[2,5,3,8,7], [5,3,8,7]]);
+
+    a = [[5,3,8,7], [5,3,8]];
+    a.sort;
+    assert(a == [[5,3,8], [5,3,8,7]]);
+}
+
+// uint[]
+
+class TypeInfo_Ak : TypeInfo_Ai
+{
+    override string toString() { return "uint[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        uint[] s1 = *cast(uint[]*)p1;
+        uint[] s2 = *cast(uint[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(uint);
+    }
+}
+
+// dchar[]
+
+class TypeInfo_Aw : TypeInfo_Ak
+{
+    override string toString() { return "dchar[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(dchar);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Along.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,109 @@
+
+module rt.typeinfo.ti_Along;
+
+private import stdc.string;
+
+// long[]
+
+class TypeInfo_Al : TypeInfo
+{
+    override string toString() { return "long[]"; }
+
+    override hash_t getHash(in void* p)
+    {   long[] s = *cast(long[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str + *(cast(uint *)str + 1);
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        long[] s1 = *cast(long[]*)p1;
+        long[] s2 = *cast(long[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * long.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        long[] s1 = *cast(long[]*)p1;
+        long[] s2 = *cast(long[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (s1[u] < s2[u])
+                return -1;
+            else if (s1[u] > s2[u])
+                return 1;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (long[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(long);
+    }
+}
+
+
+// ulong[]
+
+class TypeInfo_Am : TypeInfo_Al
+{
+    override string toString() { return "ulong[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        ulong[] s1 = *cast(ulong[]*)p1;
+        ulong[] s2 = *cast(ulong[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (s1[u] < s2[u])
+                return -1;
+            else if (s1[u] > s2[u])
+                return 1;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ulong);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Areal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,116 @@
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Areal;
+
+private import typeinfo.ti_real;
+
+// real[]
+
+class TypeInfo_Ae : TypeInfo
+{
+    override string toString() { return "real[]"; }
+
+    override hash_t getHash(in void* p)
+    {   real[] s = *cast(real[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(ushort *)str)[4];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        real[] s1 = *cast(real[]*)p1;
+        real[] s2 = *cast(real[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_e._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        real[] s1 = *cast(real[]*)p1;
+        real[] s2 = *cast(real[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_e._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (real[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(real);
+    }
+}
+
+// ireal[]
+
+class TypeInfo_Aj : TypeInfo_Ae
+{
+    override string toString() { return "ireal[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(ireal);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_Ashort.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,132 @@
+
+module rt.typeinfo.ti_Ashort;
+
+private import stdc.string;
+
+// short[]
+
+class TypeInfo_As : TypeInfo
+{
+    override string toString() { return "short[]"; }
+
+    override hash_t getHash(in void* p)
+    {   short[] s = *cast(short[]*)p;
+        size_t len = s.length;
+        short *str = s.ptr;
+        hash_t hash = 0;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 2;
+                    len -= 2;
+                    break;
+            }
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        short[] s1 = *cast(short[]*)p1;
+        short[] s2 = *cast(short[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * short.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        short[] s1 = *cast(short[]*)p1;
+        short[] s2 = *cast(short[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (short[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(short);
+    }
+}
+
+
+// ushort[]
+
+class TypeInfo_At : TypeInfo_As
+{
+    override string toString() { return "ushort[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        ushort[] s1 = *cast(ushort[]*)p1;
+        ushort[] s2 = *cast(ushort[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ushort);
+    }
+}
+
+// wchar[]
+
+class TypeInfo_Au : TypeInfo_At
+{
+    override string toString() { return "wchar[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(wchar);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_C.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_C;
+
+// Object
+
+class TypeInfo_C : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {
+        Object o = *cast(Object*)p;
+        return o ? o.toHash() : 0;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+
+        return o1 == o2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (!(o1 is o2))
+        {
+            if (o1)
+            {   if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_byte.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,38 @@
+
+// byte
+
+module rt.typeinfo.ti_byte;
+
+class TypeInfo_g : TypeInfo
+{
+    override string toString() { return "byte"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(byte *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return byte.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        byte t;
+
+        t = *cast(byte *)p1;
+        *cast(byte *)p1 = *cast(byte *)p2;
+        *cast(byte *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_cdouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,66 @@
+
+// cdouble
+
+module rt.typeinfo.ti_cdouble;
+
+class TypeInfo_r : TypeInfo
+{
+    override string toString() { return "cdouble"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+               (cast(uint *)p)[2] + (cast(uint *)p)[3];
+    }
+
+    static equals_t _equals(cdouble f1, cdouble f2)
+    {
+        return f1 == f2;
+    }
+
+    static int _compare(cdouble f1, cdouble f2)
+    {   int result;
+
+        if (f1.re < f2.re)
+            result = -1;
+        else if (f1.re > f2.re)
+            result = 1;
+        else if (f1.im < f2.im)
+            result = -1;
+        else if (f1.im > f2.im)
+            result = 1;
+        else
+            result = 0;
+        return result;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return cdouble.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        cdouble t;
+
+        t = *cast(cdouble *)p1;
+        *cast(cdouble *)p1 = *cast(cdouble *)p2;
+        *cast(cdouble *)p2 = t;
+    }
+
+    override void[] init()
+    {   static cdouble r;
+
+        return (cast(cdouble *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_cfloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,65 @@
+
+// cfloat
+
+module rt.typeinfo.ti_cfloat;
+
+class TypeInfo_q : TypeInfo
+{
+    override string toString() { return "cfloat"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static equals_t _equals(cfloat f1, cfloat f2)
+    {
+        return f1 == f2;
+    }
+
+    static int _compare(cfloat f1, cfloat f2)
+    {   int result;
+
+        if (f1.re < f2.re)
+            result = -1;
+        else if (f1.re > f2.re)
+            result = 1;
+        else if (f1.im < f2.im)
+            result = -1;
+        else if (f1.im > f2.im)
+            result = 1;
+        else
+            result = 0;
+        return result;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return cfloat.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        cfloat t;
+
+        t = *cast(cfloat *)p1;
+        *cast(cfloat *)p1 = *cast(cfloat *)p2;
+        *cast(cfloat *)p2 = t;
+    }
+
+    override void[] init()
+    {   static cfloat r;
+
+        return (cast(cfloat *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_char.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+module rt.typeinfo.ti_char;
+
+class TypeInfo_a : TypeInfo
+{
+    override string toString() { return "char"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(char *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(char *)p1 == *cast(char *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(char *)p1 - *cast(char *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return char.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        char t;
+
+        t = *cast(char *)p1;
+        *cast(char *)p1 = *cast(char *)p2;
+        *cast(char *)p2 = t;
+    }
+
+    override void[] init()
+    {   static char c;
+
+        return (cast(char *)&c)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_creal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,67 @@
+
+// creal
+
+module rt.typeinfo.ti_creal;
+
+class TypeInfo_c : TypeInfo
+{
+    override string toString() { return "creal"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+               (cast(uint *)p)[2] + (cast(uint *)p)[3] +
+               (cast(uint *)p)[4];
+    }
+
+    static equals_t _equals(creal f1, creal f2)
+    {
+        return f1 == f2;
+    }
+
+    static int _compare(creal f1, creal f2)
+    {   int result;
+
+        if (f1.re < f2.re)
+            result = -1;
+        else if (f1.re > f2.re)
+            result = 1;
+        else if (f1.im < f2.im)
+            result = -1;
+        else if (f1.im > f2.im)
+            result = 1;
+        else
+            result = 0;
+        return result;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return creal.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        creal t;
+
+        t = *cast(creal *)p1;
+        *cast(creal *)p1 = *cast(creal *)p2;
+        *cast(creal *)p2 = t;
+    }
+
+    override void[] init()
+    {   static creal r;
+
+        return (cast(creal *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_dchar.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,44 @@
+
+// dchar
+
+module rt.typeinfo.ti_dchar;
+
+class TypeInfo_w : TypeInfo
+{
+    override string toString() { return "dchar"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(dchar *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(dchar *)p1 == *cast(dchar *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(dchar *)p1 - *cast(dchar *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return dchar.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        dchar t;
+
+        t = *cast(dchar *)p1;
+        *cast(dchar *)p1 = *cast(dchar *)p2;
+        *cast(dchar *)p2 = t;
+    }
+
+    override void[] init()
+    {   static dchar c;
+
+        return (cast(dchar *)&c)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_delegate.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,39 @@
+
+// delegate
+
+module rt.typeinfo.ti_delegate;
+
+alias void delegate(int) dg;
+
+class TypeInfo_D : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {   long l = *cast(long *)p;
+
+        return cast(uint)(l + (l >> 32));
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(dg *)p1 == *cast(dg *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return dg.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        dg t;
+
+        t = *cast(dg *)p1;
+        *cast(dg *)p1 = *cast(dg *)p2;
+        *cast(dg *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_double.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,64 @@
+
+// double
+
+module rt.typeinfo.ti_double;
+
+class TypeInfo_d : TypeInfo
+{
+    override string toString() { return "double"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static equals_t _equals(double f1, double f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(double d1, double d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(double *)p1, *cast(double *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(double *)p1, *cast(double *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return double.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        double t;
+
+        t = *cast(double *)p1;
+        *cast(double *)p1 = *cast(double *)p2;
+        *cast(double *)p2 = t;
+    }
+
+    override void[] init()
+    {   static double r;
+
+        return (cast(double *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_float.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,64 @@
+
+// float
+
+module rt.typeinfo.ti_float;
+
+class TypeInfo_f : TypeInfo
+{
+    override string toString() { return "float"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    static equals_t _equals(float f1, float f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(float d1, float d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(float *)p1, *cast(float *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(float *)p1, *cast(float *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return float.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        float t;
+
+        t = *cast(float *)p1;
+        *cast(float *)p1 = *cast(float *)p2;
+        *cast(float *)p2 = t;
+    }
+
+    override void[] init()
+    {   static float r;
+
+        return (cast(float *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_idouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,11 @@
+
+// idouble
+
+module rt.typeinfo.ti_idouble;
+
+private import typeinfo.ti_double;
+
+class TypeInfo_p : TypeInfo_d
+{
+    override string toString() { return "idouble"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_ifloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,11 @@
+
+// ifloat
+
+module rt.typeinfo.ti_ifloat;
+
+private import typeinfo.ti_float;
+
+class TypeInfo_o : TypeInfo_f
+{
+    override string toString() { return "ifloat"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_int.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+// int
+
+module rt.typeinfo.ti_int;
+
+class TypeInfo_i : TypeInfo
+{
+    override string toString() { return "int"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(int*) p1 < *cast(int*) p2)
+            return -1;
+        else if (*cast(int*) p1 > *cast(int*) p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return int.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        int t;
+
+        t = *cast(int *)p1;
+        *cast(int *)p1 = *cast(int *)p2;
+        *cast(int *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_ireal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,11 @@
+
+// ireal
+
+module rt.typeinfo.ti_ireal;
+
+private import typeinfo.ti_real;
+
+class TypeInfo_j : TypeInfo_e
+{
+    override string toString() { return "ireal"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_long.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+// long
+
+module rt.typeinfo.ti_long;
+
+class TypeInfo_l : TypeInfo
+{
+    override string toString() { return "long"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p + (cast(uint *)p)[1];
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(long *)p1 == *cast(long *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(long *)p1 < *cast(long *)p2)
+            return -1;
+        else if (*cast(long *)p1 > *cast(long *)p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return long.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        long t;
+
+        t = *cast(long *)p1;
+        *cast(long *)p1 = *cast(long *)p2;
+        *cast(long *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_ptr.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,46 @@
+
+// pointer
+
+module rt.typeinfo.ti_ptr;
+
+class TypeInfo_P : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {
+        return cast(uint)*cast(void* *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(void* *)p1 == *cast(void* *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        auto c = *cast(void* *)p1 - *cast(void* *)p2;
+        if (c < 0)
+            return -1;
+        else if (c > 0)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (void*).sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        void* t;
+
+        t = *cast(void* *)p1;
+        *cast(void* *)p1 = *cast(void* *)p2;
+        *cast(void* *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_real.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,64 @@
+
+// real
+
+module rt.typeinfo.ti_real;
+
+class TypeInfo_e : TypeInfo
+{
+    override string toString() { return "real"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] + (cast(ushort *)p)[4];
+    }
+
+    static equals_t _equals(real f1, real f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(real d1, real d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(real *)p1, *cast(real *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(real *)p1, *cast(real *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return real.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        real t;
+
+        t = *cast(real *)p1;
+        *cast(real *)p1 = *cast(real *)p2;
+        *cast(real *)p2 = t;
+    }
+
+    override void[] init()
+    {   static real r;
+
+        return (cast(real *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_short.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,38 @@
+
+// short
+
+module rt.typeinfo.ti_short;
+
+class TypeInfo_s : TypeInfo
+{
+    override string toString() { return "short"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(short *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(short *)p1 == *cast(short *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(short *)p1 - *cast(short *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return short.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        short t;
+
+        t = *cast(short *)p1;
+        *cast(short *)p1 = *cast(short *)p2;
+        *cast(short *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_ubyte.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,43 @@
+
+// ubyte
+
+module rt.typeinfo.ti_ubyte;
+
+class TypeInfo_h : TypeInfo
+{
+    override string toString() { return "ubyte"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(ubyte *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ubyte *)p1 == *cast(ubyte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(ubyte *)p1 - *cast(ubyte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return ubyte.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ubyte t;
+
+        t = *cast(ubyte *)p1;
+        *cast(ubyte *)p1 = *cast(ubyte *)p2;
+        *cast(ubyte *)p2 = t;
+    }
+}
+
+class TypeInfo_b : TypeInfo_h
+{
+    override string toString() { return "bool"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_uint.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+// uint
+
+module rt.typeinfo.ti_uint;
+
+class TypeInfo_k : TypeInfo
+{
+    override string toString() { return "uint"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(uint*) p1 < *cast(uint*) p2)
+            return -1;
+        else if (*cast(uint*) p1 > *cast(uint*) p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return uint.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        int t;
+
+        t = *cast(uint *)p1;
+        *cast(uint *)p1 = *cast(uint *)p2;
+        *cast(uint *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_ulong.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+// ulong
+
+module rt.typeinfo.ti_ulong;
+
+class TypeInfo_m : TypeInfo
+{
+    override string toString() { return "ulong"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p + (cast(uint *)p)[1];
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ulong *)p1 == *cast(ulong *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(ulong *)p1 < *cast(ulong *)p2)
+            return -1;
+        else if (*cast(ulong *)p1 > *cast(ulong *)p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return ulong.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ulong t;
+
+        t = *cast(ulong *)p1;
+        *cast(ulong *)p1 = *cast(ulong *)p2;
+        *cast(ulong *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_ushort.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,38 @@
+
+// ushort
+
+module rt.typeinfo.ti_ushort;
+
+class TypeInfo_t : TypeInfo
+{
+    override string toString() { return "ushort"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(ushort *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ushort *)p1 == *cast(ushort *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(ushort *)p1 - *cast(ushort *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return ushort.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ushort t;
+
+        t = *cast(ushort *)p1;
+        *cast(ushort *)p1 = *cast(ushort *)p2;
+        *cast(ushort *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_void.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,43 @@
+
+// void
+
+module rt.typeinfo.ti_void;
+
+class TypeInfo_v : TypeInfo
+{
+    override string toString() { return "void"; }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(0);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return void.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        byte t;
+
+        t = *cast(byte *)p1;
+        *cast(byte *)p1 = *cast(byte *)p2;
+        *cast(byte *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/typeinfo/ti_wchar.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,43 @@
+
+module rt.typeinfo.ti_wchar;
+
+
+class TypeInfo_u : TypeInfo
+{
+    override string toString() { return "wchar"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(wchar *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(wchar *)p1 == *cast(wchar *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(wchar *)p1 - *cast(wchar *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return wchar.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        wchar t;
+
+        t = *cast(wchar *)p1;
+        *cast(wchar *)p1 = *cast(wchar *)p2;
+        *cast(wchar *)p2 = t;
+    }
+
+    override void[] init()
+    {   static wchar c;
+
+        return (cast(wchar *)&c)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/util/console.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,49 @@
+/**
+ * The console module contains some simple routines for console output.
+ *
+ * Copyright: Public Domain
+ * License:   Public Domain
+ * Authors:   Sean Kelly
+ */
+module rt.util.console;
+
+
+private
+{
+    version (Windows)
+    {
+        import sys.windows.windows;
+    }
+    else version( Posix )
+    {
+        import stdc.posix.unistd;
+    }
+    import util.string;
+}
+
+
+struct Console
+{
+    Console opCall( in char[] val )
+    {
+        version( Windows )
+        {
+            uint count = void;
+            WriteFile( GetStdHandle( 0xfffffff5 ), val.ptr, val.length, &count, null );
+        }
+        else version( Posix )
+        {
+            write( 2, val.ptr, val.length );
+        }
+        return *this;
+    }
+
+
+    Console opCall( uint val )
+    {
+            char[10] tmp = void;
+            return opCall( tmp.intToString( val ) );
+    }
+}
+
+Console console;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/util/cpuid.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,464 @@
+/**
+ * Identify the characteristics of the host CPU.
+ *
+ * Implemented according to:
+
+- AP-485 Intel(C) Processor Identification and the CPUID Instruction
+        $(LINK http://www.intel.com/design/xeon/applnots/241618.htm)
+
+- Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M
+        $(LINK http://developer.intel.com/design/pentium4/manuals/index_new.htm)
+
+- AMD CPUID Specification Publication # 25481
+        $(LINK http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf)
+
+Example:
+---
+import std.cpuid;
+import std.stdio;
+
+void main()
+{
+    writefln(std.cpuid.toString());
+}
+---
+
+AUTHORS:        Tomas Lindquist Olsen &lt;tomas@famolsen.dk&gt;
+                (slightly altered by Walter Bright)
+COPYRIGHT:      Public Domain
+
+ * BUGS:        Only works on x86 CPUs
+ *
+ * Macros:
+ *      WIKI = Phobos/StdCpuid
+ *      COPYRIGHT = Public Domain
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+module rt.util.cpuid;
+
+private import stdc.string;
+
+version(D_InlineAsm_X86)
+{
+    /// Returns vendor string
+    char[] vendor()             {return vendorStr;}
+    /// Returns processor string
+    string processor()          {return processorStr;}
+
+    /// Is MMX supported?
+    bool mmx()                  {return (flags&MMX_BIT)!=0;}
+    /// Is FXSR supported?
+    bool fxsr()                 {return (flags&FXSR_BIT)!=0;}
+    /// Is SSE supported?
+    bool sse()                  {return (flags&SSE_BIT)!=0;}
+    /// Is SSE2 supported?
+    bool sse2()                 {return (flags&SSE2_BIT)!=0;}
+    /// Is SSE3 supported?
+    bool sse3()                 {return (misc&SSE3_BIT)!=0;}
+    /// Is SSSE3 supported?
+    bool ssse3()                {return (misc&SSSE3_BIT)!=0;}
+
+    /// Is AMD 3DNOW supported?
+    bool amd3dnow()             {return (exflags&AMD_3DNOW_BIT)!=0;}
+    /// Is AMD 3DNOW Ext supported?
+    bool amd3dnowExt()          {return (exflags&AMD_3DNOW_EXT_BIT)!=0;}
+    /// Is AMD MMX supported?
+    bool amdMmx()               {return (exflags&AMD_MMX_BIT)!=0;}
+
+    /// Is this an Intel Architecture IA64?
+    bool ia64()                 {return (flags&IA64_BIT)!=0;}
+    /// Is this an AMD 64?
+    bool amd64()                {return (exflags&AMD64_BIT)!=0;}
+
+    /// Is hyperthreading supported?
+    bool hyperThreading()       {return (flags&HTT_BIT)!=0;}
+    /// Returns number of threads per CPU
+    uint threadsPerCPU()        {return maxThreads;}
+    /// Returns number of cores in CPU
+    uint coresPerCPU()          {return maxCores;}
+
+    /// Is this an Intel processor?
+    bool intel()                {return manufac==INTEL;}
+    /// Is this an AMD processor?
+    bool amd()                  {return manufac==AMD;}
+
+    /// Returns stepping
+    uint stepping()             {return _stepping;}
+    /// Returns model
+    uint model()                {return _model;}
+    /// Returns family
+    uint family()               {return _family;}
+    //uint processorType()      {return (signature>>>12)&0x3;}
+
+    static this()
+    {
+        getVendorString();
+        getProcessorString();
+        getFeatureFlags();
+
+        // stepping / family / model
+        _stepping = signature&0xF;
+        uint fbase = (signature>>>8)&0xF;
+        uint fex = (signature>>>20)&0xFF;
+        uint mbase = (signature>>>4)&0xF;
+        uint mex = (signature>>>16)&0xF;
+
+        // vendor specific
+        void function() threadFn;
+        switch(vendorStr)
+        {
+            case "GenuineIntel":
+                    manufac = INTEL;
+                    threadFn = &getThreadingIntel;
+                    if (fbase == 0xF)
+                            _family = fbase+fex;
+                    else
+                            _family = fbase;
+                    if (_family == 0x6 || _family == 0xF)
+                            _model = mbase+(mex<<4);
+                    else
+                            _model = mbase;
+                    break;
+
+            case "AuthenticAMD":
+                    manufac = AMD;
+                    threadFn = &getThreadingAMD;
+                    if (fbase < 0xF)
+                    {
+                            _family = fbase;
+                            _model = mbase;
+                    }
+                    else
+                    {
+                            _family = fbase+fex;
+                            _model = mbase+(mex<<4);
+                    }
+                    break;
+
+            default:
+                    manufac = OTHER;
+        }
+
+        // threading details
+        if (hyperThreading && threadFn !is null)
+        {
+                threadFn();
+        }
+    }
+
+private:
+    // feature flags
+    enum : uint
+    {
+            MMX_BIT = 1<<23,
+            FXSR_BIT = 1<<24,
+            SSE_BIT = 1<<25,
+            SSE2_BIT = 1<<26,
+            HTT_BIT = 1<<28,
+            IA64_BIT = 1<<30
+    }
+    // feature flags misc
+    enum : uint
+    {
+            SSE3_BIT = 1,
+            SSSE3_BIT = 1<<9
+    }
+    // extended feature flags
+    enum : uint
+    {
+            AMD_MMX_BIT = 1<<22,
+            AMD64_BIT = 1<<29,
+            AMD_3DNOW_EXT_BIT = 1<<30,
+            AMD_3DNOW_BIT = 1<<31
+    }
+    // manufacturer
+    enum
+    {
+            OTHER,
+            INTEL,
+            AMD
+    }
+
+    uint flags, misc, exflags, apic, signature;
+    uint _stepping, _model, _family;
+
+    char[12] vendorStr = 0;
+    string processorStr = "";
+
+    uint maxThreads=1;
+    uint maxCores=1;
+    uint manufac=OTHER;
+
+    /* **
+     * fetches the cpu vendor string
+     */
+    private void getVendorString()
+    {
+        char* dst = vendorStr.ptr;
+        // puts the vendor string into dst
+        asm
+        {
+            mov EAX, 0                  ;
+            cpuid                       ;
+            mov EAX, dst                ;
+            mov [EAX], EBX              ;
+            mov [EAX+4], EDX            ;
+            mov [EAX+8], ECX            ;
+        }
+    }
+
+    private void getProcessorString()
+    {
+        char[48] buffer;
+        char* dst = buffer.ptr;
+        // puts the processor string into dst
+        asm
+        {
+            mov EAX, 0x8000_0000        ;
+            cpuid                       ;
+            cmp EAX, 0x8000_0004        ;
+            jb PSLabel                  ; // no support
+            push EDI                    ;
+            mov EDI, dst                ;
+            mov EAX, 0x8000_0002        ;
+            cpuid                       ;
+            mov [EDI], EAX              ;
+            mov [EDI+4], EBX            ;
+            mov [EDI+8], ECX            ;
+            mov [EDI+12], EDX           ;
+            mov EAX, 0x8000_0003        ;
+            cpuid                       ;
+            mov [EDI+16], EAX           ;
+            mov [EDI+20], EBX           ;
+            mov [EDI+24], ECX           ;
+            mov [EDI+28], EDX           ;
+            mov EAX, 0x8000_0004        ;
+            cpuid                       ;
+            mov [EDI+32], EAX           ;
+            mov [EDI+36], EBX           ;
+            mov [EDI+40], ECX           ;
+            mov [EDI+44], EDX           ;
+            pop EDI                     ;
+        PSLabel:                        ;
+        }
+
+        if (buffer[0] == char.init) // no support
+            return;
+
+        // seems many intel processors prepend whitespace
+        processorStr = cast(string)strip(toString(dst)).dup;
+    }
+
+    private void getFeatureFlags()
+    {
+        uint f,m,e,a,s;
+        asm
+        {
+            mov EAX, 0                  ;
+            cpuid                       ;
+            cmp EAX, 1                  ;
+            jb FeatLabel                ; // no support
+            mov EAX, 1                  ;
+            cpuid                       ;
+            mov f, EDX                  ;
+            mov m, ECX                  ;
+            mov a, EBX                  ;
+            mov s, EAX                  ;
+
+        FeatLabel:                      ;
+            mov EAX, 0x8000_0000        ;
+            cpuid                       ;
+            cmp EAX, 0x8000_0001        ;
+            jb FeatLabel2               ; // no support
+            mov EAX, 0x8000_0001        ;
+            cpuid                       ;
+            mov e, EDX                  ;
+
+        FeatLabel2:
+            ;
+        }
+        flags = f;
+        misc = m;
+        exflags = e;
+        apic = a;
+        signature = s;
+    }
+
+    private void getThreadingIntel()
+    {
+        uint n;
+        ubyte b = 0;
+        asm
+        {
+            mov EAX, 0                  ;
+            cpuid                       ;
+            cmp EAX, 4                  ;
+            jb IntelSingle              ;
+            mov EAX, 4                  ;
+            mov ECX, 0                  ;
+            cpuid                       ;
+            mov n, EAX                  ;
+            mov b, 1                    ;
+        IntelSingle:                    ;
+        }
+        if (b != 0)
+        {
+            maxCores = ((n>>>26)&0x3F)+1;
+            maxThreads = (apic>>>16)&0xFF;
+        }
+        else
+        {
+            maxCores = maxThreads = 1;
+        }
+    }
+
+    private void getThreadingAMD()
+    {
+        ubyte n;
+        ubyte b = 0;
+        asm
+        {
+            mov EAX, 0x8000_0000        ;
+            cpuid                       ;
+            cmp EAX, 0x8000_0008        ;
+            jb AMDSingle                ;
+            mov EAX, 0x8000_0008        ;
+            cpuid                       ;
+            mov n, CL                   ;
+            mov b, 1                    ;
+        AMDSingle:                      ;
+        }
+        if (b != 0)
+        {
+            maxCores = n+1;
+            maxThreads = (apic>>>16)&0xFF;
+        }
+        else
+        {
+            maxCores = maxThreads = 1;
+        }
+    }
+
+    /***************************************************************************
+     * Support code for above, from std.string and std.ctype
+     ***************************************************************************/
+
+    private
+    {
+        enum
+        {
+            _SPC =      8,
+            _CTL =      0x20,
+            _BLK =      0x40,
+            _HEX =      0x80,
+            _UC  =      1,
+            _LC  =      2,
+            _PNC =      0x10,
+            _DIG =      4,
+            _ALP =      _UC|_LC,
+        }
+
+        ubyte _ctype[128] =
+        [
+                _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+                _CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL,
+                _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+                _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+                _SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+                _PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+                _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
+                _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
+                _PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+                _PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC,
+                _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
+                _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
+                _UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC,
+                _PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC,
+                _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
+                _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
+                _LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL
+        ];
+
+         /**
+          * Returns !=0 if c is a space, tab, vertical tab, form feed,
+          * carriage return, or linefeed.
+          */
+         int isspace(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; }
+
+        /*****************************************
+         * Strips leading or trailing whitespace, or both.
+         */
+        char[] stripl(char[] s)
+        {
+            uint i;
+
+            for (i = 0; i < s.length; i++)
+            {
+            if (!isspace(s[i]))
+                break;
+            }
+            return s[i .. s.length];
+        }
+
+        char[] stripr(char[] s) /// ditto
+        {
+            uint i;
+
+            for (i = s.length; i > 0; i--)
+            {
+            if (!isspace(s[i - 1]))
+                break;
+            }
+            return s[0 .. i];
+        }
+
+        char[] strip(char[] s) /// ditto
+        {
+            return stripr(stripl(s));
+        }
+
+        char[] toString(char* s)
+        {
+            return s ? s[0 .. strlen(s)] : null;
+        }
+
+        string toString(invariant(char)* s)
+        {
+            return s ? s[0 .. strlen(s)] : null;
+        }
+    }
+}
+else
+{
+    char[] vendor()             {return "unknown vendor"; }
+    char[] processor()          {return "unknown processor"; }
+
+    bool mmx()                  {return false; }
+    bool fxsr()                 {return false; }
+    bool sse()                  {return false; }
+    bool sse2()                 {return false; }
+    bool sse3()                 {return false; }
+    bool ssse3()                {return false; }
+
+    bool amd3dnow()             {return false; }
+    bool amd3dnowExt()          {return false; }
+    bool amdMmx()               {return false; }
+
+    bool ia64()                 {return false; }
+    bool amd64()                {return false; }
+
+    bool hyperThreading()       {return false; }
+    uint threadsPerCPU()        {return 0; }
+    uint coresPerCPU()          {return 0; }
+
+    bool intel()                {return false; }
+    bool amd()                  {return false; }
+
+    uint stepping()             {return 0; }
+    uint model()                {return 0; }
+    uint family()               {return 0; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/util/ctype.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,106 @@
+
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+// Simple ASCII char classification functions
+
+module rt.util.ctype;
+
+int isalnum(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG) : 0; }
+int isalpha(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP)      : 0; }
+int iscntrl(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_CTL)      : 0; }
+int isdigit(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_DIG)      : 0; }
+int islower(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_LC)       : 0; }
+int ispunct(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_PNC)      : 0; }
+int isspace(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_SPC)      : 0; }
+int isupper(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_UC)       : 0; }
+int isxdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_HEX)      : 0; }
+int isgraph(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC) : 0; }
+int isprint(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC|_BLK) : 0; }
+int isascii(dchar c)  { return c <= 0x7F; }
+
+dchar tolower(dchar c)
+    out (result)
+    {
+	assert(!isupper(result));
+    }
+    body
+    {
+	return isupper(c) ? c + (cast(dchar)'a' - 'A') : c;
+    }
+
+dchar toupper(dchar c)
+    out (result)
+    {
+	assert(!islower(result));
+    }
+    body
+    {
+	return islower(c) ? c - (cast(dchar)'a' - 'A') : c;
+    }
+
+private:
+
+enum
+{
+    _SPC =	8,
+    _CTL =	0x20,
+    _BLK =	0x40,
+    _HEX =	0x80,
+    _UC  =	1,
+    _LC  =	2,
+    _PNC =	0x10,
+    _DIG =	4,
+    _ALP =	_UC|_LC,
+}
+
+ubyte _ctype[128] =
+[
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL,
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
+	_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
+	_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC,
+	_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
+	_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
+	_UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC,
+	_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
+	_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
+	_LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL
+];
+
+
+unittest
+{
+    assert(isspace(' '));
+    assert(!isspace('z'));
+    assert(toupper('a') == 'A');
+    assert(tolower('Q') == 'q');
+    assert(!isxdigit('G'));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/util/string.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,35 @@
+/**
+ * The exception module defines all system-level exceptions and provides a
+ * mechanism to alter system-level error handling.
+ *
+ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
+ * License:   BSD Style, see LICENSE
+ * Authors:   Sean Kelly
+ */
+module rt.util.string;
+
+private import stdc.string;
+
+char[] intToString( char[] buf, uint val )
+{
+    assert( buf.length > 9 );
+    auto p = buf.ptr + buf.length;
+
+    do
+    {
+        *--p = cast(char)(val % 10 + '0');
+    } while( val /= 10 );
+
+    return buf[p - buf.ptr .. $];
+}
+
+
+int dstrcmp( in char[] s1, in char[] s2 )
+{
+    auto len = s1.length;
+    if( s2.length < len )
+        len = s2.length;
+    if( memcmp( s1.ptr, s2.ptr, len ) == 0 )
+        return 0;
+    return s1.length > s2.length ? 1 : -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/util/utf.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,917 @@
+// Written in the D programming language
+
+/*
+ *  Copyright (C) 2003-2004 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/********************************************
+ * Encode and decode UTF-8, UTF-16 and UTF-32 strings.
+ *
+ * For Win32 systems, the C wchar_t type is UTF-16 and corresponds to the D
+ * wchar type.
+ * For linux systems, the C wchar_t type is UTF-32 and corresponds to
+ * the D utf.dchar type.
+ *
+ * UTF character support is restricted to (\u0000 &lt;= character &lt;= \U0010FFFF).
+ *
+ * See_Also:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)<br>
+ *	$(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)<br>
+ *	$(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335)
+ * Macros:
+ *	WIKI = Phobos/StdUtf
+ */
+
+module rt.util.utf;
+
+
+extern (C) void onUnicodeError( string msg, size_t idx );
+
+/*******************************
+ * Test if c is a valid UTF-32 character.
+ *
+ * \uFFFE and \uFFFF are considered valid by this function,
+ * as they are permitted for internal use by an application,
+ * but they are not allowed for interchange by the Unicode standard.
+ *
+ * Returns: true if it is, false if not.
+ */
+
+bool isValidDchar(dchar c)
+{
+    /* Note: FFFE and FFFF are specifically permitted by the
+     * Unicode standard for application internal use, but are not
+     * allowed for interchange.
+     * (thanks to Arcane Jill)
+     */
+
+    return c < 0xD800 ||
+	(c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/);
+}
+
+unittest
+{
+    debug(utf) printf("utf.isValidDchar.unittest\n");
+    assert(isValidDchar(cast(dchar)'a') == true);
+    assert(isValidDchar(cast(dchar)0x1FFFFF) == false);
+}
+
+
+
+auto UTF8stride =
+[
+    cast(ubyte)
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+    4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF,
+];
+
+/**
+ * stride() returns the length of a UTF-8 sequence starting at index i
+ * in string s.
+ * Returns:
+ *	The number of bytes in the UTF-8 sequence or
+ *	0xFF meaning s[i] is not the start of of UTF-8 sequence.
+ */
+uint stride(in char[] s, size_t i)
+{
+    return UTF8stride[s[i]];
+}
+
+/**
+ * stride() returns the length of a UTF-16 sequence starting at index i
+ * in string s.
+ */
+uint stride(in wchar[] s, size_t i)
+{   uint u = s[i];
+    return 1 + (u >= 0xD800 && u <= 0xDBFF);
+}
+
+/**
+ * stride() returns the length of a UTF-32 sequence starting at index i
+ * in string s.
+ * Returns: The return value will always be 1.
+ */
+uint stride(in dchar[] s, size_t i)
+{
+    return 1;
+}
+
+/*******************************************
+ * Given an index i into an array of characters s[],
+ * and assuming that index i is at the start of a UTF character,
+ * determine the number of UCS characters up to that index i.
+ */
+
+size_t toUCSindex(in char[] s, size_t i)
+{
+    size_t n;
+    size_t j;
+
+    for (j = 0; j < i; )
+    {
+	j += stride(s, j);
+	n++;
+    }
+    if (j > i)
+    {
+        onUnicodeError("invalid UTF-8 sequence", j);
+    }
+    return n;
+}
+
+/** ditto */
+size_t toUCSindex(in wchar[] s, size_t i)
+{
+    size_t n;
+    size_t j;
+
+    for (j = 0; j < i; )
+    {
+	j += stride(s, j);
+	n++;
+    }
+    if (j > i)
+    {
+        onUnicodeError("invalid UTF-16 sequence", j);
+    }
+    return n;
+}
+
+/** ditto */
+size_t toUCSindex(in dchar[] s, size_t i)
+{
+    return i;
+}
+
+/******************************************
+ * Given a UCS index n into an array of characters s[], return the UTF index.
+ */
+
+size_t toUTFindex(in char[] s, size_t n)
+{
+    size_t i;
+
+    while (n--)
+    {
+	uint j = UTF8stride[s[i]];
+	if (j == 0xFF)
+	    onUnicodeError("invalid UTF-8 sequence", i);
+	i += j;
+    }
+    return i;
+}
+
+/** ditto */
+size_t toUTFindex(in wchar[] s, size_t n)
+{
+    size_t i;
+
+    while (n--)
+    {	wchar u = s[i];
+
+	i += 1 + (u >= 0xD800 && u <= 0xDBFF);
+    }
+    return i;
+}
+
+/** ditto */
+size_t toUTFindex(in dchar[] s, size_t n)
+{
+    return n;
+}
+
+/* =================== Decode ======================= */
+
+/***************
+ * Decodes and returns character starting at s[idx]. idx is advanced past the
+ * decoded character. If the character is not well formed, a UtfException is
+ * thrown and idx remains unchanged.
+ */
+dchar decode(in char[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    out (result)
+    {
+	assert(isValidDchar(result));
+    }
+    body
+    {
+	size_t len = s.length;
+	dchar V;
+	size_t i = idx;
+	char u = s[i];
+
+	if (u & 0x80)
+	{   uint n;
+	    char u2;
+
+	    /* The following encodings are valid, except for the 5 and 6 byte
+	     * combinations:
+	     *	0xxxxxxx
+	     *	110xxxxx 10xxxxxx
+	     *	1110xxxx 10xxxxxx 10xxxxxx
+	     *	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     *	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     *	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     */
+	    for (n = 1; ; n++)
+	    {
+		if (n > 4)
+		    goto Lerr;		// only do the first 4 of 6 encodings
+		if (((u << n) & 0x80) == 0)
+		{
+		    if (n == 1)
+			goto Lerr;
+		    break;
+		}
+	    }
+
+	    // Pick off (7 - n) significant bits of B from first byte of octet
+	    V = cast(dchar)(u & ((1 << (7 - n)) - 1));
+
+	    if (i + (n - 1) >= len)
+		goto Lerr;			// off end of string
+
+	    /* The following combinations are overlong, and illegal:
+	     *	1100000x (10xxxxxx)
+	     *	11100000 100xxxxx (10xxxxxx)
+	     *	11110000 1000xxxx (10xxxxxx 10xxxxxx)
+	     *	11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
+	     *	11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+	     */
+	    u2 = s[i + 1];
+	    if ((u & 0xFE) == 0xC0 ||
+		(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
+		(u == 0xF0 && (u2 & 0xF0) == 0x80) ||
+		(u == 0xF8 && (u2 & 0xF8) == 0x80) ||
+		(u == 0xFC && (u2 & 0xFC) == 0x80))
+		goto Lerr;			// overlong combination
+
+	    for (uint j = 1; j != n; j++)
+	    {
+		u = s[i + j];
+		if ((u & 0xC0) != 0x80)
+		    goto Lerr;			// trailing bytes are 10xxxxxx
+		V = (V << 6) | (u & 0x3F);
+	    }
+	    if (!isValidDchar(V))
+		goto Lerr;
+	    i += n;
+	}
+	else
+	{
+	    V = cast(dchar) u;
+	    i++;
+	}
+
+	idx = i;
+	return V;
+
+      Lerr:
+      onUnicodeError("invalid UTF-8 sequence", i);
+    return V; // dummy return
+    }
+
+unittest
+{   size_t i;
+    dchar c;
+
+    debug(utf) printf("utf.decode.unittest\n");
+
+    static s1 = "abcd"c;
+    i = 0;
+    c = decode(s1, i);
+    assert(c == cast(dchar)'a');
+    assert(i == 1);
+    c = decode(s1, i);
+    assert(c == cast(dchar)'b');
+    assert(i == 2);
+
+    static s2 = "\xC2\xA9"c;
+    i = 0;
+    c = decode(s2, i);
+    assert(c == cast(dchar)'\u00A9');
+    assert(i == 2);
+
+    static s3 = "\xE2\x89\xA0"c;
+    i = 0;
+    c = decode(s3, i);
+    assert(c == cast(dchar)'\u2260');
+    assert(i == 3);
+
+    static s4 =
+    [	"\xE2\x89"c,		// too short
+	"\xC0\x8A",
+	"\xE0\x80\x8A",
+	"\xF0\x80\x80\x8A",
+	"\xF8\x80\x80\x80\x8A",
+	"\xFC\x80\x80\x80\x80\x8A",
+    ];
+
+    for (int j = 0; j < s4.length; j++)
+    {
+	try
+	{
+	    i = 0;
+	    c = decode(s4[j], i);
+	    assert(0);
+	}
+	catch (Object o)
+	{
+	    i = 23;
+	}
+	assert(i == 23);
+    }
+}
+
+/** ditto */
+
+dchar decode(in wchar[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    out (result)
+    {
+	assert(isValidDchar(result));
+    }
+    body
+    {
+	string msg;
+	dchar V;
+	size_t i = idx;
+	uint u = s[i];
+
+	if (u & ~0x7F)
+	{   if (u >= 0xD800 && u <= 0xDBFF)
+	    {   uint u2;
+
+		if (i + 1 == s.length)
+		{   msg = "surrogate UTF-16 high value past end of string";
+		    goto Lerr;
+		}
+		u2 = s[i + 1];
+		if (u2 < 0xDC00 || u2 > 0xDFFF)
+		{   msg = "surrogate UTF-16 low value out of range";
+		    goto Lerr;
+		}
+		u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
+		i += 2;
+	    }
+	    else if (u >= 0xDC00 && u <= 0xDFFF)
+	    {   msg = "unpaired surrogate UTF-16 value";
+		goto Lerr;
+	    }
+	    else if (u == 0xFFFE || u == 0xFFFF)
+	    {   msg = "illegal UTF-16 value";
+		goto Lerr;
+	    }
+	    else
+		i++;
+	}
+	else
+	{
+	    i++;
+	}
+
+	idx = i;
+	return cast(dchar)u;
+
+      Lerr:
+	  onUnicodeError(msg, i);
+	return cast(dchar)u; // dummy return
+    }
+
+/** ditto */
+
+dchar decode(in dchar[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    body
+    {
+	size_t i = idx;
+	dchar c = s[i];
+
+	if (!isValidDchar(c))
+	    goto Lerr;
+	idx = i + 1;
+	return c;
+
+      Lerr:
+	  onUnicodeError("invalid UTF-32 value", i);
+	return c; // dummy return
+    }
+
+
+/* =================== Encode ======================= */
+
+/*******************************
+ * Encodes character c and appends it to array s[].
+ */
+void encode(inout char[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	char[] r = s;
+
+	if (c <= 0x7F)
+	{
+	    r ~= cast(char) c;
+	}
+	else
+	{
+	    char[4] buf;
+	    uint L;
+
+	    if (c <= 0x7FF)
+	    {
+		buf[0] = cast(char)(0xC0 | (c >> 6));
+		buf[1] = cast(char)(0x80 | (c & 0x3F));
+		L = 2;
+	    }
+	    else if (c <= 0xFFFF)
+	    {
+		buf[0] = cast(char)(0xE0 | (c >> 12));
+		buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+		buf[2] = cast(char)(0x80 | (c & 0x3F));
+		L = 3;
+	    }
+	    else if (c <= 0x10FFFF)
+	    {
+		buf[0] = cast(char)(0xF0 | (c >> 18));
+		buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
+		buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+		buf[3] = cast(char)(0x80 | (c & 0x3F));
+		L = 4;
+	    }
+	    else
+	    {
+		assert(0);
+	    }
+	    r ~= buf[0 .. L];
+	}
+	s = r;
+    }
+
+unittest
+{
+    debug(utf) printf("utf.encode.unittest\n");
+
+    char[] s = "abcd".dup;
+    encode(s, cast(dchar)'a');
+    assert(s.length == 5);
+    assert(s == "abcda");
+
+    encode(s, cast(dchar)'\u00A9');
+    assert(s.length == 7);
+    assert(s == "abcda\xC2\xA9");
+    //assert(s == "abcda\u00A9");	// BUG: fix compiler
+
+    encode(s, cast(dchar)'\u2260');
+    assert(s.length == 10);
+    assert(s == "abcda\xC2\xA9\xE2\x89\xA0");
+}
+
+/** ditto */
+
+void encode(inout wchar[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	wchar[] r = s;
+
+	if (c <= 0xFFFF)
+	{
+	    r ~= cast(wchar) c;
+	}
+	else
+	{
+	    wchar[2] buf;
+
+	    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
+	    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
+	    r ~= buf;
+	}
+	s = r;
+    }
+
+/** ditto */
+void encode(inout dchar[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	s ~= c;
+    }
+
+/**
+Returns the code length of $(D c) in the encoding using $(D C) as a
+code point. The code is returned in character count, not in bytes.
+ */
+
+ubyte codeLength(C)(dchar c)
+{
+
+    static if (C.sizeof == 1)
+    {
+        return
+            c <= 0x7F ? 1
+            : c <= 0x7FF ? 2
+            : c <= 0xFFFF ? 3
+            : c <= 0x10FFFF ? 4
+            : (assert(false), 6);
+}
+
+    else static if (C.sizeof == 2)
+{
+	return c <= 0xFFFF ? 1 : 2;
+    }
+    else
+    {
+        static assert(C.sizeof == 4);
+        return 1;
+    }
+}
+
+/* =================== Validation ======================= */
+
+/***********************************
+Checks to see if string is well formed or not. $(D S) can be an array
+ of $(D char), $(D wchar), or $(D dchar). Throws a $(D UtfException)
+ if it is not. Use to check all untrusted input for correctness.
+ */
+void validate(S)(in S s)
+{
+    auto len = s.length;
+    for (size_t i = 0; i < len; )
+    {
+	decode(s, i);
+    }
+}
+
+/* =================== Conversion to UTF8 ======================= */
+
+char[] toUTF8(char[4] buf, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	if (c <= 0x7F)
+	{
+	    buf[0] = cast(char) c;
+	    return buf[0 .. 1];
+	}
+	else if (c <= 0x7FF)
+	{
+	    buf[0] = cast(char)(0xC0 | (c >> 6));
+	    buf[1] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 2];
+	}
+	else if (c <= 0xFFFF)
+	{
+	    buf[0] = cast(char)(0xE0 | (c >> 12));
+	    buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+	    buf[2] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 3];
+	}
+	else if (c <= 0x10FFFF)
+	{
+	    buf[0] = cast(char)(0xF0 | (c >> 18));
+	    buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
+	    buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+	    buf[3] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 4];
+	}
+	assert(0);
+    }
+
+/*******************
+ * Encodes string s into UTF-8 and returns the encoded string.
+ */
+string toUTF8(string s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/** ditto */
+string toUTF8(in wchar[] s)
+{
+    char[] r;
+    size_t i;
+    size_t slen = s.length;
+
+    r.length = slen;
+
+    for (i = 0; i < slen; i++)
+    {	wchar c = s[i];
+
+	if (c <= 0x7F)
+	    r[i] = cast(char)c;		// fast path for ascii
+	else
+	{
+	    r.length = i;
+	    foreach (dchar c; s[i .. slen])
+	    {
+		encode(r, c);
+	    }
+	    break;
+	}
+    }
+    return cast(string)r;
+}
+
+/** ditto */
+string toUTF8(in dchar[] s)
+{
+    char[] r;
+    size_t i;
+    size_t slen = s.length;
+
+    r.length = slen;
+
+    for (i = 0; i < slen; i++)
+    {	dchar c = s[i];
+
+	if (c <= 0x7F)
+	    r[i] = cast(char)c;		// fast path for ascii
+	else
+	{
+	    r.length = i;
+	    foreach (dchar d; s[i .. slen])
+	    {
+		encode(r, d);
+	    }
+	    break;
+	}
+    }
+    return cast(string)r;
+}
+
+/* =================== Conversion to UTF16 ======================= */
+
+wchar[] toUTF16(wchar[2] buf, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	if (c <= 0xFFFF)
+	{
+	    buf[0] = cast(wchar) c;
+	    return buf[0 .. 1];
+	}
+	else
+	{
+	    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
+	    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
+	    return buf[0 .. 2];
+	}
+    }
+
+/****************
+ * Encodes string s into UTF-16 and returns the encoded string.
+ * toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take
+ * an LPWSTR or LPCWSTR argument.
+ */
+wstring toUTF16(in char[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen;
+    r.length = 0;
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c <= 0x7F)
+	{
+	    i++;
+	    r ~= cast(wchar)c;
+	}
+	else
+	{
+	    c = decode(s, i);
+	    encode(r, c);
+	}
+    }
+    return cast(wstring)r;
+}
+
+alias const(wchar)* wptr;
+/** ditto */
+wptr toUTF16z(in char[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen + 1;
+    r.length = 0;
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c <= 0x7F)
+	{
+	    i++;
+	    r ~= cast(wchar)c;
+	}
+	else
+	{
+	    c = decode(s, i);
+	    encode(r, c);
+	}
+    }
+    r ~= "\000";
+    return r.ptr;
+}
+
+/** ditto */
+wstring toUTF16(wstring s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/** ditto */
+wstring toUTF16(in dchar[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen;
+    r.length = 0;
+    for (size_t i = 0; i < slen; i++)
+    {
+	encode(r, s[i]);
+    }
+    return cast(wstring)r;
+}
+
+/* =================== Conversion to UTF32 ======================= */
+
+/*****
+ * Encodes string s into UTF-32 and returns the encoded string.
+ */
+dstring toUTF32(in char[] s)
+{
+    dchar[] r;
+    size_t slen = s.length;
+    size_t j = 0;
+
+    r.length = slen;		// r[] will never be longer than s[]
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c >= 0x80)
+	    c = decode(s, i);
+	else
+	    i++;		// c is ascii, no need for decode
+	r[j++] = c;
+    }
+    return cast(dstring)r[0 .. j];
+}
+
+/** ditto */
+dstring toUTF32(in wchar[] s)
+{
+    dchar[] r;
+    size_t slen = s.length;
+    size_t j = 0;
+
+    r.length = slen;		// r[] will never be longer than s[]
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c >= 0x80)
+	    c = decode(s, i);
+	else
+	    i++;		// c is ascii, no need for decode
+	r[j++] = c;
+    }
+    return cast(dstring)r[0 .. j];
+}
+
+/** ditto */
+dstring toUTF32(dstring s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/* ================================ tests ================================== */
+
+unittest
+{
+    debug(utf) printf("utf.toUTF.unittest\n");
+
+    auto c = "hello"c;
+    auto w = toUTF16(c);
+    assert(w == "hello");
+    auto d = toUTF32(c);
+    assert(d == "hello");
+
+    c = toUTF8(w);
+    assert(c == "hello");
+    d = toUTF32(w);
+    assert(d == "hello");
+
+    c = toUTF8(d);
+    assert(c == "hello");
+    w = toUTF16(d);
+    assert(w == "hello");
+
+
+    c = "hel\u1234o";
+    w = toUTF16(c);
+    assert(w == "hel\u1234o");
+    d = toUTF32(c);
+    assert(d == "hel\u1234o");
+
+    c = toUTF8(w);
+    assert(c == "hel\u1234o");
+    d = toUTF32(w);
+    assert(d == "hel\u1234o");
+
+    c = toUTF8(d);
+    assert(c == "hel\u1234o");
+    w = toUTF16(d);
+    assert(w == "hel\u1234o");
+
+
+    c = "he\U0010AAAAllo";
+    w = toUTF16(c);
+    //foreach (wchar c; w) printf("c = x%x\n", c);
+    //foreach (wchar c; cast(wstring)"he\U0010AAAAllo") printf("c = x%x\n", c);
+    assert(w == "he\U0010AAAAllo");
+    d = toUTF32(c);
+    assert(d == "he\U0010AAAAllo");
+
+    c = toUTF8(w);
+    assert(c == "he\U0010AAAAllo");
+    d = toUTF32(w);
+    assert(d == "he\U0010AAAAllo");
+
+    c = toUTF8(d);
+    assert(c == "he\U0010AAAAllo");
+    w = toUTF16(d);
+    assert(w == "he\U0010AAAAllo");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/dmd/win32.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,171 @@
+# Makefile to build the compiler runtime D library for Win32
+# Designed to work with DigitalMars make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the compiler runtime library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=druntime-rt-dmd.lib
+LIB_MASK=druntime-rt-dmd*.lib
+
+CP=xcopy /y
+RM=del /f
+MD=mkdir
+
+CFLAGS=-mn -6 -r $(ADD_CFLAGS)
+#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS)
+
+DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
+#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+TFLAGS=-O -inline -w  -nofloat $(ADD_DFLAGS)
+#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=dmc
+LC=lib
+DC=dmd
+
+LIB_DEST=..\..\..\lib
+
+.DEFAULT: .asm .c .cpp .d .html .obj
+
+.asm.obj:
+	$(CC) -c $<
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.obj:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.d.obj:
+	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
+
+targets : lib doc
+all     : lib doc
+lib     : dmd.lib
+doc     : dmd.doc
+
+######################################################
+
+OBJ_BASE= \
+    aaA.obj \
+    aApply.obj \
+    aApplyR.obj \
+    adi.obj \
+    arrayassign.obj \
+    arraybyte.obj \
+    arraycast.obj \
+    arraycat.obj \
+    arraydouble.obj \
+    arrayfloat.obj \
+    arrayint.obj \
+    arrayreal.obj \
+    arrayshort.obj \
+    cast_.obj \
+    complex.obj \
+    cover.obj \
+    critical.obj \
+    deh.obj \
+    dmain2.obj \
+    invariant.obj \
+    invariant_.obj \
+    lifetime.obj \
+    memory.obj \
+    memset.obj \
+    monitor.obj \
+    obj.obj \
+    object_.obj \
+    qsort.obj \
+    switch_.obj \
+    trace.obj
+# NOTE: trace.obj and cover.obj are not necessary for a successful build
+#       as both are used for debugging features (profiling and coverage)
+# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and
+#       minit.asm is not used by dmd for linux
+
+OBJ_UTIL= \
+    util\console.obj \
+    util\cpuid.obj \
+    util\ctype.obj \
+    util\string.obj \
+    util\utf.obj
+
+OBJ_TI= \
+    typeinfo\ti_AC.obj \
+    typeinfo\ti_Acdouble.obj \
+    typeinfo\ti_Acfloat.obj \
+    typeinfo\ti_Acreal.obj \
+    typeinfo\ti_Adouble.obj \
+    typeinfo\ti_Afloat.obj \
+    typeinfo\ti_Ag.obj \
+    typeinfo\ti_Aint.obj \
+    typeinfo\ti_Along.obj \
+    typeinfo\ti_Areal.obj \
+    typeinfo\ti_Ashort.obj \
+    typeinfo\ti_byte.obj \
+    typeinfo\ti_C.obj \
+    typeinfo\ti_cdouble.obj \
+    typeinfo\ti_cfloat.obj \
+    typeinfo\ti_char.obj \
+    typeinfo\ti_creal.obj \
+    typeinfo\ti_dchar.obj \
+    typeinfo\ti_delegate.obj \
+    typeinfo\ti_double.obj \
+    typeinfo\ti_float.obj \
+    typeinfo\ti_idouble.obj \
+    typeinfo\ti_ifloat.obj \
+    typeinfo\ti_int.obj \
+    typeinfo\ti_ireal.obj \
+    typeinfo\ti_long.obj \
+    typeinfo\ti_ptr.obj \
+    typeinfo\ti_real.obj \
+    typeinfo\ti_short.obj \
+    typeinfo\ti_ubyte.obj \
+    typeinfo\ti_uint.obj \
+    typeinfo\ti_ulong.obj \
+    typeinfo\ti_ushort.obj \
+    typeinfo\ti_void.obj \
+    typeinfo\ti_wchar.obj
+
+ALL_OBJS= \
+    $(OBJ_BASE) \
+    $(OBJ_UTIL) \
+    $(OBJ_TI)
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+dmd.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) -c -n $@ $(ALL_OBJS) minit.obj
+
+dmd.doc : $(ALL_DOCS)
+	@echo No documentation available.
+
+######################################################
+
+clean :
+	$(RM) /s *.di
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)\.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/aApply.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,414 @@
+/**
+ * Part of the D programming language runtime library.
+ */
+
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+/* This code handles decoding UTF strings for foreach loops.
+ * There are 6 combinations of conversions between char, wchar,
+ * and dchar, and 2 of each of those.
+ */
+
+private import util.utf;
+
+//debug = apply;
+debug(apply)
+{
+    extern(C) int printf(char*, ...);
+}
+
+/**********************************************
+ */
+
+// dg is D, but _aApplycd() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+extern (C) int _aApplycd1(char[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycd1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+
+        d = aa[i];
+        if (d & 0x80)
+            d = decode(aa, i);
+        else
+            i++;
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywd1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+
+        d = aa[i];
+        if (d & ~0x7F)
+            d = decode(aa, i);
+        else
+            i++;
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplycw1(char[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycw1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+        wchar w;
+
+        w = aa[i];
+        if (w & 0x80)
+        {   d = decode(aa, i);
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+		w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(cast(void *)&w);
+                if (result)
+                    break;
+		w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        else
+            i++;
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywc1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+        wchar w;
+        char c;
+
+        w = aa[i];
+        if (w & ~0x7F)
+        {
+            char[4] buf;
+
+            d = decode(aa, i);
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)w;
+            i++;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
+    foreach (dchar d; aa)
+    {
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {
+            c = cast(char)d;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
+    foreach (dchar d; aa)
+    {
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+	    w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(cast(void *)&w);
+            if (result)
+                break;
+	    w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+
+/****************************************************************************/
+
+// dg is D, but _aApplycd2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+extern (C) int _aApplycd2(char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycd2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+
+        d = aa[i];
+        if (d & 0x80)
+        {
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywd2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+
+        d = aa[i];
+        if (d & ~0x7F)
+        {
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplycw2(char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycw2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+        wchar w;
+
+        w = aa[i];
+        if (w & 0x80)
+        {   n = i;
+            d = decode(aa, n);
+            n -= i;
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+		w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(&i, cast(void *)&w);
+                if (result)
+                    break;
+		w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywc2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+        wchar w;
+        char c;
+
+        w = aa[i];
+        if (w & ~0x7F)
+        {
+            char[4] buf;
+
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)w;
+            n = 1;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplydc2(), len = %d\n", len);
+    for (i = 0; i < len; i++)
+    {   dchar d;
+        char c;
+
+        d = aa[i];
+        debug(apply) printf("d = %u\n", d);
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                debug(apply) printf("c2 = %d\n", c2);
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)d;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
+    foreach (size_t i, dchar d; aa)
+    {
+        wchar w;
+        auto j = i;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+	    w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(&j, cast(void *)&w);
+            if (result)
+                break;
+	    w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(&j, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/aApplyR.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,975 @@
+
+/**
+ * Part of the D programming language runtime library.
+ */
+
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+/* This code handles decoding UTF strings for foreach_reverse loops.
+ * There are 6 combinations of conversions between char, wchar,
+ * and dchar, and 2 of each of those.
+ */
+
+private import util.utf;
+
+/**********************************************/
+/* 1 argument versions */
+
+// dg is D, but _aApplyRcd() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d & 0x80)
+        {   char c = cast(char)d;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+        }
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcd1.unittest\n");
+
+    char[] s = "hello"c;
+    int i;
+
+    foreach_reverse(dchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(dchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == '\U00100456'); break;
+            case 2:     assert(d == '\u1234'); break;
+            case 3:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwd1.unittest\n");
+
+    wchar[] s = "hello"w;
+    int i;
+
+    foreach_reverse(dchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(dchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == '\U00100456'); break;
+            case 2:     assert(d == '\u1234'); break;
+            case 3:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        wchar w;
+
+        i--;
+        w = aa[i];
+        if (w & 0x80)
+        {   char c = cast(char)w;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcw1.unittest\n");
+
+    char[] s = "hello"c;
+    int i;
+
+    foreach_reverse(wchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(wchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xDBC1); break;
+            case 2:     assert(d == 0xDC56); break;
+            case 3:     assert(d == 0x1234); break;
+            case 4:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        char c;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        c = cast(char)d;
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwc1.unittest\n");
+
+    wchar[] s = "hello"w;
+    int i;
+
+    foreach_reverse(char d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(char d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xF4); break;
+            case 2:     assert(d == 0x80); break;
+            case 3:     assert(d == 0x91); break;
+            case 4:     assert(d == 0x96); break;
+            case 5:     assert(d == 0xE1); break;
+            case 6:     assert(d == 0x88); break;
+            case 7:     assert(d == 0xB4); break;
+            case 8:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0;)
+    {   dchar d = aa[--i];
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {
+            c = cast(char)d;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdc1.unittest\n");
+
+    dchar[] s = "hello"d;
+    int i;
+
+    foreach_reverse(char d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(char d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xF4); break;
+            case 2:     assert(d == 0x80); break;
+            case 3:     assert(d == 0x91); break;
+            case 4:     assert(d == 0x96); break;
+            case 5:     assert(d == 0xE1); break;
+            case 6:     assert(d == 0x88); break;
+            case 7:     assert(d == 0xB4); break;
+            case 8:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdw1.unittest\n");
+
+    dchar[] s = "hello"d;
+    int i;
+
+    foreach_reverse(wchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(wchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xDBC1); break;
+            case 2:     assert(d == 0xDC56); break;
+            case 3:     assert(d == 0x1234); break;
+            case 4:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+
+/****************************************************************************/
+/* 2 argument versions */
+
+// dg is D, but _aApplyRcd2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
+    for (i = len; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d & 0x80)
+        {   char c = cast(char)d;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+        }
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcd2.unittest\n");
+
+    char[] s = "hello"c;
+    int i;
+
+    foreach_reverse(k, dchar d; s)
+    {
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); assert(k == 8); break;
+            case 1:     assert(d == '\U00100456'); assert(k == 4); break;
+            case 2:     assert(d == '\u1234'); assert(k == 1); break;
+            case 3:     assert(d == 'a'); assert(k == 0); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwd2.unittest\n");
+
+    wchar[] s = "hello"w;
+    int i;
+
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 4); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == '\U00100456'); break;
+            case 2:     assert(k == 1); assert(d == '\u1234'); break;
+            case 3:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        wchar w;
+
+        i--;
+        w = aa[i];
+        if (w & 0x80)
+        {   char c = cast(char)w;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(&i, cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcw2.unittest\n");
+
+    char[] s = "hello"c;
+    int i;
+
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 8); assert(d == 'b'); break;
+            case 1:     assert(k == 4); assert(d == 0xDBC1); break;
+            case 2:     assert(k == 4); assert(d == 0xDC56); break;
+            case 3:     assert(k == 1); assert(d == 0x1234); break;
+            case 4:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        char c;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        c = cast(char)d;
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwc2.unittest\n");
+
+    wchar[] s = "hello"w;
+    int i;
+
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 4); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xF4); break;
+            case 2:     assert(k == 2); assert(d == 0x80); break;
+            case 3:     assert(k == 2); assert(d == 0x91); break;
+            case 4:     assert(k == 2); assert(d == 0x96); break;
+            case 5:     assert(k == 1); assert(d == 0xE1); break;
+            case 6:     assert(k == 1); assert(d == 0x88); break;
+            case 7:     assert(k == 1); assert(d == 0xB4); break;
+            case 8:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)d;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdc2.unittest\n");
+
+    dchar[] s = "hello"d;
+    int i;
+
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 3); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xF4); break;
+            case 2:     assert(k == 2); assert(d == 0x80); break;
+            case 3:     assert(k == 2); assert(d == 0x91); break;
+            case 4:     assert(k == 2); assert(d == 0x96); break;
+            case 5:     assert(k == 1); assert(d == 0xE1); break;
+            case 6:     assert(k == 1); assert(d == 0x88); break;
+            case 7:     assert(k == 1); assert(d == 0xB4); break;
+            case 8:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(&i, cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdw2.unittest\n");
+
+    dchar[] s = "hello"d;
+    int i;
+
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 3); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xDBC1); break;
+            case 2:     assert(k == 2); assert(d == 0xDC56); break;
+            case 3:     assert(k == 1); assert(d == 0x1234); break;
+            case 4:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/aaA.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,837 @@
+//_ aaA.d
+
+/**
+ * Part of the D programming language runtime library.
+ * Implementation of associative arrays.
+ */
+
+/*
+ *  Copyright (C) 2000-2008 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ *  Modified by Tomas Lindquist Olsen <tomas@famolsen.dk> for use with LDC.
+ */
+
+private
+{
+    version( D_Version2 )
+    {
+    import stdc.stdarg;
+    import stdc.string;
+    }
+    else
+    {
+    import tango.stdc.stdarg;
+    import tango.stdc.string;
+    }
+
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) void  gc_free( void* p );
+}
+
+// Auto-rehash and pre-allocate - Dave Fladebo
+
+static size_t[] prime_list = [
+               97UL,            389UL,
+            1_543UL,          6_151UL,
+           24_593UL,         98_317UL,
+          393_241UL,      1_572_869UL,
+        6_291_469UL,     25_165_843UL,
+      100_663_319UL,    402_653_189UL,
+    1_610_612_741UL,  4_294_967_291UL,
+//  8_589_934_513UL, 17_179_869_143UL
+];
+
+struct aaA
+{
+    aaA *left;
+    aaA *right;
+    hash_t hash;
+    /* key   */
+    /* value */
+}
+
+struct BB
+{
+    aaA*[] b;
+    size_t nodes;       // total number of aaA nodes
+    TypeInfo keyti;     // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet() 
+}
+
+/* This is the type actually seen by the programmer, although
+ * it is completely opaque.
+ */
+
+// LDC doesn't pass structs in registers so no need to wrap it ...
+alias BB* AA;
+
+/**********************************
+ * Align to next pointer boundary, so that
+ * GC won't be faced with misaligned pointers
+ * in value.
+ */
+
+size_t aligntsize(size_t tsize)
+{
+    return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
+}
+
+extern (C):
+
+/*************************************************
+ * Invariant for aa.
+ */
+
+/+
+void _aaInvAh(aaA*[] aa)
+{
+    for (size_t i = 0; i < aa.length; i++)
+    {
+        if (aa[i])
+            _aaInvAh_x(aa[i]);
+    }
+}
+
+private int _aaCmpAh_x(aaA *e1, aaA *e2)
+{   int c;
+
+    c = e1.hash - e2.hash;
+    if (c == 0)
+    {
+        c = e1.key.length - e2.key.length;
+        if (c == 0)
+            c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
+    }
+    return c;
+}
+
+private void _aaInvAh_x(aaA *e)
+{
+    hash_t key_hash;
+    aaA *e1;
+    aaA *e2;
+
+    key_hash = getHash(e.key);
+    assert(key_hash == e.hash);
+
+    while (1)
+    {   int c;
+
+        e1 = e.left;
+        if (e1)
+        {
+            _aaInvAh_x(e1);             // ordinary recursion
+            do
+            {
+                c = _aaCmpAh_x(e1, e);
+                assert(c < 0);
+                e1 = e1.right;
+            } while (e1 != null);
+        }
+
+        e2 = e.right;
+        if (e2)
+        {
+            do
+            {
+                c = _aaCmpAh_x(e, e2);
+                assert(c < 0);
+                e2 = e2.left;
+            } while (e2 != null);
+            e = e.right;                // tail recursion
+        }
+        else
+            break;
+    }
+}
++/
+
+/****************************************************
+ * Determine number of entries in associative array.
+ */
+
+size_t _aaLen(AA aa)
+in
+{
+    //printf("_aaLen()+\n");
+    //_aaInv(aa);
+}
+out (result)
+{
+    size_t len = 0;
+
+    void _aaLen_x(aaA* ex)
+    {
+        auto e = ex;
+        len++;
+
+        while (1)
+        {
+            if (e.right)
+               _aaLen_x(e.right);
+            e = e.left;
+            if (!e)
+                break;
+            len++;
+        }
+    }
+
+    if (aa)
+    {
+        foreach (e; aa.b)
+        {
+            if (e)
+                _aaLen_x(e);
+        }
+    }
+    assert(len == result);
+
+    //printf("_aaLen()-\n");
+}
+body
+{
+    return aa ? aa.nodes : 0;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Add entry for key if it is not already there.
+ */
+
+void* _aaGet(AA* aa_arg, TypeInfo keyti, size_t valuesize, void* pkey)
+in
+{
+    assert(aa_arg);
+}
+out (result)
+{
+    assert(result);
+    assert(*aa_arg);
+    assert((*aa_arg).b.length);
+    //assert(_aaInAh(*aa, key));
+}
+body
+{
+    //auto pkey = cast(void *)(&valuesize + 1);
+    size_t i;
+    aaA *e;
+    auto keysize = aligntsize(keyti.tsize());
+
+    if (!*aa_arg)
+        *aa_arg = new BB();
+    auto aa = *aa_arg;
+    aa.keyti = keyti;
+
+    if (!aa.b.length)
+    {
+        alias aaA *pa;
+        auto len = prime_list[0];
+
+        aa.b = new pa[len];
+    }
+
+    auto key_hash = keyti.getHash(pkey);
+    //printf("hash = %d\n", key_hash);
+    i = key_hash % aa.b.length;
+    auto pe = &aa.b[i];
+    while ((e = *pe) !is null)
+    {
+        if (key_hash == e.hash)
+        {
+            auto c = keyti.compare(pkey, e + 1);
+            if (c == 0)
+                goto Lret;
+            pe = (c < 0) ? &e.left : &e.right;
+        }
+        else
+            pe = (key_hash < e.hash) ? &e.left : &e.right;
+    }
+
+    // Not found, create new elem
+    //printf("create new one\n");
+    size_t size = aaA.sizeof + keysize + valuesize;
+    e = cast(aaA *) gc_calloc(size);
+    memcpy(e + 1, pkey, keysize);
+    e.hash = key_hash;
+    *pe = e;
+
+    auto nodes = ++aa.nodes;
+    //printf("length = %d, nodes = %d\n", (*aa).length, nodes);
+    if (nodes > aa.b.length * 4)
+    {
+        _aaRehash(aa_arg,keyti);
+    }
+
+Lret:
+    return cast(void *)(e + 1) + keysize;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Returns null if it is not already there.
+ */
+
+void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, void *pkey)
+{
+    //printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
+    if (!aa)
+        return null;
+
+    //auto pkey = cast(void *)(&valuesize + 1);
+    auto keysize = aligntsize(keyti.tsize());
+    auto len = aa.b.length;
+
+    if (len)
+    {
+        auto key_hash = keyti.getHash(pkey);
+        //printf("hash = %d\n", key_hash);
+        size_t i = key_hash % len;
+        auto e = aa.b[i];
+        while (e !is null)
+        {
+            if (key_hash == e.hash)
+            {
+                auto c = keyti.compare(pkey, e + 1);
+            if (c == 0)
+                return cast(void *)(e + 1) + keysize;
+                e = (c < 0) ? e.left : e.right;
+            }
+            else
+                e = (key_hash < e.hash) ? e.left : e.right;
+        }
+    }
+    return null;    // not found, caller will throw exception
+}
+
+
+/*************************************************
+ * Determine if key is in aa.
+ * Returns:
+ *      null    not in aa
+ *      !=null  in aa, return pointer to value
+ */
+
+void* _aaIn(AA aa, TypeInfo keyti, void *pkey)
+in
+{
+}
+out (result)
+{
+    //assert(result == 0 || result == 1);
+}
+body
+{
+    if (aa)
+    {
+        //auto pkey = cast(void *)(&keyti + 1);
+
+        //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr);
+        auto len = aa.b.length;
+
+        if (len)
+        {
+            auto key_hash = keyti.getHash(pkey);
+            //printf("hash = %d\n", key_hash);
+            size_t i = key_hash % len;
+            auto e = aa.b[i];
+            while (e !is null)
+            {
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(pkey, e + 1);
+                    if (c == 0)
+                        return cast(void *)(e + 1) + aligntsize(keyti.tsize());
+                    e = (c < 0) ? e.left : e.right;
+                }
+                else
+                    e = (key_hash < e.hash) ? e.left : e.right;
+            }
+        }
+    }
+
+    // Not found
+    return null;
+}
+
+/*************************************************
+ * Delete key entry in aa[].
+ * If key is not in aa[], do nothing.
+ */
+
+void _aaDel(AA aa, TypeInfo keyti, void *pkey)
+{
+    //auto pkey = cast(void *)(&keyti + 1);
+    aaA *e;
+
+    if (aa && aa.b.length)
+    {
+        auto key_hash = keyti.getHash(pkey);
+        //printf("hash = %d\n", key_hash);
+        size_t i = key_hash % aa.b.length;
+        auto pe = &aa.b[i];
+        while ((e = *pe) !is null) // null means not found
+        {
+            if (key_hash == e.hash)
+            {
+                auto c = keyti.compare(pkey, e + 1);
+                if (c == 0)
+                {
+                    if (!e.left && !e.right)
+                    {
+                        *pe = null;
+                    }
+                    else if (e.left && !e.right)
+                    {
+                        *pe = e.left;
+                         e.left = null;
+                    }
+                    else if (!e.left && e.right)
+                    {
+                        *pe = e.right;
+                         e.right = null;
+                    }
+                    else
+                    {
+                        *pe = e.left;
+                        e.left = null;
+                        do
+                            pe = &(*pe).right;
+                        while (*pe);
+                        *pe = e.right;
+                        e.right = null;
+                    }
+
+                    aa.nodes--;
+                    gc_free(e);
+
+                    break;
+                }
+                pe = (c < 0) ? &e.left : &e.right;
+            }
+            else
+                pe = (key_hash < e.hash) ? &e.left : &e.right;
+        }
+    }
+}
+
+
+/********************************************
+ * Produce array of values from aa.
+ * The actual type is painted on the return value by the frontend
+ * This means the returned length should be the number of elements
+ */
+
+void[] _aaValues(AA aa, size_t keysize, size_t valuesize)
+in
+{
+    assert(keysize == aligntsize(keysize));
+}
+body
+{
+    size_t resi;
+    void[] a;
+
+    void _aaValues_x(aaA* e)
+    {
+        do
+        {
+            memcpy(a.ptr + resi * valuesize,
+                   cast(byte*)e + aaA.sizeof + keysize,
+                   valuesize);
+            resi++;
+            if (e.left)
+            {   if (!e.right)
+                {   e = e.left;
+                    continue;
+                }
+                _aaValues_x(e.left);
+            }
+            e = e.right;
+        } while (e !is null);
+    }
+
+    if (aa)
+    {
+        auto len = _aaLen(aa);
+        auto ptr = cast(byte*) gc_malloc(len * valuesize,
+                                      valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
+        a = ptr[0 .. len];
+        resi = 0;
+        foreach (e; aa.b)
+        {
+            if (e)
+                _aaValues_x(e);
+        }
+        assert(resi == a.length);
+    }
+    return a;
+}
+
+
+/********************************************
+ * Rehash an array.
+ */
+
+void* _aaRehash(AA* paa, TypeInfo keyti)
+in
+{
+    //_aaInvAh(paa);
+}
+out (result)
+{
+    //_aaInvAh(result);
+}
+body
+{
+    BB newb;
+
+    void _aaRehash_x(aaA* olde)
+    {
+        while (1)
+        {
+            auto left = olde.left;
+            auto right = olde.right;
+            olde.left = null;
+            olde.right = null;
+
+            aaA *e;
+
+            //printf("rehash %p\n", olde);
+            auto key_hash = olde.hash;
+            size_t i = key_hash % newb.b.length;
+            auto pe = &newb.b[i];
+            while ((e = *pe) !is null)
+            {
+                //printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
+                assert(e.left != e);
+                assert(e.right != e);
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(olde + 1, e + 1);
+                    assert(c != 0);
+                    pe = (c < 0) ? &e.left : &e.right;
+                }
+                else
+                    pe = (key_hash < e.hash) ? &e.left : &e.right;
+            }
+            *pe = olde;
+
+            if (right)
+            {
+                if (!left)
+                {   olde = right;
+                    continue;
+                }
+                _aaRehash_x(right);
+            }
+            if (!left)
+                break;
+            olde = left;
+        }
+    }
+
+    //printf("Rehash\n");
+    if (*paa)
+    {
+        auto aa = *paa;
+        auto len = _aaLen(aa);
+        if (len)
+        {   size_t i;
+
+            for (i = 0; i < prime_list.length - 1; i++)
+            {
+                if (len <= prime_list[i])
+                    break;
+            }
+            len = prime_list[i];
+            newb.b = new aaA*[len];
+            newb.keyti = keyti;
+
+            foreach (e; aa.b)
+            {
+                if (e)
+                    _aaRehash_x(e);
+            }
+
+            newb.nodes = (*aa).nodes;
+        }
+
+        **paa = newb;
+    }
+    return *paa;
+}
+
+
+/********************************************
+ * Produce array of N byte keys from aa.
+ * The actual type is painted on the return value by the frontend
+ * This means the returned length should be the number of elements
+ */
+
+void[] _aaKeys(AA aa, size_t keysize)
+{
+    byte[] res;
+    size_t resi;
+
+    void _aaKeys_x(aaA* e)
+    {
+        do
+        {
+            memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
+            resi++;
+            if (e.left)
+            {   if (!e.right)
+                {   e = e.left;
+                    continue;
+                }
+                _aaKeys_x(e.left);
+            }
+            e = e.right;
+        } while (e !is null);
+    }
+
+    auto len = _aaLen(aa);
+    if (!len)
+        return null;
+    res = (cast(byte*) gc_malloc(len * keysize,
+                                 !(aa.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0)) [0 .. len * keysize];
+    resi = 0;
+    foreach (e; aa.b)
+    {
+        if (e)
+            _aaKeys_x(e);
+    }
+    assert(resi == len);
+
+    return res.ptr[0 .. len];
+}
+
+
+/**********************************************
+ * 'apply' for associative arrays - to support foreach
+ */
+
+// dg is D, but _aaApply() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+int _aaApply(AA aa, size_t keysize, dg_t dg)
+in
+{
+    assert(aligntsize(keysize) == keysize);
+}
+body
+{   int result;
+
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
+
+    int treewalker(aaA* e)
+    {   int result;
+
+        do
+        {
+            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
+            result = dg(cast(void *)(e + 1) + keysize);
+            if (result)
+                break;
+            if (e.right)
+            {   if (!e.left)
+                {
+                    e = e.right;
+                    continue;
+                }
+                result = treewalker(e.right);
+                if (result)
+                    break;
+            }
+            e = e.left;
+        } while (e);
+
+        return result;
+    }
+
+    if (aa)
+    {
+        foreach (e; aa.b)
+        {
+            if (e)
+            {
+                result = treewalker(e);
+                if (result)
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+// dg is D, but _aaApply2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+int _aaApply2(AA aa, size_t keysize, dg2_t dg)
+in
+{
+    assert(aligntsize(keysize) == keysize);
+}
+body
+{   int result;
+
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
+
+    int treewalker(aaA* e)
+    {   int result;
+
+        do
+        {
+            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
+            result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
+            if (result)
+                break;
+            if (e.right)
+            {   if (!e.left)
+                {
+                    e = e.right;
+                    continue;
+                }
+                result = treewalker(e.right);
+                if (result)
+                    break;
+            }
+            e = e.left;
+        } while (e);
+
+        return result;
+    }
+
+    if (aa)
+    {
+        foreach (e; aa.b)
+        {
+            if (e)
+            {
+                result = treewalker(e);
+                if (result)
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+
+/***********************************
+ * Construct an associative array of type ti from
+ * length pairs of key/value pairs.
+ */
+
+/+
+
+extern (C)
+BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
+{
+    auto valuesize = ti.next.tsize();           // value size
+    auto keyti = ti.key;
+    auto keysize = keyti.tsize();               // key size
+    BB* result;
+
+    //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
+    //printf("tivalue = %.*s\n", ti.next.classinfo.name);
+    if (length == 0 || valuesize == 0 || keysize == 0)
+    {
+        ;
+    }
+    else
+    {
+        va_list q;
+        va_start!(size_t)(q, length);
+
+        result = new BB();
+        size_t i;
+
+        for (i = 0; i < prime_list.length - 1; i++)
+        {
+            if (length <= prime_list[i])
+                break;
+        }
+        auto len = prime_list[i];
+        result.b = new aaA*[len];
+
+        size_t keystacksize   = (keysize   + int.sizeof - 1) & ~(int.sizeof - 1);
+        size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
+
+        size_t keytsize = aligntsize(keysize);
+
+        for (size_t j = 0; j < length; j++)
+        {   void* pkey = q;
+            q += keystacksize;
+            void* pvalue = q;
+            q += valuestacksize;
+            aaA* e;
+
+            auto key_hash = keyti.getHash(pkey);
+            //printf("hash = %d\n", key_hash);
+            i = key_hash % len;
+            auto pe = &result.b[i];
+            while (1)
+            {
+                e = *pe;
+                if (!e)
+                {
+                    // Not found, create new elem
+                    //printf("create new one\n");
+                    e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
+                    memcpy(e + 1, pkey, keysize);
+                    e.hash = key_hash;
+                    *pe = e;
+                    result.nodes++;
+                    break;
+                }
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(pkey, e + 1);
+                    if (c == 0)
+                        break;
+                    pe = (c < 0) ? &e.left : &e.right;
+                }
+                else
+                    pe = (key_hash < e.hash) ? &e.left : &e.right;
+            }
+            memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
+        }
+
+        va_end(q);
+    }
+    return result;
+}
+
++/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/adi.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,602 @@
+//_ adi.d
+
+/**
+ * Part of the D programming language runtime library.
+ * Dynamic array property support routines
+ */
+
+/*
+ *  Copyright (C) 2000-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+
+//debug=adi;            // uncomment to turn on debugging printf's
+
+private
+{
+    version( D_Version2 )
+    {
+    import stdc.stdlib;
+    import stdc.string;
+    }
+    else
+    {
+    import tango.stdc.stdlib;
+    import tango.stdc.string;
+    }
+    import util.utf;
+
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) void  gc_free( void* p );
+}
+
+
+/**********************************************
+ * Reverse array of chars.
+ * Handled separately because embedded multibyte encodings should not be
+ * reversed.
+ */
+
+extern (C) char[] _adReverseChar(char[] a)
+{
+    if (a.length > 1)
+    {
+        char[6] tmp;
+        char[6] tmplo;
+        char* lo = a.ptr;
+        char* hi = &a[length - 1];
+
+        while (lo < hi)
+        {   auto clo = *lo;
+            auto chi = *hi;
+
+	    debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
+            if (clo <= 0x7F && chi <= 0x7F)
+            {
+		debug(adi) printf("\tascii\n");
+                *lo = chi;
+                *hi = clo;
+                lo++;
+                hi--;
+                continue;
+            }
+
+            uint stridelo = UTF8stride[clo];
+            // don't barf on invalid strides, just ignore it
+            if (stridelo == 0xFF)
+                stridelo = 1;
+
+            uint stridehi = 1;
+            while ((chi & 0xC0) == 0x80)
+            {
+                chi = *--hi;
+                stridehi++;
+                assert(hi >= lo);
+            }
+            if (lo == hi)
+                break;
+
+	    debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
+            if (stridelo == stridehi)
+            {
+
+                memcpy(tmp.ptr, lo, stridelo);
+                memcpy(lo, hi, stridelo);
+                memcpy(hi, tmp.ptr, stridelo);
+                lo += stridelo;
+                hi--;
+                continue;
+            }
+
+            /* Shift the whole array. This is woefully inefficient
+             */
+            memcpy(tmp.ptr, hi, stridehi);
+            memcpy(tmplo.ptr, lo, stridelo);
+            memmove(lo + stridehi, lo + stridelo , cast(size_t)(hi - lo) - stridelo);
+            memcpy(lo, tmp.ptr, stridehi);
+            memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
+
+            lo += stridehi;
+            hi = hi - 1 + (stridehi - stridelo);
+        }
+    }
+    return a;
+}
+
+unittest
+{
+    char[] a = "abcd"c;
+
+    char[] r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "dcba");
+
+    a = "a\u1235\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234\u1235a");
+
+    a = "ab\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234ba");
+
+    a = "\u3026\u2021\u3061\n";
+    r = a.dup.reverse;
+    assert(r == "\n\u3061\u2021\u3026");
+}
+
+
+/**********************************************
+ * Reverse array of wchars.
+ * Handled separately because embedded multiword encodings should not be
+ * reversed.
+ */
+
+extern (C) wchar[] _adReverseWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+        wchar[2] tmp;
+        wchar* lo = a.ptr;
+        wchar* hi = &a[length - 1];
+
+        while (lo < hi)
+        {   auto clo = *lo;
+            auto chi = *hi;
+
+            if ((clo < 0xD800 || clo > 0xDFFF) &&
+                (chi < 0xD800 || chi > 0xDFFF))
+            {
+                *lo = chi;
+                *hi = clo;
+                lo++;
+                hi--;
+                continue;
+            }
+
+            int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
+
+            int stridehi = 1;
+            if (chi >= 0xDC00 && chi <= 0xDFFF)
+            {
+                chi = *--hi;
+                stridehi++;
+                assert(hi >= lo);
+            }
+            if (lo == hi)
+                break;
+
+            if (stridelo == stridehi)
+            {   int stmp;
+
+                assert(stridelo == 2);
+                assert(stmp.sizeof == 2 * (*lo).sizeof);
+                stmp = *cast(int*)lo;
+                *cast(int*)lo = *cast(int*)hi;
+                *cast(int*)hi = stmp;
+                lo += stridelo;
+                hi--;
+                continue;
+            }
+
+            /* Shift the whole array. This is woefully inefficient
+             */
+            memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
+            memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
+            memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
+            memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
+
+            lo += stridehi;
+            hi = hi - 1 + (stridehi - stridelo);
+        }
+    }
+    return a;
+}
+
+unittest
+{
+    wchar[] a = "abcd";
+    wchar[] r;
+
+    r = a.dup.reverse;
+    assert(r == "dcba");
+
+    a = "a\U00012356\U00012346c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012346\U00012356a");
+
+    a = "ab\U00012345c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012345ba");
+}
+
+
+/**********************************************
+ * Support for array.reverse property.
+ * The actual type is painted on the return value by the frontend
+ * Given and returned length are number of elements
+ */
+
+extern (C) void[] _adReverse(void[] a, size_t szelem)
+    out (result)
+    {
+        assert(result.ptr is a.ptr);
+    }
+    body
+    {
+        if (a.length >= 2)
+        {
+            byte*    tmp;
+            byte[16] buffer;
+
+            void* lo = a.ptr;
+            void* hi = a.ptr + (a.length - 1) * szelem;
+
+            tmp = buffer.ptr;
+            if (szelem > 16)
+            {
+                //version (Win32)
+                    //tmp = cast(byte*) alloca(szelem);
+                //else
+                    tmp = cast(byte*) gc_malloc(szelem);
+            }
+
+            for (; lo < hi; lo += szelem, hi -= szelem)
+            {
+                memcpy(tmp, lo,  szelem);
+                memcpy(lo,  hi,  szelem);
+                memcpy(hi,  tmp, szelem);
+            }
+
+            version (Win32)
+            {
+            }
+            else
+            {
+                //if (szelem > 16)
+                    // BUG: bad code is generate for delete pointer, tries
+                    // to call delclass.
+                    //gc_free(tmp);
+            }
+        }
+        return a.ptr[0 .. a.length];
+    }
+
+unittest
+{
+    debug(adi) printf("array.reverse.unittest\n");
+
+    int[] a = new int[5];
+    int[] b;
+    size_t i;
+
+    for (i = 0; i < 5; i++)
+        a[i] = i;
+    b = a.reverse;
+    assert(b is a);
+    for (i = 0; i < 5; i++)
+        assert(a[i] == 4 - i);
+
+    struct X20
+    {   // More than 16 bytes in size
+        int a;
+        int b, c, d, e;
+    }
+
+    X20[] c = new X20[5];
+    X20[] d;
+
+    for (i = 0; i < 5; i++)
+    {   c[i].a = i;
+        c[i].e = 10;
+    }
+    d = c.reverse;
+    assert(d is c);
+    for (i = 0; i < 5; i++)
+    {
+        assert(c[i].a == 4 - i);
+        assert(c[i].e == 10);
+    }
+}
+
+/**********************************************
+ * Sort array of chars.
+ */
+
+extern (C) char[] _adSortChar(char[] a)
+{
+    if (a.length > 1)
+    {
+	dstring da = toUTF32(a);
+        da.sort;
+        size_t i = 0;
+        foreach (dchar d; da)
+        {   char[4] buf;
+            auto t = toUTF8(buf, d);
+            a[i .. i + t.length] = t[];
+            i += t.length;
+        }
+        delete da;
+    }
+    return a;
+}
+
+/**********************************************
+ * Sort array of wchars.
+ */
+
+extern (C) wchar[] _adSortWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+	dstring da = toUTF32(a);
+        da.sort;
+        size_t i = 0;
+        foreach (dchar d; da)
+        {   wchar[2] buf;
+	    auto t = toUTF16(buf, d);
+            a[i .. i + t.length] = t[];
+            i += t.length;
+        }
+        delete da;
+    }
+    return a;
+}
+
+/***************************************
+ * Support for array equality test.
+ * The actual type is painted on the return value by the frontend
+ * Given lengths are number of elements
+ */
+
+extern (C) int _adEq(void[] a1, void[] a2, TypeInfo ti)
+{
+    debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+
+    if (a1.length != a2.length)
+        return 0;               // not equal
+    else if (a1.ptr == a2.ptr)
+        return 1;               // equal
+
+    // let typeinfo decide
+    return ti.equals(&a1, &a2);
+}
+
+unittest
+{
+    debug(adi) printf("array.Eq unittest\n");
+
+    char[] a = "hello"c;
+
+    assert(a != "hel");
+    assert(a != "helloo");
+    assert(a != "betty");
+    assert(a == "hello");
+    assert(a != "hxxxx");
+}
+
+/***************************************
+ * Support for array compare test.
+ * The actual type is painted on the return value by the frontend
+ * Given lengths are number of elements
+ */
+
+extern (C) int _adCmp(void[] a1, void[] a2, TypeInfo ti)
+{
+    debug(adi) printf("adCmp()\n");
+
+    if (a1.ptr == a2.ptr &&
+        a1.length == a2.length)
+        return 0;
+
+    auto len = a1.length;
+    if (a2.length < len)
+        len = a2.length;
+
+    // let typeinfo decide
+    return ti.compare(&a1, &a2);
+}
+
+unittest
+{
+    debug(adi) printf("array.Cmp unittest\n");
+
+    char[] a = "hello"c;
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
+
+/***************************************
+ * Support for array compare test.
+ * The actual type is painted on the return value by the frontend
+ * Given lengths are number of elements
+ */
+
+extern (C) int _adCmpChar(void[] a1, void[] a2)
+{
+  version(D_InlineAsm_X86)
+  {
+  //version = Asm86;
+  }
+  version (Asm86)
+  {
+    asm
+    {   naked                   ;
+
+        push    EDI             ;
+        push    ESI             ;
+
+        mov    ESI,a1+4[4+ESP]  ;
+        mov    EDI,a2+4[4+ESP]  ;
+
+        mov    ECX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        cmp     ECX,EDX         ;
+        jb      GotLength       ;
+
+        mov     ECX,EDX         ;
+
+GotLength:
+        cmp    ECX,4            ;
+        jb    DoBytes           ;
+
+        // Do alignment if neither is dword aligned
+        test    ESI,3           ;
+        jz    Aligned           ;
+
+        test    EDI,3           ;
+        jz    Aligned           ;
+DoAlign:
+        mov    AL,[ESI]         ; //align ESI to dword bounds
+        mov    DL,[EDI]         ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        inc    ESI              ;
+        inc    EDI              ;
+
+        test    ESI,3           ;
+
+        lea    ECX,[ECX-1]      ;
+        jnz    DoAlign          ;
+Aligned:
+        mov    EAX,ECX          ;
+
+        // do multiple of 4 bytes at a time
+
+        shr    ECX,2            ;
+        jz    TryOdd            ;
+
+        repe                    ;
+        cmpsd                   ;
+
+        jnz    UnequalQuad      ;
+
+TryOdd:
+        mov    ECX,EAX          ;
+DoBytes:
+        // if still equal and not end of string, do up to 3 bytes slightly
+        // slower.
+
+        and    ECX,3            ;
+        jz    Equal             ;
+
+        repe                    ;
+        cmpsb                   ;
+
+        jnz    Unequal          ;
+Equal:
+        mov    EAX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        sub    EAX,EDX          ;
+        pop    ESI              ;
+
+        pop    EDI              ;
+        ret                     ;
+
+UnequalQuad:
+        mov    EDX,[EDI-4]      ;
+        mov    EAX,[ESI-4]      ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        cmp    AH,DH            ;
+        jnz    Unequal          ;
+
+        shr    EAX,16           ;
+
+        shr    EDX,16           ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        cmp    AH,DH            ;
+Unequal:
+        sbb    EAX,EAX          ;
+        pop    ESI              ;
+
+        or     EAX,1            ;
+        pop    EDI              ;
+
+        ret                     ;
+    }
+  }
+  else
+  {
+    int len;
+    int c;
+
+    debug(adi) printf("adCmpChar()\n");
+    len = cast(int)a1.length;
+    if (a2.length < len)
+        len = cast(int)a2.length;
+    c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
+    if (!c)
+        c = cast(int)a1.length - cast(int)a2.length;
+    return c;
+  }
+}
+
+unittest
+{
+    debug(adi) printf("array.CmpChar unittest\n");
+
+    char[] a = "hello"c;
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/arrayInit.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,158 @@
+private import ldc.intrinsics;
+
+extern(C):
+
+int memcmp(void*,void*,size_t);
+size_t strlen(char*);
+
+version(LLVM64)
+alias llvm_memcpy_i64 llvm_memcpy;
+else
+alias llvm_memcpy_i32 llvm_memcpy;
+
+// per-element array init routines
+
+void _d_array_init_i1(bool* a, size_t n, bool v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i8(ubyte* a, size_t n, ubyte v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i16(ushort* a, size_t n, ushort v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i32(uint* a, size_t n, uint v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i64(ulong* a, size_t n, ulong v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_float(float* a, size_t n, float v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_double(double* a, size_t n, double v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_real(real* a, size_t n, real v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_cfloat(cfloat* a, size_t n, cfloat v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_cdouble(cdouble* a, size_t n, cdouble v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_creal(creal* a, size_t n, creal v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_pointer(void** a, size_t n, void* v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_mem(void* a, size_t na, void* v, size_t nv)
+{
+    auto p = a;
+    auto end = a + na*nv;
+    while (p !is end) {
+        llvm_memcpy(p,v,nv,0);
+        p += nv;
+    }
+}
+
+/*
+void _d_array_init(TypeInfo ti, void* a)
+{
+    auto initializer = ti.next.init();
+    auto isize = initializer.length;
+    auto q = initializer.ptr;
+
+    if (isize == 1)
+        memset(p, *cast(ubyte*)q, size);
+    else if (isize == int.sizeof)
+    {
+        int init = *cast(int*)q;
+        size /= int.sizeof;
+        for (size_t u = 0; u < size; u++)
+        {
+            (cast(int*)p)[u] = init;
+        }
+    }
+    else
+    {
+        for (size_t u = 0; u < size; u += isize)
+        {
+            memcpy(p + u, q, isize);
+        }
+    }
+}*/
+
+// for array cast
+size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz)
+{
+    if (newelemsz == 1) {
+        return len*elemsz;
+    }
+    else if ((len*elemsz) % newelemsz) {
+        throw new Exception("Bad array cast");
+    }
+    return (len*elemsz)/newelemsz;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/cast.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,196 @@
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+extern (C):
+
+//debug = PRINTF;
+debug(PRINTF) int printf(char*, ...);
+
+/******************************************
+ * Given a pointer:
+ *      If it is an Object, return that Object.
+ *      If it is an interface, return the Object implementing the interface.
+ *      If it is null, return null.
+ *      Else, undefined crash
+ */
+
+Object _d_toObject(void* p)
+{   Object o;
+    debug(PRINTF) printf("toObject(%p)\n", p);
+    if (p)
+    {
+        o = cast(Object)p;
+        debug(PRINTF) printf("o = %p\n", o);
+        debug(PRINTF) printf("o.vtbl = %p\n", *cast(void**)p);
+        ClassInfo oc = o.classinfo;
+        debug(PRINTF) printf("oc = %p\n", oc);
+        Interface *pi = **cast(Interface ***)p;
+        debug(PRINTF) printf("pi = %p\n", pi);
+
+        /* Interface.offset lines up with ClassInfo.name.ptr,
+         * so we rely on pointers never being less than 64K,
+         * and interface vtable offsets never being greater.
+         */
+        if (pi.offset < 0x10000)
+        {
+            debug(PRINTF) printf("\tpi.offset = %d\n", pi.offset);
+            o = cast(Object)(p - pi.offset);
+        }
+    }
+    debug(PRINTF) printf("toObject = %p\n", o);
+    return o;
+}
+
+
+/*************************************
+ * Attempts to cast Object o to class c.
+ * Returns o if successful, null if not.
+ */
+
+Object _d_interface_cast(void* p, ClassInfo c)
+{   Object o;
+
+    debug(PRINTF) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name.length, c.name.ptr);
+    if (p)
+    {
+        Interface *pi = **cast(Interface ***)p;
+
+        debug(PRINTF) printf("\tpi.offset = %d\n", pi.offset);
+        o = cast(Object)(p - pi.offset);
+        return _d_dynamic_cast(o, c);
+    }
+    debug(PRINTF) printf("_d_interface_cast = %p\n", o);
+    return o;
+}
+
+Object _d_dynamic_cast(Object o, ClassInfo c)
+{   ClassInfo oc;
+    size_t offset = 0;
+
+    debug(PRINTF) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name.length, c.name.ptr);
+
+    if (o)
+    {
+        oc = o.classinfo;
+        if (_d_isbaseof2(oc, c, offset))
+        {
+            debug(PRINTF) printf("\toffset = %d\n", offset);
+            o = cast(Object)(cast(void*)o + offset);
+        }
+        else
+            o = null;
+    }
+    //printf("\tresult = %p\n", o);
+    debug(PRINTF) printf("_d_dynamic_cast = %p\n", o);
+    return o;
+}
+
+int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
+{   int i;
+
+    debug(PRINTF) printf("_d_isbaseof2(%.*s, %.*s, %ul)\n", oc.name.length, oc.name.ptr, c.name.length, c.name.ptr, offset);
+
+    if (oc is c)
+        return 1;
+    do
+    {
+        debug(PRINTF) printf("oc.interfaces.length = %ul\n", oc.interfaces.length);
+        if (oc.base is c)
+            return 1;
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            debug(PRINTF) printf("checking %.*s\n", ic.name.length, ic.name.ptr);
+            if (ic is c)
+            {   offset = cast(size_t)oc.interfaces[i].offset;
+                return 1;
+            }
+        }
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            if (_d_isbaseof2(ic, c, offset))
+            {   offset = cast(size_t)oc.interfaces[i].offset;
+                return 1;
+            }
+        }
+        oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+int _d_isbaseof(ClassInfo oc, ClassInfo c)
+{   int i;
+
+    if (oc is c)
+        return 1;
+    do
+    {
+        if (oc.base is c)
+            return 1;
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            if (ic is c || _d_isbaseof(ic, c))
+                return 1;
+        }
+        oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+/*********************************
+ * Find the vtbl[] associated with Interface ic.
+ */
+
+void *_d_interface_vtbl(ClassInfo ic, Object o)
+{   int i;
+    ClassInfo oc;
+
+    //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
+
+    assert(o);
+
+    oc = o.classinfo;
+    for (i = 0; i < oc.interfaces.length; i++)
+    {
+        ClassInfo oic;
+
+        oic = oc.interfaces[i].classinfo;
+        if (oic is ic)
+        {
+            return cast(void *)oc.interfaces[i].vtbl;
+        }
+    }
+    assert(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/critical.c	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,164 @@
+/*
+ * Placed into the Public Domain
+ * written by Walter Bright, Digital Mars
+ * www.digitalmars.com
+ */
+
+/* ================================= Win32 ============================ */
+
+#if _WIN32
+
+#include	<windows.h>
+
+/******************************************
+ * Enter/exit critical section.
+ */
+
+/* We don't initialize critical sections unless we actually need them.
+ * So keep a linked list of the ones we do use, and in the static destructor
+ * code, walk the list and release them.
+ */
+
+typedef struct D_CRITICAL_SECTION
+{
+    struct D_CRITICAL_SECTION *next;
+    CRITICAL_SECTION cs;
+} D_CRITICAL_SECTION;
+
+static D_CRITICAL_SECTION *dcs_list;
+static D_CRITICAL_SECTION critical_section;
+static volatile int inited;
+
+void _d_criticalenter(D_CRITICAL_SECTION *dcs)
+{
+    if (!dcs->next)
+    {
+	EnterCriticalSection(&critical_section.cs);
+	if (!dcs->next)	// if, in the meantime, another thread didn't set it
+	{
+	    dcs->next = dcs_list;
+	    dcs_list = dcs;
+	    InitializeCriticalSection(&dcs->cs);
+	}
+	LeaveCriticalSection(&critical_section.cs);
+    }
+    EnterCriticalSection(&dcs->cs);
+}
+
+void _d_criticalexit(D_CRITICAL_SECTION *dcs)
+{
+    LeaveCriticalSection(&dcs->cs);
+}
+
+void _STI_critical_init()
+{
+    if (!inited)
+    {	InitializeCriticalSection(&critical_section.cs);
+	dcs_list = &critical_section;
+	inited = 1;
+    }
+}
+
+void _STD_critical_term()
+{
+    if (inited)
+    {	inited = 0;
+	while (dcs_list)
+	{
+	    DeleteCriticalSection(&dcs_list->cs);
+	    dcs_list = dcs_list->next;
+	}
+    }
+}
+
+#endif
+
+/* ================================= linux ============================ */
+
+#if linux || __APPLE__ || __FreeBSD__
+
+#include	<stdio.h>
+#include	<stdlib.h>
+#include	<pthread.h>
+
+#if !linux
+#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
+#endif
+
+/******************************************
+ * Enter/exit critical section.
+ */
+
+/* We don't initialize critical sections unless we actually need them.
+ * So keep a linked list of the ones we do use, and in the static destructor
+ * code, walk the list and release them.
+ */
+
+typedef struct D_CRITICAL_SECTION
+{
+    struct D_CRITICAL_SECTION *next;
+    pthread_mutex_t cs;
+} D_CRITICAL_SECTION;
+
+static D_CRITICAL_SECTION *dcs_list;
+static D_CRITICAL_SECTION critical_section;
+static pthread_mutexattr_t _criticals_attr;
+
+void _STI_critical_init(void);
+void _STD_critical_term(void);
+
+void _d_criticalenter(D_CRITICAL_SECTION *dcs)
+{
+    if (!dcs_list)
+    {	_STI_critical_init();
+	atexit(_STD_critical_term);
+    }
+    //printf("_d_criticalenter(dcs = x%x)\n", dcs);
+    if (!dcs->next)
+    {
+	pthread_mutex_lock(&critical_section.cs);
+	if (!dcs->next)	// if, in the meantime, another thread didn't set it
+	{
+	    dcs->next = dcs_list;
+	    dcs_list = dcs;
+	    pthread_mutex_init(&dcs->cs, &_criticals_attr);
+	}
+	pthread_mutex_unlock(&critical_section.cs);
+    }
+    pthread_mutex_lock(&dcs->cs);
+}
+
+void _d_criticalexit(D_CRITICAL_SECTION *dcs)
+{
+    //printf("_d_criticalexit(dcs = x%x)\n", dcs);
+    pthread_mutex_unlock(&dcs->cs);
+}
+
+void _STI_critical_init()
+{
+    if (!dcs_list)
+    {	//printf("_STI_critical_init()\n");
+	pthread_mutexattr_init(&_criticals_attr);
+	pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE_NP);
+
+	// The global critical section doesn't need to be recursive
+	pthread_mutex_init(&critical_section.cs, 0);
+	dcs_list = &critical_section;
+    }
+}
+
+void _STD_critical_term()
+{
+    if (dcs_list)
+    {	//printf("_STI_critical_term()\n");
+	while (dcs_list)
+	{
+	    //printf("\tlooping... %x\n", dcs_list);
+	    pthread_mutex_destroy(&dcs_list->cs);
+	    dcs_list = dcs_list->next;
+	}
+    }
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/dmain2.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,314 @@
+/*
+ * Placed into the Public Domain.
+ * written by Walter Bright
+ * www.digitalmars.com
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+private
+{
+    import util.console;
+
+    version( D_Version2)
+    {
+    import stdc.stddef;
+    import stdc.stdlib;
+    import stdc.string;
+    }
+    else
+    {
+    import tango.stdc.stddef;
+    import tango.stdc.stdlib;
+    import tango.stdc.string;
+    }
+    import memory;
+}
+
+version( Win32 )
+{
+    extern (Windows) void*      LocalFree(void*);
+    extern (Windows) wchar_t*   GetCommandLineW();
+    extern (Windows) wchar_t**  CommandLineToArgvW(wchar_t*, int*);
+    extern (Windows) export int WideCharToMultiByte(uint, uint, wchar_t*, int, char*, int, char*, int);
+    //pragma(lib, "shell32.lib");   // needed for CommandLineToArgvW
+    //pragma(lib, "tango-win32-dmd.lib"); // links Tango's Win32 library to reduce EXE size
+}
+
+extern (C) void _STI_monitor_staticctor();
+extern (C) void _STD_monitor_staticdtor();
+extern (C) void _STI_critical_init();
+extern (C) void _STD_critical_term();
+extern (C) void gc_init();
+extern (C) void gc_term();
+extern (C) void _moduleCtor();
+extern (C) void _moduleDtor();
+extern (C) void thread_joinAll();
+
+//debug=PRINTF;
+debug(PRINTF) extern (C) int printf(char*, ...);
+
+/***********************************
+ * These functions must be defined for any D program linked
+ * against this library.
+ */
+extern (C) void onAssertError( char[] file, size_t line );
+extern (C) void onAssertErrorMsg( char[] file, size_t line, char[] msg );
+extern (C) void onArrayBoundsError( char[] file, size_t line );
+extern (C) void onSwitchError( char[] file, size_t line );
+extern (C) bool runModuleUnitTests();
+
+// this function is called from the utf module
+//extern (C) void onUnicodeError( char[] msg, size_t idx );
+
+/***********************************
+ * These are internal callbacks for various language errors.
+ */
+extern (C) void _d_assert( char[] file, uint line )
+{
+    onAssertError( file, line );
+}
+
+extern (C) void _d_assert_msg( char[] msg, char[] file, uint line )
+{
+    onAssertErrorMsg( file, line, msg );
+}
+
+extern (C) void _d_array_bounds( char[] file, uint line )
+{
+    onArrayBoundsError( file, line );
+}
+
+extern (C) void _d_switch_error( char[] file, uint line )
+{
+    onSwitchError( file, line );
+}
+
+bool _d_isHalting = false;
+
+extern (C) bool rt_isHalting()
+{
+    return _d_isHalting;
+}
+
+extern (C) bool rt_trapExceptions = true;
+
+void _d_criticalInit()
+{
+    _STI_monitor_staticctor();
+    _STI_critical_init();
+    initStaticDataPtrs();
+}
+
+alias void delegate( Throwable ) ExceptionHandler;
+
+// this is here so users can manually initialize the runtime
+// for example, when there is no main function etc.
+extern (C) bool rt_init( ExceptionHandler dg = null )
+{
+    _d_criticalInit();
+
+    try
+    {
+        gc_init();
+        _moduleCtor();
+        return true;
+    }
+    catch( Throwable e )
+    {
+        if( dg )
+            dg( e );
+    }
+    catch
+    {
+
+    }
+    _d_criticalTerm();
+    return false;
+}
+
+void _d_criticalTerm()
+{
+    _STD_critical_term();
+    _STD_monitor_staticdtor();
+}
+
+// this is here so users can manually terminate the runtime
+// for example, when there is no main function etc.
+extern (C) bool rt_term( ExceptionHandler dg = null )
+{
+    try
+    {
+        thread_joinAll();
+        _d_isHalting = true;
+        _moduleDtor();
+        gc_term();
+        return true;
+    }
+    catch( Throwable e )
+    {
+        if( dg )
+            dg( e );
+    }
+    catch
+    {
+
+    }
+    finally
+    {
+        _d_criticalTerm();
+    }
+    return false;
+}
+
+/***********************************
+ * The D main() function supplied by the user's program
+ */
+int main(char[][] args);
+
+/***********************************
+ * Substitutes for the C main() function.
+ * It's purpose is to wrap the call to the D main()
+ * function and catch any unhandled exceptions.
+ */
+
+extern (C) int main(int argc, char **argv, char** env)
+{
+    char[][] args;
+    int result;
+
+    debug(PRINTF) printf("main ctors\n");
+    _STI_monitor_staticctor();
+    _STI_critical_init();
+    initStaticDataPtrs();
+
+    debug(PRINTF) printf("main args\n");
+    // GDC seems to get by without this Windows special case...
+    version (Win32)
+    {
+        wchar_t*  wcbuf = GetCommandLineW();
+        size_t    wclen = wcslen(wcbuf);
+        int       wargc = 0;
+        wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc);
+        assert(wargc == argc);
+
+        char*     cargp = null;
+        size_t    cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0);
+
+        cargp = cast(char*) alloca(cargl);
+        args  = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc];
+
+        for (size_t i = 0, p = 0; i < wargc; i++)
+        {
+            int wlen = wcslen( wargs[i] );
+            int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0);
+            args[i]  = cargp[p .. p+clen];
+            p += clen; assert(p <= cargl);
+            WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0);
+        }
+        LocalFree(wargs);
+        wargs = null;
+        wargc = 0;
+    }
+    else
+    {
+        char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof);
+        scope(exit) free(am);
+
+        for (size_t i = 0; i < argc; i++)
+        {
+            auto len = strlen(argv[i]);
+            am[i] = argv[i][0 .. len];
+        }
+        args = am[0 .. argc];
+    }
+
+    debug(PRINTF) printf("main trap exceptions\n");
+    bool trapExceptions = rt_trapExceptions;
+
+    void tryExec(void delegate() dg)
+    {
+        debug(PRINTF) printf("main try exec\n");
+        if (trapExceptions)
+        {
+            try
+            {
+                dg();
+            }
+            catch (Throwable e)
+            {
+                while (e)
+                {
+                    if (e.file)
+                    {
+                       // fprintf(stderr, "%.*s(%u): %.*s\n", e.file, e.line, e.msg);
+                       console (e.classinfo.name)("@")(e.file)("(")(e.line)("): ")(e.toString)("\n");
+                    }
+                    else
+                    {
+                       // fprintf(stderr, "%.*s\n", e.toString());
+                       console (e.classinfo.name)(": ")(e.toString)("\n");
+                    }
+                    if (e.info)
+                    {
+                        console ("----------------\n");
+                        foreach (t; e.info)
+                            console (t)("\n");
+                    }
+                    if (e.next)
+                        console ("\n");
+                    e = e.next;
+                }
+                result = EXIT_FAILURE;
+            }
+            catch (Object o)
+            {
+                // fprintf(stderr, "%.*s\n", o.toString());
+                console (o.toString)("\n");
+                result = EXIT_FAILURE;
+            }
+        }
+        else
+        {
+            dg();
+        }
+    }
+
+    // NOTE: The lifetime of a process is much like the lifetime of an object:
+    //       it is initialized, then used, then destroyed.  If initialization
+    //       fails, the successive two steps are never reached.  However, if
+    //       initialization succeeds, then cleanup will occur even if the use
+    //       step fails in some way.  Here, the use phase consists of running
+    //       the user's main function.  If main terminates with an exception,
+    //       the exception is handled and then cleanup begins.  An exception
+    //       thrown during cleanup, however, will abort the cleanup process.
+
+    void runMain()
+    {
+        debug(PRINTF) printf("main runMain\n");
+        result = main(args);
+    }
+
+    void runAll()
+    {
+        debug(PRINTF) printf("main runAll\n");
+        gc_init();
+        _moduleCtor();
+        if (runModuleUnitTests())
+            tryExec(&runMain);
+        thread_joinAll();
+        _d_isHalting = true;
+        _moduleDtor();
+        gc_term();
+    }
+
+    tryExec(&runAll);
+
+    debug(PRINTF) printf("main dtor\n");
+    _STD_critical_term();
+    _STD_monitor_staticdtor();
+
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/eh.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,388 @@
+/**
+ * This module contains functions and structures required for
+ * exception handling.
+ */
+module eh;
+
+import util.console;
+import ldc.cstdarg;
+
+// debug = EH_personality;
+
+// current EH implementation works on x86
+// if it has a working unwind runtime
+version(X86) {
+    version(linux) version=X86_UNWIND;
+    version(darwin) version=X86_UNWIND;
+}
+version(X86_64) {
+    version(linux) version=X86_UNWIND;
+}
+
+private extern(C) void abort();
+private extern(C) int printf(in char*, ...);
+private extern(C) int vprintf(in char*, va_list va);
+
+// D runtime functions
+extern(C) {
+    int _d_isbaseof(ClassInfo oc, ClassInfo c);
+}
+
+// libunwind headers
+extern(C)
+{
+    enum _Unwind_Reason_Code
+    {
+        NO_REASON = 0,
+        FOREIGN_EXCEPTION_CAUGHT = 1,
+        FATAL_PHASE2_ERROR = 2,
+        FATAL_PHASE1_ERROR = 3,
+        NORMAL_STOP = 4,
+        END_OF_STACK = 5,
+        HANDLER_FOUND = 6,
+        INSTALL_CONTEXT = 7,
+        CONTINUE_UNWIND = 8
+    }
+
+    enum _Unwind_Action
+    {
+        SEARCH_PHASE = 1,
+        CLEANUP_PHASE = 2,
+        HANDLER_PHASE = 3,
+        FORCE_UNWIND = 4
+    }
+
+    alias void* _Unwind_Context_Ptr;
+
+    alias void function(_Unwind_Reason_Code, _Unwind_Exception*) _Unwind_Exception_Cleanup_Fn;
+
+    struct _Unwind_Exception
+    {
+        char[8] exception_class;
+        _Unwind_Exception_Cleanup_Fn exception_cleanup;
+        int private_1;
+        int private_2;
+    }
+
+version(X86_UNWIND) 
+{
+    void _Unwind_Resume(_Unwind_Exception*);
+    _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*);
+    ulong _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context);
+    ulong _Unwind_GetIP(_Unwind_Context_Ptr context);
+    ulong _Unwind_SetIP(_Unwind_Context_Ptr context, ulong new_value);
+    ulong _Unwind_SetGR(_Unwind_Context_Ptr context, int index, ulong new_value);
+    ulong _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
+}
+else
+{
+    // runtime calls these directly
+    void _Unwind_Resume(_Unwind_Exception*)
+    {
+        console("_Unwind_Resume is not implemented on this platform.\n");
+    }
+    _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*)
+    {
+        console("_Unwind_RaiseException is not implemented on this platform.\n");
+        return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+    }
+}
+
+}
+
+// error and exit
+extern(C) private void fatalerror(in char* format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  printf("Fatal error in EH code: ");
+  vprintf(format, args);
+  printf("\n");
+  abort();
+}
+
+
+// helpers for reading certain DWARF data
+private ubyte* get_uleb128(ubyte* addr, ref size_t res)
+{
+  res = 0;
+  size_t bitsize = 0;
+
+  // read as long as high bit is set
+  while(*addr & 0x80) {
+    res |= (*addr & 0x7f) << bitsize;
+    bitsize += 7;
+    addr += 1;
+    if(bitsize >= size_t.sizeof*8)
+       fatalerror("tried to read uleb128 that exceeded size of size_t");
+  }
+  // read last
+  if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
+    fatalerror("Fatal error in EH code: tried to read uleb128 that exceeded size of size_t");
+  res |= (*addr) << bitsize;
+
+  return addr + 1;
+}
+
+private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res)
+{
+  res = 0;
+  size_t bitsize = 0;
+
+  // read as long as high bit is set
+  while(*addr & 0x80) {
+    res |= (*addr & 0x7f) << bitsize;
+    bitsize += 7;
+    addr += 1;
+    if(bitsize >= size_t.sizeof*8)
+       fatalerror("tried to read sleb128 that exceeded size of size_t");
+  }
+  // read last
+  if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
+    fatalerror("tried to read sleb128 that exceeded size of size_t");
+  res |= (*addr) << bitsize;
+
+  // take care of sign
+  if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40))
+    res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1);
+
+  return addr + 1;
+}
+
+
+// exception struct used by the runtime.
+// _d_throw allocates a new instance and passes the address of its
+// _Unwind_Exception member to the unwind call. The personality
+// routine is then able to get the whole struct by looking at the data
+// surrounding the unwind info.
+struct _d_exception
+{
+  Object exception_object;
+  _Unwind_Exception unwind_info;
+}
+
+// the 8-byte string identifying the type of exception
+// the first 4 are for vendor, the second 4 for language
+//TODO: This may be the wrong way around
+char[8] _d_exception_class = "LLDCD1\0\0";
+
+
+//
+// x86 unwind specific implementation of personality function
+// and helpers
+//
+version(X86_UNWIND)
+{
+
+// the personality routine gets called by the unwind handler and is responsible for
+// reading the EH tables and deciding what to do
+extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context)
+{
+  // check ver: the C++ Itanium ABI only allows ver == 1
+  if(ver != 1)
+    return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+
+  // check exceptionClass
+  //TODO: Treat foreign exceptions with more respect
+  if((cast(char*)&exception_class)[0..8] != _d_exception_class)
+    return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+
+  // find call site table, action table and classinfo table
+  // Note: callsite and action tables do not contain static-length
+  // data and will be parsed as needed
+  // Note: classinfo_table points past the end of the table
+  ubyte* callsite_table;
+  ubyte* action_table;
+  ClassInfo* classinfo_table;
+  _d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table);
+
+
+  /*
+    find landing pad and action table index belonging to ip by walking
+    the callsite_table
+  */
+  ubyte* callsite_walker = callsite_table;
+
+  // get the instruction pointer
+  // will be used to find the right entry in the callsite_table
+  // -1 because it will point past the last instruction
+  ulong ip = _Unwind_GetIP(context) - 1;
+
+  // address block_start is relative to
+  ulong region_start = _Unwind_GetRegionStart(context);
+
+  // table entries
+  uint block_start_offset, block_size;
+  ulong landing_pad;
+  size_t action_offset;
+
+  while(true) {
+    // if we've gone through the list and found nothing...
+    if(callsite_walker >= action_table)
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+    block_start_offset = *cast(uint*)callsite_walker;
+    block_size = *(cast(uint*)callsite_walker + 1);
+    landing_pad = *(cast(uint*)callsite_walker + 2);
+    if(landing_pad)
+      landing_pad += region_start;
+    callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset);
+
+    debug(EH_personality_verbose) printf("%d %d %d\n", block_start_offset, block_size, landing_pad);
+
+    // since the list is sorted, as soon as we're past the ip
+    // there's no handler to be found
+    if(ip < region_start + block_start_offset)
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+    // if we've found our block, exit
+    if(ip < region_start + block_start_offset + block_size)
+      break;
+  }
+
+  debug(EH_personality) printf("Found correct landing pad and actionOffset %d\n", action_offset);
+
+  // now we need the exception's classinfo to find a handler
+  // the exception_info is actually a member of a larger _d_exception struct
+  // the runtime allocated. get that now
+  _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof);
+
+  // if there's no action offset and no landing pad, continue unwinding
+  if(!action_offset && !landing_pad)
+    return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+  // if there's no action offset but a landing pad, this is a cleanup handler
+  else if(!action_offset && landing_pad)
+    return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
+
+  /*
+   walk action table chain, comparing classinfos using _d_isbaseof
+  */
+  ubyte* action_walker = action_table + action_offset - 1;
+
+  ptrdiff_t ti_offset, next_action_offset;
+  while(true) {
+    action_walker = get_sleb128(action_walker, ti_offset);
+    // it is intentional that we not modify action_walker here
+    // next_action_offset is from current action_walker position
+    get_sleb128(action_walker, next_action_offset);
+
+    // negative are 'filters' which we don't use
+    if(!(ti_offset >= 0))
+      fatalerror("Filter actions are unsupported");
+
+    // zero means cleanup, which we require to be the last action
+    if(ti_offset == 0) {
+      if(!(next_action_offset == 0))
+        fatalerror("Cleanup action must be last in chain");
+      return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
+    }
+
+    // get classinfo for action and check if the one in the
+    // exception structure is a base
+    ClassInfo catch_ci = classinfo_table[-ti_offset];
+    debug(EH_personality) printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr);
+    if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci))
+      return _d_eh_install_catch_context(actions, ti_offset, landing_pad, exception_struct, context);
+
+    // we've walked through all actions and found nothing...
+    if(next_action_offset == 0)
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+    else
+      action_walker += next_action_offset;
+  }
+
+  fatalerror("reached unreachable");
+  return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+}
+
+// These are the register numbers for SetGR that
+// llvm's eh.exception and eh.selector intrinsics
+// will pick up.
+// Found by trial-and-error :/
+version (X86_64)
+{
+  private int eh_exception_regno = 3;
+  private int eh_selector_regno = 1;
+} else {
+  private int eh_exception_regno = 0;
+  private int eh_selector_regno = 2;
+}
+
+private _Unwind_Reason_Code _d_eh_install_catch_context(_Unwind_Action actions, ptrdiff_t switchval, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
+{
+  debug(EH_personality) printf("Found catch clause!\n");
+
+  if(actions & _Unwind_Action.SEARCH_PHASE)
+    return _Unwind_Reason_Code.HANDLER_FOUND;
+
+  else if(actions & _Unwind_Action.HANDLER_PHASE)
+  {
+    debug(EH_personality) printf("Setting switch value to: %d!\n", switchval);
+    _Unwind_SetGR(context, eh_exception_regno, cast(ulong)cast(void*)(exception_struct.exception_object));
+    _Unwind_SetGR(context, eh_selector_regno, switchval);
+    _Unwind_SetIP(context, landing_pad);
+    return _Unwind_Reason_Code.INSTALL_CONTEXT;
+  }
+
+  fatalerror("reached unreachable");
+  return _Unwind_Reason_Code.FATAL_PHASE2_ERROR;
+}
+
+private _Unwind_Reason_Code _d_eh_install_finally_context(_Unwind_Action actions, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
+{
+  // if we're merely in search phase, continue
+  if(actions & _Unwind_Action.SEARCH_PHASE)
+    return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+  debug(EH_personality) printf("Calling cleanup routine...\n");
+
+  _Unwind_SetGR(context, eh_exception_regno, cast(ulong)exception_struct);
+  _Unwind_SetGR(context, eh_selector_regno, 0);
+  _Unwind_SetIP(context, landing_pad);
+  return _Unwind_Reason_Code.INSTALL_CONTEXT;
+}
+
+private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci)
+{
+  ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
+
+  //TODO: Do proper DWARF reading here
+  if(*data++ != 0xff)
+    fatalerror("DWARF header has unexpected format 1");
+
+  if(*data++ != 0x00)
+    fatalerror("DWARF header has unexpected format 2");
+  size_t cioffset;
+  data = get_uleb128(data, cioffset);
+  ci = cast(ClassInfo*)(data + cioffset);
+
+  if(*data++ != 0x03)
+    fatalerror("DWARF header has unexpected format 3");
+  size_t callsitelength;
+  data = get_uleb128(data, callsitelength);
+  action = data + callsitelength;
+
+  callsite = data;
+}
+
+} // end of x86 Linux specific implementation
+
+
+extern(C) void _d_throw_exception(Object e)
+{
+    if (e !is null)
+    {
+        _d_exception* exc_struct = new _d_exception;
+        exc_struct.unwind_info.exception_class[] = _d_exception_class;
+        exc_struct.exception_object = e;
+        _Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info);
+        console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
+    }
+    abort();
+}
+
+extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct)
+{
+  _Unwind_Resume(&exception_struct.unwind_info);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/genobj.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,1521 @@
+/**
+ * Part of the D programming language runtime library.
+ * Forms the symbols available to all D programs. Includes
+ * Object, which is the root of the class object hierarchy.
+ *
+ * This module is implicitly imported.
+ * Macros:
+ *      WIKI = Object
+ */
+
+/*
+ *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly for use with the D Runtime Project
+ */
+
+/*
+ * Modified by Tomas Lindquist Olsen for use with the LLVM D Compiler
+ */
+
+module object;
+
+private
+{
+    import stdc.string;
+    import stdc.stdlib;
+    import util.string;
+    debug(PRINTF) import stdc.stdio;
+
+    extern (C) void onOutOfMemoryError();
+    extern (C) Object _d_newclass(ClassInfo ci);
+}
+
+// NOTE: For some reason, this declaration method doesn't work
+//       in this particular file (and this file only).  It must
+//       be a DMD thing.
+//alias typeof(int.sizeof)                    size_t;
+//alias typeof(cast(void*)0 - cast(void*)0)   ptrdiff_t;
+
+version(X86_64)
+{
+    alias ulong size_t;
+    alias long  ptrdiff_t;
+}
+else
+{
+    alias uint  size_t;
+    alias int   ptrdiff_t;
+}
+
+alias size_t hash_t;
+alias bool equals_t;
+
+alias invariant(char)[]  string;
+alias invariant(wchar)[] wstring;
+alias invariant(dchar)[] dstring;
+
+/**
+ * All D class objects inherit from Object.
+ */
+class Object
+{
+    /**
+     * Convert Object to a human readable string.
+     */
+    string toString()
+    {
+        return this.classinfo.name;
+    }
+
+    /**
+     * Compute hash function for Object.
+     */
+    hash_t toHash()
+    {
+        // BUG: this prevents a compacting GC from working, needs to be fixed
+        return cast(hash_t)cast(void*)this;
+    }
+
+    /**
+     * Compare with another Object obj.
+     * Returns:
+     *  $(TABLE
+     *  $(TR $(TD this &lt; obj) $(TD &lt; 0))
+     *  $(TR $(TD this == obj) $(TD 0))
+     *  $(TR $(TD this &gt; obj) $(TD &gt; 0))
+     *  )
+     */
+    int opCmp(Object o)
+    {
+        // BUG: this prevents a compacting GC from working, needs to be fixed
+        //return cast(int)cast(void*)this - cast(int)cast(void*)o;
+
+        throw new Exception("need opCmp for class " ~ this.classinfo.name);
+        //return this !is o;
+    }
+
+    /**
+     * Returns !=0 if this object does have the same contents as obj.
+     */
+    equals_t opEquals(Object o)
+    {
+        return this is o;
+    }
+
+    interface Monitor
+    {
+        void lock();
+        void unlock();
+    }
+
+    /**
+     * Create instance of class specified by classname.
+     * The class must either have no constructors or have
+     * a default constructor.
+     * Returns:
+     *   null if failed
+     */
+    static Object factory(string classname)
+    {
+        auto ci = ClassInfo.find(classname);
+        if (ci)
+        {
+            return ci.create();
+        }
+        return null;
+    }
+}
+
+/**
+ * Information about an interface.
+ * When an object is accessed via an interface, an Interface* appears as the
+ * first entry in its vtbl.
+ */
+struct Interface
+{
+    ClassInfo   classinfo;  /// .classinfo for this interface (not for containing class)
+    void*[]     vtbl;
+    ptrdiff_t   offset;     /// offset to Interface 'this' from Object 'this'
+}
+
+/**
+ * Runtime type information about a class. Can be retrieved for any class type
+ * or instance by using the .classinfo property.
+ * A pointer to this appears as the first entry in the class's vtbl[].
+ */
+class ClassInfo : Object
+{
+    byte[]      init;           /** class static initializer
+                                 * (init.length gives size in bytes of class)
+                                 */
+    string      name;           /// class name
+    void*[]     vtbl;           /// virtual function pointer table
+    Interface[] interfaces;     /// interfaces this class implements
+    ClassInfo   base;           /// base class
+    void*       destructor;
+    void function(Object) classInvariant;
+    uint        flags;
+    //  1:                      // is IUnknown or is derived from IUnknown
+    //  2:                      // has no possible pointers into GC memory
+    //  4:                      // has offTi[] member
+    //  8:                      // has constructors
+    // 16:                      // has xgetMembers member
+    void*       deallocator;
+    OffsetTypeInfo[] offTi;
+    void function(Object) defaultConstructor;   // default Constructor
+    const(MemberInfo[]) function(in char[]) xgetMembers;
+
+    /**
+     * Search all modules for ClassInfo corresponding to classname.
+     * Returns: null if not found
+     */
+    static ClassInfo find(in char[] classname)
+    {
+        foreach (m; ModuleInfo)
+        {
+            //writefln("module %s, %d", m.name, m.localClasses.length);
+            foreach (c; m.localClasses)
+            {
+                //writefln("\tclass %s", c.name);
+                if (c.name == classname)
+                    return c;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create instance of Object represented by 'this'.
+     */
+    Object create()
+    {
+        if (flags & 8 && !defaultConstructor)
+            return null;
+        Object o = _d_newclass(this);
+        if (flags & 8 && defaultConstructor)
+        {
+            defaultConstructor(o);
+        }
+        return o;
+    }
+
+    /**
+     * Search for all members with the name 'name'.
+     * If name[] is null, return all members.
+     */
+    const(MemberInfo[]) getMembers(in char[] name)
+    {
+        if (flags & 16 && xgetMembers)
+            return xgetMembers(name);
+        return null;
+    }
+}
+
+/**
+ * Array of pairs giving the offset and type information for each
+ * member in an aggregate.
+ */
+struct OffsetTypeInfo
+{
+    size_t   offset;    /// Offset of member from start of object
+    TypeInfo ti;        /// TypeInfo for this member
+}
+
+/**
+ * Runtime type information about a type.
+ * Can be retrieved for any type using a
+ * <a href="../expression.html#typeidexpression">TypeidExpression</a>.
+ */
+class TypeInfo
+{
+    override hash_t toHash()
+    {
+        hash_t hash;
+
+        foreach (char c; this.toString())
+            hash = hash * 9 + c;
+        return hash;
+    }
+
+    override int opCmp(Object o)
+    {
+        if (this is o)
+            return 0;
+        TypeInfo ti = cast(TypeInfo)o;
+        if (ti is null)
+            return 1;
+        return dstrcmp(this.toString(), ti.toString());
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        /* TypeInfo instances are singletons, but duplicates can exist
+         * across DLL's. Therefore, comparing for a name match is
+         * sufficient.
+         */
+        if (this is o)
+            return true;
+        TypeInfo ti = cast(TypeInfo)o;
+        return ti && this.toString() == ti.toString();
+    }
+
+    /// Returns a hash of the instance of a type.
+    hash_t getHash(in void* p) { return cast(hash_t)p; }
+
+    /// Compares two instances for equality.
+    equals_t equals(in void* p1, in void* p2) { return p1 == p2; }
+
+    /// Compares two instances for &lt;, ==, or &gt;.
+    int compare(in void* p1, in void* p2) { return 0; }
+
+    /// Returns size of the type.
+    size_t tsize() { return 0; }
+
+    /// Swaps two instances of the type.
+    void swap(void* p1, void* p2)
+    {
+        size_t n = tsize();
+        for (size_t i = 0; i < n; i++)
+        {
+            byte t = (cast(byte *)p1)[i];
+            (cast(byte*)p1)[i] = (cast(byte*)p2)[i];
+            (cast(byte*)p2)[i] = t;
+        }
+    }
+
+    /// Get TypeInfo for 'next' type, as defined by what kind of type this is,
+    /// null if none.
+    TypeInfo next() { return null; }
+
+    /// Return default initializer, null if default initialize to 0
+    void[] init() { return null; }
+
+    /// Get flags for type: 1 means GC should scan for pointers
+    uint flags() { return 0; }
+
+    /// Get type information on the contents of the type; null if not available
+    OffsetTypeInfo[] offTi() { return null; }
+    /// Run the destructor on the object and all its sub-objects
+    void destroy(void* p) {}
+    /// Run the postblit on the object and all its sub-objects
+    void postblit(void* p) {}
+}
+
+class TypeInfo_Typedef : TypeInfo
+{
+    override string toString() { return name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Typedef c;
+        return this is o ||
+               ((c = cast(TypeInfo_Typedef)o) !is null &&
+                this.name == c.name &&
+                this.base == c.base);
+    }
+
+    override hash_t getHash(in void* p) { return base.getHash(p); }
+    override equals_t equals(in void* p1, in void* p2) { return base.equals(p1, p2); }
+    override int compare(in void* p1, in void* p2) { return base.compare(p1, p2); }
+    override size_t tsize() { return base.tsize(); }
+    override void swap(void* p1, void* p2) { return base.swap(p1, p2); }
+
+    override TypeInfo next() { return base.next(); }
+    override uint flags() { return base.flags(); }
+    override void[] init() { return m_init.length ? m_init : base.init(); }
+
+    TypeInfo base;
+    string   name;
+    void[]   m_init;
+}
+
+class TypeInfo_Enum : TypeInfo_Typedef
+{
+
+}
+
+class TypeInfo_Pointer : TypeInfo
+{
+    override string toString() { return m_next.toString() ~ "*"; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Pointer c;
+        return this is o ||
+                ((c = cast(TypeInfo_Pointer)o) !is null &&
+                 this.m_next == c.m_next);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        return cast(hash_t)*cast(void**)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(void**)p1 == *cast(void**)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(void**)p1 < *cast(void**)p2)
+            return -1;
+        else if (*cast(void**)p1 > *cast(void**)p2)
+            return 1;
+        else
+            return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (void*).sizeof;
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void* tmp = *cast(void**)p1;
+        *cast(void**)p1 = *cast(void**)p2;
+        *cast(void**)p2 = tmp;
+    }
+
+    override TypeInfo next() { return m_next; }
+    override uint flags() { return 1; }
+
+    TypeInfo m_next;
+}
+
+class TypeInfo_Array : TypeInfo
+{
+    override string toString() { return value.toString() ~ "[]"; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Array c;
+        return this is o ||
+               ((c = cast(TypeInfo_Array)o) !is null &&
+                this.value == c.value);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        size_t sz = value.tsize();
+        hash_t hash = 0;
+        void[] a = *cast(void[]*)p;
+        for (size_t i = 0; i < a.length; i++)
+            hash += value.getHash(a.ptr + i * sz);
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        void[] a1 = *cast(void[]*)p1;
+        void[] a2 = *cast(void[]*)p2;
+        if (a1.length != a2.length)
+            return false;
+        size_t sz = value.tsize();
+        for (size_t i = 0; i < a1.length; i++)
+        {
+            if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        void[] a1 = *cast(void[]*)p1;
+        void[] a2 = *cast(void[]*)p2;
+        size_t sz = value.tsize();
+        size_t len = a1.length;
+
+        if (a2.length < len)
+            len = a2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
+            if (result)
+                return result;
+        }
+        return cast(int)a1.length - cast(int)a2.length;
+    }
+
+    override size_t tsize()
+    {
+        return (void[]).sizeof;
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void[] tmp = *cast(void[]*)p1;
+        *cast(void[]*)p1 = *cast(void[]*)p2;
+        *cast(void[]*)p2 = tmp;
+    }
+
+    TypeInfo value;
+
+    override TypeInfo next()
+    {
+        return value;
+    }
+
+    override uint flags() { return 1; }
+}
+
+class TypeInfo_StaticArray : TypeInfo
+{
+    override string toString()
+    {
+        char[10] tmp = void;
+        return cast(string)(value.toString() ~ "[" ~ tmp.intToString(len) ~ "]");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_StaticArray c;
+        return this is o ||
+               ((c = cast(TypeInfo_StaticArray)o) !is null &&
+                this.len == c.len &&
+                this.value == c.value);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        size_t sz = value.tsize();
+        hash_t hash = 0;
+        for (size_t i = 0; i < len; i++)
+            hash += value.getHash(p + i * sz);
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        size_t sz = value.tsize();
+
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!value.equals(p1 + u * sz, p2 + u * sz))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        size_t sz = value.tsize();
+
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = value.compare(p1 + u * sz, p2 + u * sz);
+            if (result)
+                return result;
+        }
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return len * value.tsize();
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void* tmp;
+        size_t sz = value.tsize();
+        ubyte[16] buffer;
+        void* pbuffer;
+
+        if (sz < buffer.sizeof)
+            tmp = buffer.ptr;
+        else
+            tmp = pbuffer = (new void[sz]).ptr;
+
+        for (size_t u = 0; u < len; u += sz)
+        {   size_t o = u * sz;
+            memcpy(tmp, p1 + o, sz);
+            memcpy(p1 + o, p2 + o, sz);
+            memcpy(p2 + o, tmp, sz);
+        }
+        if (pbuffer)
+            delete pbuffer;
+    }
+
+    override void[] init() { return value.init(); }
+    override TypeInfo next() { return value; }
+    override uint flags() { return value.flags(); }
+
+    override void destroy(void* p)
+    {
+        auto sz = value.tsize();
+        p += sz * len;
+        foreach (i; 0 .. len)
+        {
+            p -= sz;
+            value.destroy(p);
+        }
+    }
+
+    override void postblit(void* p)
+    {
+        auto sz = value.tsize();
+        foreach (i; 0 .. len)
+        {
+            value.postblit(p);
+            p += sz;
+        }
+    }
+
+    TypeInfo value;
+    size_t   len;
+}
+
+class TypeInfo_AssociativeArray : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ "[" ~ key.toString() ~ "]");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_AssociativeArray c;
+        return this is o ||
+                ((c = cast(TypeInfo_AssociativeArray)o) !is null &&
+                 this.key == c.key &&
+                 this.value == c.value);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    override size_t tsize()
+    {
+        return (char[int]).sizeof;
+    }
+
+    override TypeInfo next() { return value; }
+    override uint flags() { return 1; }
+
+    TypeInfo value;
+    TypeInfo key;
+}
+
+class TypeInfo_Function : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ "()");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Function c;
+        return this is o ||
+                ((c = cast(TypeInfo_Function)o) !is null &&
+                 this.next == c.next);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    override size_t tsize()
+    {
+        return 0;       // no size for functions
+    }
+
+    TypeInfo next;
+}
+
+class TypeInfo_Delegate : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ " delegate()");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Delegate c;
+        return this is o ||
+                ((c = cast(TypeInfo_Delegate)o) !is null &&
+                 this.next == c.next);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    override size_t tsize()
+    {
+        alias int delegate() dg;
+        return dg.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    TypeInfo next;
+}
+
+class TypeInfo_Class : TypeInfo
+{
+    override string toString() { return info.name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Class c;
+        return this is o ||
+                ((c = cast(TypeInfo_Class)o) !is null &&
+                 this.info.name == c.classinfo.name);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        Object o = *cast(Object*)p;
+        return o ? o.toHash() : 0;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+
+        return (o1 is o2) || (o1 && o1.opEquals(o2));
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (o1 !is o2)
+        {
+            if (o1)
+            {
+                if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    override OffsetTypeInfo[] offTi()
+    {
+        return (info.flags & 4) ? info.offTi : null;
+    }
+
+    ClassInfo info;
+}
+
+class TypeInfo_Interface : TypeInfo
+{
+    override string toString() { return info.name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Interface c;
+        return this is o ||
+                ((c = cast(TypeInfo_Interface)o) !is null &&
+                 this.info.name == c.classinfo.name);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p;
+        Object o = cast(Object)(*cast(void**)p - pi.offset);
+        assert(o);
+        return o.toHash();
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p1;
+        Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
+        pi = **cast(Interface ***)*cast(void**)p2;
+        Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
+
+        return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p1;
+        Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
+        pi = **cast(Interface ***)*cast(void**)p2;
+        Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (o1 != o2)
+        {
+            if (o1)
+            {
+                if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    ClassInfo info;
+}
+
+class TypeInfo_Struct : TypeInfo
+{
+    override string toString() { return name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Struct s;
+        return this is o ||
+                ((s = cast(TypeInfo_Struct)o) !is null &&
+                 this.name == s.name &&
+                 this.init.length == s.init.length);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(p);
+        if (xtoHash)
+        {
+            debug(PRINTF) printf("getHash() using xtoHash\n");
+            return (*xtoHash)(p);
+        }
+        else
+        {
+            hash_t h;
+            debug(PRINTF) printf("getHash() using default hash\n");
+            // A sorry hash algorithm.
+            // Should use the one for strings.
+            // BUG: relies on the GC not moving objects
+            auto q = cast(const(ubyte)*)p;
+            for (size_t i = 0; i < init.length; i++)
+            {
+                h = h * 9 + *q;
+                q++;
+            }
+            return h;
+        }
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        if (p1 == p2)
+            return true;
+        else if (!p1 || !p2)
+            return false;
+        else if (xopEquals)
+            return (*xopEquals)(p1, p2);
+        else
+            // BUG: relies on the GC not moving objects
+            return memcmp(p1, p2, init.length) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        // Regard null references as always being "less than"
+        if (p1 != p2)
+        {
+            if (p1)
+            {
+                if (!p2)
+                    return true;
+                else if (xopCmp)
+                    return (*xopCmp)(p2, p1);
+                else
+                    // BUG: relies on the GC not moving objects
+                    return memcmp(p1, p2, init.length);
+            }
+            else
+                return -1;
+        }
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return init.length;
+    }
+
+    override void[] init() { return m_init; }
+
+    override uint flags() { return m_flags; }
+
+    override void destroy(void* p)
+    {
+        if (xdtor)
+            (*xdtor)(p);
+    }
+
+    override void postblit(void* p)
+    {
+        if (xpostblit)
+            (*xpostblit)(p);
+    }
+
+    string name;
+    void[] m_init;      // initializer; init.ptr == null if 0 initialize
+
+    hash_t   function(in void*)           xtoHash;
+    equals_t function(in void*, in void*) xopEquals;
+    int      function(in void*, in void*) xopCmp;
+    char[]   function(in void*)           xtoString;
+
+    uint m_flags;
+
+    const(MemberInfo[]) function(in char[]) xgetMembers;
+    void function(void*)                    xdtor;
+    void function(void*)                    xpostblit;
+}
+
+class TypeInfo_Tuple : TypeInfo
+{
+    TypeInfo[] elements;
+
+    override string toString()
+    {
+        string s = "(";
+        foreach (i, element; elements)
+        {
+            if (i)
+                s ~= ',';
+            s ~= element.toString();
+        }
+        s ~= ")";
+        return s;
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        if (this is o)
+            return true;
+
+        auto t = cast(TypeInfo_Tuple)o;
+        if (t && elements.length == t.elements.length)
+        {
+            for (size_t i = 0; i < elements.length; i++)
+            {
+                if (elements[i] != t.elements[i])
+                    return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(0);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        assert(0);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        assert(0);
+    }
+
+    override size_t tsize()
+    {
+        assert(0);
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        assert(0);
+    }
+
+    override void destroy(void* p)
+    {
+        assert(0);
+    }
+
+    override void postblit(void* p)
+    {
+        assert(0);
+    }
+}
+
+class TypeInfo_Const : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string) ("const(" ~ base.toString() ~ ")");
+    }
+
+    override equals_t opEquals(Object o) { return base.opEquals(o); }
+    override hash_t getHash(in void *p) { return base.getHash(p); }
+    override equals_t equals(in void *p1, in void *p2) { return base.equals(p1, p2); }
+    override int compare(in void *p1, in void *p2) { return base.compare(p1, p2); }
+    override size_t tsize() { return base.tsize(); }
+    override void swap(void *p1, void *p2) { return base.swap(p1, p2); }
+
+    override TypeInfo next() { return base.next(); }
+    override uint flags() { return base.flags(); }
+    override void[] init() { return base.init(); }
+
+    TypeInfo base;
+}
+
+class TypeInfo_Invariant : TypeInfo_Const
+{
+    override string toString()
+    {
+        return cast(string) ("invariant(" ~ base.toString() ~ ")");
+    }
+}
+
+abstract class MemberInfo
+{
+    string name();
+}
+
+class MemberInfo_field : MemberInfo
+{
+    this(string name, TypeInfo ti, size_t offset)
+    {
+        m_name = name;
+        m_typeinfo = ti;
+        m_offset = offset;
+    }
+
+    override string name() { return m_name; }
+    TypeInfo typeInfo() { return m_typeinfo; }
+    size_t offset() { return m_offset; }
+
+    string   m_name;
+    TypeInfo m_typeinfo;
+    size_t   m_offset;
+}
+
+class MemberInfo_function : MemberInfo
+{
+    this(string name, TypeInfo ti, void* fp, uint flags)
+    {
+        m_name = name;
+        m_typeinfo = ti;
+        m_fp = fp;
+        m_flags = flags;
+    }
+
+    override string name() { return m_name; }
+    TypeInfo typeInfo() { return m_typeinfo; }
+    void* fp() { return m_fp; }
+    uint flags() { return m_flags; }
+
+    string   m_name;
+    TypeInfo m_typeinfo;
+    void*    m_fp;
+    uint     m_flags;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Throwable
+///////////////////////////////////////////////////////////////////////////////
+
+
+class Throwable : Object
+{
+    interface TraceInfo
+    {
+        int opApply(int delegate(inout char[]));
+    }
+
+    string      msg;
+    string      file;
+    size_t      line;
+    TraceInfo   info;
+    Throwable   next;
+
+    this(string msg, Throwable next = null)
+    {
+        this.msg = msg;
+        this.next = next;
+        this.info = traceContext();
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        this(msg, next);
+        this.file = file;
+        this.line = line;
+        this.info = traceContext();
+    }
+
+    override string toString()
+    {
+        char[10] tmp = void;
+        char[]   buf;
+
+        for (Throwable e = this; e !is null; e = e.next)
+        {
+            if (e.file)
+            {
+               buf ~= e.classinfo.name ~ "@" ~ e.file ~ "(" ~ tmp.intToString(e.line) ~ "): " ~ e.msg;
+            }
+            else
+            {
+               buf ~= e.classinfo.name ~ ": " ~ e.msg;
+            }
+            if (e.info)
+            {
+                buf ~= "\n----------------";
+                foreach (t; e.info)
+                    buf ~= "\n" ~ t;
+            }
+            if (e.next)
+                buf ~= "\n";
+        }
+        return cast(string) buf;
+    }
+}
+
+
+alias Throwable.TraceInfo function(void* ptr = null) TraceHandler;
+private TraceHandler traceHandler = null;
+
+
+/**
+ * Overrides the default trace hander with a user-supplied version.
+ *
+ * Params:
+ *  h = The new trace handler.  Set to null to use the default handler.
+ */
+extern (C) void  rt_setTraceHandler(TraceHandler h)
+{
+    traceHandler = h;
+}
+
+
+/**
+ * This function will be called when an exception is constructed.  The
+ * user-supplied trace handler will be called if one has been supplied,
+ * otherwise no trace will be generated.
+ *
+ * Params:
+ *  ptr = A pointer to the location from which to generate the trace, or null
+ *        if the trace should be generated from within the trace handler
+ *        itself.
+ *
+ * Returns:
+ *  An object describing the current calling context or null if no handler is
+ *  supplied.
+ */
+Throwable.TraceInfo traceContext(void* ptr = null)
+{
+    if (traceHandler is null)
+        return null;
+    return traceHandler(ptr);
+}
+
+
+class Exception : Throwable
+{
+    this(string msg, Throwable next = null)
+    {
+        super(msg, next);
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        super(msg, file, line, next);
+    }
+}
+
+
+class Error : Throwable
+{
+    this(string msg, Throwable next = null)
+    {
+        super(msg, next);
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        super(msg, file, line, next);
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// ModuleInfo
+///////////////////////////////////////////////////////////////////////////////
+
+
+enum
+{
+    MIctorstart  = 1,   // we've started constructing it
+    MIctordone   = 2,   // finished construction
+    MIstandalone = 4,   // module ctor does not depend on other module
+                        // ctors being done first
+    MIhasictor   = 8,   // has ictor member
+}
+
+
+class ModuleInfo
+{
+    string          name;
+    ModuleInfo[]    importedModules;
+    ClassInfo[]     localClasses;
+    uint            flags;
+
+    void function() ctor;       // module static constructor (order dependent)
+    void function() dtor;       // module static destructor
+    void function() unitTest;   // module unit tests
+
+    void* xgetMembers;          // module getMembers() function
+
+    void function() ictor;      // module static constructor (order independent)
+
+    static int opApply(int delegate(inout ModuleInfo) dg)
+    {
+        int ret = 0;
+
+        foreach (m; _moduleinfo_array)
+        {
+            ret = dg(m);
+            if (ret)
+                break;
+        }
+        return ret;
+    }
+}
+
+
+// Windows: this gets initialized by minit.asm
+// linux: this gets initialized in _moduleCtor()
+extern (C) ModuleInfo[] _moduleinfo_array;
+
+
+version (linux)
+{
+    // This linked list is created by a compiler generated function inserted
+    // into the .ctor list by the compiler.
+    struct ModuleReference
+    {
+        ModuleReference* next;
+        ModuleInfo       mod;
+    }
+
+    extern (C) ModuleReference* _Dmodule_ref;   // start of linked list
+}
+
+ModuleInfo[] _moduleinfo_dtors;
+uint         _moduleinfo_dtors_i;
+
+// Register termination function pointers
+extern (C) int _fatexit(void*);
+
+/**
+ * Initialize the modules.
+ */
+
+extern (C) void _moduleCtor()
+{
+    debug(PRINTF) printf("_moduleCtor()\n");
+    version (linux)
+    {
+        int len = 0;
+        ModuleReference *mr;
+
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+            len++;
+        _moduleinfo_array = new ModuleInfo[len];
+        len = 0;
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+        {   _moduleinfo_array[len] = mr.mod;
+            len++;
+        }
+    }
+
+    version (Windows)
+    {
+        // Ensure module destructors also get called on program termination
+        //_fatexit(&_STD_moduleDtor);
+    }
+
+    _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length];
+    debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void*)_moduleinfo_dtors);
+    _moduleIndependentCtors();
+    _moduleCtor2(_moduleinfo_array, 0);
+}
+
+extern (C) void _moduleIndependentCtors()
+{
+    debug(PRINTF) printf("_moduleIndependentCtors()\n");
+    foreach (m; _moduleinfo_array)
+    {
+        if (m && m.flags & MIhasictor && m.ictor)
+        {
+            (*m.ictor)();
+        }
+    }
+}
+
+void _moduleCtor2(ModuleInfo[] mi, int skip)
+{
+    debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length);
+    for (uint i = 0; i < mi.length; i++)
+    {
+        ModuleInfo m = mi[i];
+
+        debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m);
+        if (!m)
+            continue;
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name);
+        if (m.flags & MIctordone)
+            continue;
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m);
+
+        if (m.ctor || m.dtor)
+        {
+            if (m.flags & MIctorstart)
+            {   if (skip || m.flags & MIstandalone)
+                    continue;
+                    throw new Exception("Cyclic dependency in module " ~ m.name);
+            }
+
+            m.flags |= MIctorstart;
+            _moduleCtor2(m.importedModules, 0);
+            if (m.ctor)
+                (*m.ctor)();
+            m.flags &= ~MIctorstart;
+            m.flags |= MIctordone;
+
+            // Now that construction is done, register the destructor
+            //printf("\tadding module dtor x%x\n", m);
+            assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length);
+            _moduleinfo_dtors[_moduleinfo_dtors_i++] = m;
+        }
+        else
+        {
+            m.flags |= MIctordone;
+            _moduleCtor2(m.importedModules, 1);
+        }
+    }
+}
+
+/**
+ * Destruct the modules.
+ */
+
+// Starting the name with "_STD" means under linux a pointer to the
+// function gets put in the .dtors segment.
+
+extern (C) void _moduleDtor()
+{
+    debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i);
+
+    for (uint i = _moduleinfo_dtors_i; i-- != 0;)
+    {
+        ModuleInfo m = _moduleinfo_dtors[i];
+
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m);
+        if (m.dtor)
+        {
+            (*m.dtor)();
+        }
+    }
+    debug(PRINTF) printf("_moduleDtor() done\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Monitor
+///////////////////////////////////////////////////////////////////////////////
+
+alias Object.Monitor        IMonitor;
+alias void delegate(Object) DEvent;
+
+// NOTE: The dtor callback feature is only supported for monitors that are not
+//       supplied by the user.  The assumption is that any object with a user-
+//       supplied monitor may have special storage or lifetime requirements and
+//       that as a result, storing references to local objects within Monitor
+//       may not be safe or desirable.  Thus, devt is only valid if impl is
+//       null.
+struct Monitor
+{
+    IMonitor impl;
+    /* internal */
+    DEvent[] devt;
+    /* stuff */
+}
+
+Monitor* getMonitor(Object h)
+{
+    return cast(Monitor*) (cast(void**) h)[1];
+}
+
+void setMonitor(Object h, Monitor* m)
+{
+    (cast(void**) h)[1] = m;
+}
+
+extern (C) void _d_monitor_create(Object);
+extern (C) void _d_monitor_destroy(Object);
+extern (C) void _d_monitor_lock(Object);
+extern (C) int  _d_monitor_unlock(Object);
+
+extern (C) void _d_monitordelete(Object h, bool det)
+{
+    Monitor* m = getMonitor(h);
+
+    if (m !is null)
+    {
+        IMonitor i = m.impl;
+        if (i is null)
+        {
+            _d_monitor_devt(m, h);
+            _d_monitor_destroy(h);
+            setMonitor(h, null);
+            return;
+        }
+        if (det && (cast(void*) i) !is (cast(void*) h))
+            delete i;
+        setMonitor(h, null);
+    }
+}
+
+extern (C) void _d_monitorenter(Object h)
+{
+    Monitor* m = getMonitor(h);
+
+    if (m is null)
+    {
+        _d_monitor_create(h);
+        m = getMonitor(h);
+    }
+
+    IMonitor i = m.impl;
+
+    if (i is null)
+    {
+        _d_monitor_lock(h);
+        return;
+    }
+    i.lock();
+}
+
+extern (C) void _d_monitorexit(Object h)
+{
+    Monitor* m = getMonitor(h);
+    IMonitor i = m.impl;
+
+    if (i is null)
+    {
+        _d_monitor_unlock(h);
+        return;
+    }
+    i.unlock();
+}
+
+extern (C) void _d_monitor_devt(Monitor* m, Object h)
+{
+    if (m.devt.length)
+    {
+        DEvent[] devt;
+
+        synchronized (h)
+        {
+            devt = m.devt;
+            m.devt = null;
+        }
+        foreach (v; devt)
+        {
+            if (v)
+                v(h);
+        }
+        free(devt.ptr);
+    }
+}
+
+extern (C) void rt_attachDisposeEvent(Object h, DEvent e)
+{
+    synchronized (h)
+    {
+        Monitor* m = getMonitor(h);
+        assert(m.impl is null);
+
+        foreach (inout v; m.devt)
+        {
+            if (v is null || v == e)
+            {
+                v = e;
+                return;
+            }
+        }
+
+        auto len = m.devt.length + 4; // grow by 4 elements
+        auto pos = m.devt.length;     // insert position
+        auto p = realloc(m.devt.ptr, DEvent.sizeof * len);
+        if (!p)
+            onOutOfMemoryError();
+        m.devt = (cast(DEvent*)p)[0 .. len];
+        m.devt[pos+1 .. len] = null;
+        m.devt[pos] = e;
+    }
+}
+
+extern (C) void rt_detachDisposeEvent(Object h, DEvent e)
+{
+    synchronized (h)
+    {
+        Monitor* m = getMonitor(h);
+        assert(m.impl is null);
+
+        foreach (p, v; m.devt)
+        {
+            if (v == e)
+            {
+                memmove(&m.devt[p],
+                        &m.devt[p+1],
+                        (m.devt.length - p - 1) * DEvent.sizeof);
+                m.devt[$ - 1] = null;
+                return;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/invariant.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,25 @@
+
+/*
+ * Placed into the Public Domain
+ * written by Walter Bright
+ * www.digitalmars.com
+ */
+
+extern(C) void _d_invariant(Object o)
+{   ClassInfo c;
+
+    //printf("__d_invariant(%p)\n", o);
+
+    // BUG: needs to be filename/line of caller, not library routine
+    assert(o !is null);	// just do null check, not invariant check
+
+    c = o.classinfo;
+    do
+    {
+	if (c.classInvariant)
+	{
+	    (*c.classInvariant)(o);
+	}
+	c = c.base;
+    } while (c);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/ldc.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,261 @@
+# Makefile to build the LDC compiler runtime D library for Linux
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the compiler runtime library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET_FULL=libldc-runtime.a
+LIB_TARGET_BC_ONLY=libldc-runtime-bc-only.a
+LIB_TARGET_C_ONLY=libldc-runtime-c-only.a
+LIB_TARGET_SHARED=libldc-runtime-shared.so
+LIB_MASK=libldc-runtime*.*
+
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+#CFLAGS=-O3 $(ADD_CFLAGS)
+CFLAGS=$(ADD_CFLAGS)
+
+#DFLAGS=-release -O3 -inline -w $(ADD_DFLAGS)
+DFLAGS=-w $(ADD_DFLAGS)
+
+#TFLAGS=-O3 -inline -w $(ADD_DFLAGS)
+TFLAGS=-w $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=gcc
+LC=llvm-ar rsv
+LLINK=llvm-link
+LCC=llc
+CLC=ar rsv
+DC=ldc
+LLC=llvm-as
+
+LIB_DEST=..
+
+.SUFFIXES: .s .S .c .cpp .d .ll .html .o .bc
+
+.s.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.S.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.o:
+	g++ -c $(CFLAGS) $< -o$@
+
+.d.o:
+	$(DC) -c $(DFLAGS) $< -of$@ -output-bc
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html ldc.ddoc $<
+
+targets : lib sharedlib doc
+all     : lib sharedlib doc
+#lib     : ldc.bclib ldc.clib ldc.lib
+lib     : ldc.clib ldc.lib
+sharedlib : ldc.sharedlib
+doc     : ldc.doc
+
+######################################################
+OBJ_C= \
+    monitor.o \
+    critical.o
+
+OBJ_BASE_BC= \
+    aaA.bc \
+    aApply.bc \
+    aApplyR.bc \
+    adi.bc \
+    arrayInit.bc \
+    cast.bc \
+    dmain2.bc \
+    eh.bc \
+    genobj.bc \
+    lifetime.bc \
+    memory.bc \
+    qsort2.bc \
+    switch.bc \
+    invariant.bc
+
+OBJ_UTIL_BC= \
+    util/console.bc \
+    util/ctype.bc \
+    util/string.bc \
+    util/utf.bc
+
+OBJ_LDC_BC= \
+    ldc/bitmanip.bc \
+    ldc/vararg.bc
+
+OBJ_TI_BC= \
+    typeinfo/ti_AC.bc \
+    typeinfo/ti_Acdouble.bc \
+    typeinfo/ti_Acfloat.bc \
+    typeinfo/ti_Acreal.bc \
+    typeinfo/ti_Adouble.bc \
+    typeinfo/ti_Afloat.bc \
+    typeinfo/ti_Ag.bc \
+    typeinfo/ti_Aint.bc \
+    typeinfo/ti_Along.bc \
+    typeinfo/ti_Areal.bc \
+    typeinfo/ti_Ashort.bc \
+    typeinfo/ti_byte.bc \
+    typeinfo/ti_C.bc \
+    typeinfo/ti_cdouble.bc \
+    typeinfo/ti_cfloat.bc \
+    typeinfo/ti_char.bc \
+    typeinfo/ti_creal.bc \
+    typeinfo/ti_dchar.bc \
+    typeinfo/ti_delegate.bc \
+    typeinfo/ti_double.bc \
+    typeinfo/ti_float.bc \
+    typeinfo/ti_idouble.bc \
+    typeinfo/ti_ifloat.bc \
+    typeinfo/ti_int.bc \
+    typeinfo/ti_ireal.bc \
+    typeinfo/ti_long.bc \
+    typeinfo/ti_ptr.bc \
+    typeinfo/ti_real.bc \
+    typeinfo/ti_short.bc \
+    typeinfo/ti_ubyte.bc \
+    typeinfo/ti_uint.bc \
+    typeinfo/ti_ulong.bc \
+    typeinfo/ti_ushort.bc \
+    typeinfo/ti_void.bc \
+    typeinfo/ti_wchar.bc
+
+OBJ_BASE_O= \
+    aaA.o \
+    aApply.o \
+    aApplyR.o \
+    adi.o \
+    arrayInit.o \
+    cast.o \
+    dmain2.o \
+    eh.o \
+    genobj.o \
+    lifetime.o \
+    memory.o \
+    qsort2.o \
+    switch.o \
+    invariant.o
+
+OBJ_UTIL_O= \
+    util/console.o \
+    util/ctype.o \
+    util/string.o \
+    util/utf.o
+
+OBJ_LDC_O= \
+    ldc/bitmanip.o \
+    ldc/vararg.o
+
+OBJ_TI_O= \
+    typeinfo/ti_AC.o \
+    typeinfo/ti_Acdouble.o \
+    typeinfo/ti_Acfloat.o \
+    typeinfo/ti_Acreal.o \
+    typeinfo/ti_Adouble.o \
+    typeinfo/ti_Afloat.o \
+    typeinfo/ti_Ag.o \
+    typeinfo/ti_Aint.o \
+    typeinfo/ti_Along.o \
+    typeinfo/ti_Areal.o \
+    typeinfo/ti_Ashort.o \
+    typeinfo/ti_byte.o \
+    typeinfo/ti_C.o \
+    typeinfo/ti_cdouble.o \
+    typeinfo/ti_cfloat.o \
+    typeinfo/ti_char.o \
+    typeinfo/ti_creal.o \
+    typeinfo/ti_dchar.o \
+    typeinfo/ti_delegate.o \
+    typeinfo/ti_double.o \
+    typeinfo/ti_float.o \
+    typeinfo/ti_idouble.o \
+    typeinfo/ti_ifloat.o \
+    typeinfo/ti_int.o \
+    typeinfo/ti_ireal.o \
+    typeinfo/ti_long.o \
+    typeinfo/ti_ptr.o \
+    typeinfo/ti_real.o \
+    typeinfo/ti_short.o \
+    typeinfo/ti_ubyte.o \
+    typeinfo/ti_uint.o \
+    typeinfo/ti_ulong.o \
+    typeinfo/ti_ushort.o \
+    typeinfo/ti_void.o \
+    typeinfo/ti_wchar.o
+
+ALL_OBJS_BC= \
+    $(OBJ_BASE_BC) \
+    $(OBJ_UTIL_BC) \
+    $(OBJ_TI_BC) \
+    $(OBJ_LDC_BC)
+
+ALL_OBJS_O= \
+    $(OBJ_BASE_O) \
+    $(OBJ_UTIL_O) \
+    $(OBJ_TI_O) \
+    $(OBJ_LDC_O) \
+    $(OBJ_C)
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+#ldc.bclib : $(LIB_TARGET_BC_ONLY)
+ldc.clib : $(LIB_TARGET_C_ONLY)
+ldc.lib : $(LIB_TARGET_FULL)
+ldc.sharedlib : $(LIB_TARGET_SHARED)
+
+#$(LIB_TARGET_BC_ONLY) : $(ALL_OBJS_O)
+#	$(RM) $@
+#	$(LC) $@ $(ALL_OBJS_BC)
+
+
+$(LIB_TARGET_FULL) : $(ALL_OBJS_O)
+	$(RM) $@
+	$(CLC) $@ $(ALL_OBJS_O)
+
+
+$(LIB_TARGET_C_ONLY) : $(OBJ_C)
+	$(RM) $@
+	$(CLC) $@ $(OBJ_C)
+
+
+$(LIB_TARGET_SHARED) : $(ALL_OBJS_O)
+	$(RM) $@
+	$(CC) -shared -o $@ $(ALL_OBJS_O)
+
+
+ldc.doc : $(ALL_DOCS)
+	echo No documentation available.
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+#	$(RM) $(ALL_OBJS_BC)
+	$(RM) $(ALL_OBJS_O)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/ldc/bitmanip.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,81 @@
+/*
+ * D phobos intrinsics for LDC
+ *
+ * From GDC ... public domain!
+ */
+module ldc.bitmanip;
+
+// Check for the right compiler
+version(LDC)
+{
+    // OK
+}
+else
+{
+    static assert(false, "This module is only valid for LDC");
+}
+
+int bsf(uint v)
+{
+    uint m = 1;
+    uint i;
+    for (i = 0; i < 32; i++,m<<=1) {
+        if (v&m)
+        return i;
+    }
+    return i; // supposed to be undefined
+}
+
+int bsr(uint v)
+{
+    uint m = 0x80000000;
+    uint i;
+    for (i = 32; i ; i--,m>>>=1) {
+    if (v&m)
+        return i-1;
+    }
+    return i; // supposed to be undefined
+}
+
+int bt(uint *p, uint bitnum)
+{
+    return (p[bitnum / (uint.sizeof*8)] & (1<<(bitnum & ((uint.sizeof*8)-1)))) ? -1 : 0 ;
+}
+
+int btc(uint *p, uint bitnum)
+{
+    uint * q = p + (bitnum / (uint.sizeof*8));
+    uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
+    int result = *q & mask;
+    *q ^= mask;
+    return result ? -1 : 0;
+}
+
+int btr(uint *p, uint bitnum)
+{
+    uint * q = p + (bitnum / (uint.sizeof*8));
+    uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
+    int result = *q & mask;
+    *q &= ~mask;
+    return result ? -1 : 0;
+}
+
+int bts(uint *p, uint bitnum)
+{
+    uint * q = p + (bitnum / (uint.sizeof*8));
+    uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
+    int result = *q & mask;
+    *q |= mask;
+    return result ? -1 : 0;
+}
+
+pragma(intrinsic, "llvm.bswap.i32")
+    uint bswap(uint val);
+
+ubyte  inp(uint p) { throw new Exception("inp intrinsic not yet implemented"); }
+ushort inpw(uint p) { throw new Exception("inpw intrinsic not yet implemented"); }
+uint   inpl(uint p) { throw new Exception("inpl intrinsic not yet implemented"); }
+
+ubyte  outp(uint p, ubyte v) { throw new Exception("outp intrinsic not yet implemented"); }
+ushort outpw(uint p, ushort v) { throw new Exception("outpw intrinsic not yet implemented"); }
+uint   outpl(uint p, uint v) { throw new Exception("outpl intrinsic not yet implemented"); }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/ldc/vararg.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,43 @@
+/*
+ * This module holds the implementation of special vararg templates for D style var args.
+ *
+ * Provides the functions tango.core.Vararg expects to be present!
+ */
+
+module ldc.Vararg;
+
+// Check for the right compiler
+version(LDC)
+{
+    // OK
+}
+else
+{
+    static assert(false, "This module is only valid for LDC");
+}
+
+alias void* va_list;
+
+void va_start(T) ( out va_list ap, inout T parmn )
+{
+    // not needed !
+}
+
+T va_arg(T)(ref va_list vp)
+{
+    T* arg = cast(T*) vp;
+    // ldc always aligns to size_t.sizeof in vararg lists
+    vp = cast(va_list) ( cast(void*) vp + ( ( T.sizeof + size_t.sizeof - 1 ) & ~( size_t.sizeof - 1 ) ) );
+    return *arg;
+}
+
+void va_end( va_list ap )
+{
+    // not needed !
+}
+
+void va_copy( out va_list dst, va_list src )
+{
+    // seems pretty useless !
+    dst = src;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/lifetime.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,1147 @@
+/**
+ * This module contains all functions related to an object's lifetime:
+ * allocation, resizing, deallocation, and finalization.
+ *
+ * Copyright: Copyright (C) 2004-2007 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, Sean Kelly, Tomas Lindquist Olsen
+ */
+module lifetime;
+
+//debug=PRINTF;
+//debug=PRINTF2;
+
+private
+{
+    version( D_Version2 )
+    {
+    import stdc.stdlib;
+    import stdc.string;
+    import stdc.stdarg;
+    debug(PRINTF) import stdc.stdio;
+    else debug(PRINTF2) import stdc.stdio;
+    }
+    else
+    {
+    import tango.stdc.stdlib;
+    import tango.stdc.string;
+    import tango.stdc.stdarg;
+    debug(PRINTF) import tango.stdc.stdio;
+    else debug(PRINTF2) import tango.stdc.stdio;
+    }
+}
+
+
+private
+{
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    struct BlkInfo
+    {
+        void*  base;
+        size_t size;
+        uint   attr;
+    }
+
+    extern (C) uint gc_getAttr( void* p );
+    extern (C) uint gc_setAttr( void* p, uint a );
+    extern (C) uint gc_clrAttr( void* p, uint a );
+
+    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
+    extern (C) void   gc_free( void* p );
+
+    extern (C) void*   gc_addrOf( void* p );
+    extern (C) size_t  gc_sizeOf( void* p );
+    extern (C) BlkInfo gc_query( void* p );
+
+    extern (C) bool onCollectResource( Object o );
+    extern (C) void onFinalizeError( ClassInfo c, Exception e );
+    extern (C) void onOutOfMemoryError();
+
+    extern (C) void _d_monitordelete(Object h, bool det = true);
+
+    enum
+    {
+        PAGESIZE = 4096
+    }
+
+    alias bool function(Object) CollectHandler;
+    CollectHandler collectHandler = null;
+}
+
+
+/**
+ *
+ */
+extern (C) Object _d_allocclass(ClassInfo ci)
+{
+    void* p;
+
+    debug(PRINTF2) printf("_d_allocclass(ci = %p, %s)\n", ci, cast(char *)ci.name.ptr);
+    /+
+    if (ci.flags & 1) // if COM object
+    {   /* COM objects are not garbage collected, they are reference counted
+         * using AddRef() and Release().  They get free'd by C's free()
+         * function called by Release() when Release()'s reference count goes
+         * to zero.
+	 */
+        p = tango.stdc.stdlib.malloc(ci.init.length);
+        if (!p)
+            onOutOfMemoryError();
+    }
+    else
+    +/
+    {
+        p = gc_malloc(ci.init.length,
+                      BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0));
+        debug(PRINTF2) printf(" p = %p\n", p);
+    }
+
+    debug(PRINTF2)
+    {
+        printf("p = %p\n", p);
+        printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init.ptr, ci.init.length);
+        printf("vptr = %p\n", *cast(void**) ci.init.ptr);
+        printf("vtbl[0] = %p\n", (*cast(void***) ci.init.ptr)[0]);
+        printf("vtbl[1] = %p\n", (*cast(void***) ci.init.ptr)[1]);
+        printf("init[0] = %p\n", (cast(uint**) ci.init.ptr)[0]);
+        printf("init[1] = %p\n", (cast(uint**) ci.init.ptr)[1]);
+        printf("init[2] = %p\n", (cast(uint**) ci.init.ptr)[2]);
+        printf("init[3] = %p\n", (cast(uint**) ci.init.ptr)[3]);
+        printf("init[4] = %p\n", (cast(uint**) ci.init.ptr)[4]);
+    }
+
+    // initialize it
+    // ldc does this inline
+    //(cast(byte*) p)[0 .. ci.init.length] = ci.init[];
+
+    debug(PRINTF) printf("initialization done\n");
+    return cast(Object) p;
+}
+
+/**
+ *
+ */
+extern (C) void _d_delinterface(void* p)
+{
+    if (p)
+    {
+        Interface* pi = **cast(Interface ***)p;
+        Object     o  = cast(Object)(p - pi.offset);
+
+        _d_delclass(o);
+        //*p = null;
+    }
+}
+
+// used for deletion
+private extern (D) alias void function(Object) fp_t;
+
+
+/**
+ *
+ */
+extern (C) void _d_delclass(Object p)
+{
+    if (p)
+    {
+        debug(PRINTF) printf("_d_delclass(%p)\n", p);
+
+        ClassInfo **pc = cast(ClassInfo **)p;
+        if (*pc)
+        {
+            ClassInfo c = **pc;
+
+            rt_finalize(cast(void*) p);
+
+            if (c.deallocator)
+            {
+                fp_t fp = cast(fp_t)c.deallocator;
+                (*fp)(p); // call deallocator
+                //*p = null;
+                return;
+            }
+        }
+        else
+        {
+            rt_finalize(cast(void*) p);
+        }
+        gc_free(cast(void*) p);
+        //*p = null;
+    }
+}
+
+/+
+
+/**
+ *
+ */
+struct Array
+{
+    size_t length;
+    void*  data;
+}
+
++/
+
+/**
+ * Allocate a new array of length elements.
+ * ti is the type of the resulting array, or pointer to element.
+ * The resulting array is initialized to 0
+ */
+extern (C) void* _d_newarrayT(TypeInfo ti, size_t length)
+{
+    void* p;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayT(length = %u, size = %d)\n", length, size);
+    if (length == 0 || size == 0)
+        return null;
+
+    version (D_InlineAsm_X86)
+    {
+        asm
+        {
+            mov     EAX,size        ;
+            mul     EAX,length      ;
+            mov     size,EAX        ;
+            jc      Loverflow       ;
+        }
+    }
+    else
+        size *= length;
+    p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    debug(PRINTF) printf(" p = %p\n", p);
+    memset(p, 0, size);
+    return p;
+
+Loverflow:
+    onOutOfMemoryError();
+    return null;
+}
+
+/**
+ * As _d_newarrayT, but 
+ * for when the array has a non-zero initializer.
+ */
+extern (C) void* _d_newarrayiT(TypeInfo ti, size_t length)
+{
+    void* result;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayiT(length = %d, size = %d)\n", length, size);
+
+    if (length == 0 || size == 0)
+        result = null;
+    else
+    {
+        auto initializer = ti.next.init();
+        auto isize = initializer.length;
+        auto q = initializer.ptr;
+        version (D_InlineAsm_X86)
+        {
+            asm
+            {
+                mov     EAX,size        ;
+                mul     EAX,length      ;
+                mov     size,EAX        ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+            size *= length;
+        auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        debug(PRINTF) printf(" p = %p\n", p);
+        if (isize == 1)
+            memset(p, *cast(ubyte*)q, size);
+        else if (isize == int.sizeof)
+        {
+            int init = *cast(int*)q;
+            size /= int.sizeof;
+            for (size_t u = 0; u < size; u++)
+            {
+                (cast(int*)p)[u] = init;
+            }
+        }
+        else
+        {
+            for (size_t u = 0; u < size; u += isize)
+            {
+                memcpy(p + u, q, isize);
+            }
+        }
+        result = p;
+    }
+    return result;
+
+Loverflow:
+    onOutOfMemoryError();
+    return null;
+}
+
+/**
+ * As _d_newarrayT, but without initialization
+ */
+extern (C) void* _d_newarrayvT(TypeInfo ti, size_t length)
+{
+    void* p;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayvT(length = %u, size = %d)\n", length, size);
+    if (length == 0 || size == 0)
+        return null;
+
+    version (D_InlineAsm_X86)
+    {
+        asm
+        {
+            mov     EAX,size        ;
+            mul     EAX,length      ;
+            mov     size,EAX        ;
+            jc      Loverflow       ;
+        }
+    }
+    else
+        size *= length;
+    p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    debug(PRINTF) printf(" p = %p\n", p);
+    return p;
+
+Loverflow:
+    onOutOfMemoryError();
+    return null;
+}
+
+/**
+ * Allocate a new array of arrays of arrays of arrays ...
+ * ti is the type of the resulting array.
+ * ndims is the number of nested arrays.
+ * dims it the array of dimensions, its size is ndims.
+ * The resulting array is initialized to 0
+ */
+extern (C) void* _d_newarraymT(TypeInfo ti, int ndims, size_t* dims)
+{
+    void* result;
+
+    debug(PRINTF) printf("_d_newarraymT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = null;
+    else
+    {
+        static void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayT(ti, dim);
+                return r[0 .. dim];
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        result = foo(ti, dims, ndims).ptr;
+        debug(PRINTF) printf("result = %p\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, *dims++);
+            }
+        }
+    }
+    return result;
+}
+
+
+/**
+ * As _d_newarraymT, but 
+ * for when the array has a non-zero initializer.
+ */
+extern (C) void* _d_newarraymiT(TypeInfo ti, int ndims, size_t* dims)
+{
+    void* result;
+
+    debug(PRINTF) printf("_d_newarraymiT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = null;
+    else
+    {
+        static void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayiT(ti, dim);
+                p = r[0 .. dim];
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        result = foo(ti, dims, ndims).ptr;
+        debug(PRINTF) printf("result = %p\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, *dims++);
+                printf("init = %d\n", *dims++);
+            }
+        }
+    }
+    return result;
+}
+
+/**
+ * As _d_newarraymT, but without initialization
+ */
+extern (C) void* _d_newarraymvT(TypeInfo ti, int ndims, size_t* dims)
+{
+    void* result;
+
+    debug(PRINTF) printf("_d_newarraymvT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = null;
+    else
+    {
+        static void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayvT(ti, dim);
+                return r[0 .. dim];
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        result = foo(ti, dims, ndims).ptr;
+        debug(PRINTF) printf("result = %p\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, *dims++);
+            }
+        }
+    }
+    return result;
+}
+
+/+
+
+/**
+ *
+ */
+void* _d_allocmemory(size_t nbytes)
+{
+    return gc_malloc(nbytes);
+}
+
++/
+
+/**
+ * for allocating a single POD value
+ */
+extern (C) void* _d_allocmemoryT(TypeInfo ti)
+{
+    return gc_malloc(ti.tsize(), !(ti.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+}
+
+/**
+ *
+ */
+extern (C) void _d_delarray(size_t plength, void* pdata)
+{
+//     if (p)
+//     {
+        assert(!plength || pdata);
+
+        if (pdata)
+            gc_free(pdata);
+//         p.data = null;
+//         p.length = 0;
+//     }
+}
+
+/**
+ *
+ */
+extern (C) void _d_delmemory(void* p)
+{
+    if (p)
+    {
+        gc_free(p);
+        //*p = null;
+    }
+}
+
+/** 
+ * 
+ */ 
+extern (C) void _d_callinterfacefinalizer(void *p)
+{
+    if (p)
+    {
+        Interface *pi = **cast(Interface ***)p;
+        Object o = cast(Object)(p - pi.offset);
+        rt_finalize(cast(void*)o);
+    }
+}
+
+/**
+ *
+ */
+extern (C) void _d_callfinalizer(void* p)
+{
+    rt_finalize( p );
+}
+
+
+/**
+ *
+ */
+extern (C) void  rt_setCollectHandler(CollectHandler h)
+{
+    collectHandler = h;
+}
+
+/**
+ *
+ */
+extern (C) void rt_finalize(void* p, bool det = true)
+{
+    debug(PRINTF) printf("rt_finalize(p = %p)\n", p);
+
+    if (p) // not necessary if called from gc
+    {
+        ClassInfo** pc = cast(ClassInfo**)p;
+
+        if (*pc)
+        {
+            ClassInfo c = **pc;
+
+            try
+            {
+                if (det || collectHandler is null || collectHandler(cast(Object)p))
+                {
+                    do
+                    {
+                        if (c.destructor)
+                        {
+                            debug(PRINTF) printf("calling dtor of %.*s\n", c.name.length, c.name.ptr);
+                            fp_t fp = cast(fp_t)c.destructor;
+                            (*fp)(cast(Object)p); // call destructor
+                        }
+                        c = c.base;
+                    } while (c);
+                }
+                if ((cast(void**)p)[1]) // if monitor is not null
+                    _d_monitordelete(cast(Object)p, det);
+            }
+            catch (Exception e)
+            {
+                onFinalizeError(**pc, e);
+            }
+            finally
+            {
+                *pc = null; // zero vptr
+            }
+        }
+    }
+}
+
+/**
+ * Resize dynamic arrays with 0 initializers.
+ */
+extern (C) byte* _d_arraysetlengthT(TypeInfo ti, size_t newlength, size_t plength, byte* pdata)
+in
+{
+    assert(ti);
+    assert(!plength || pdata);
+}
+body
+{
+    byte* newdata;
+    size_t sizeelem = ti.next.tsize();
+
+    debug(PRINTF)
+    {
+        printf("_d_arraysetlengthT(sizeelem = %d, newlength = %d)\n", sizeelem, newlength);
+        printf("\tp.data = %p, p.length = %d\n", pdata, plength);
+    }
+
+    if (newlength)
+    {
+        version (D_InlineAsm_X86)
+        {
+            size_t newsize = void;
+
+            asm
+            {
+                mov EAX, newlength;
+                mul EAX, sizeelem;
+                mov newsize, EAX;
+                jc  Loverflow;
+            }
+        }
+        else
+        {
+            size_t newsize = sizeelem * newlength;
+
+            if (newsize / newlength != sizeelem)
+                goto Loverflow;
+        }
+
+        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+        if (pdata)
+        {
+            newdata = pdata;
+            if (newlength > plength)
+            {
+                size_t size = plength * sizeelem;
+                auto   info = gc_query(pdata);
+
+                if (info.size <= newsize || info.base != pdata)
+                {
+                    if (info.size >= PAGESIZE && info.base == pdata)
+                    {   // Try to extend in-place
+                        auto u = gc_extend(pdata, (newsize + 1) - info.size, (newsize + 1) - info.size);
+                        if (u)
+                        {
+                            goto L1;
+                        }
+                    }
+                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
+                    newdata[0 .. size] = pdata[0 .. size];
+                }
+             L1:
+                newdata[size .. newsize] = 0;
+            }
+        }
+        else
+        {
+            newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        }
+    }
+    else
+    {
+        newdata = pdata;
+    }
+
+    return newdata;
+
+Loverflow:
+    onOutOfMemoryError();
+    return null;
+}
+
+
+/**
+ * Resize arrays for non-zero initializers.
+ *      p               pointer to array lvalue to be updated
+ *      newlength       new .length property of array
+ *      sizeelem        size of each element of array
+ *      initsize        size of initializer
+ *      ...             initializer
+ */
+extern (C) byte* _d_arraysetlengthiT(TypeInfo ti, size_t newlength, size_t plength, byte* pdata)
+in
+{
+    assert(!plength || pdata);
+}
+body
+{
+    byte* newdata;
+    TypeInfo tinext = ti.next;
+    size_t sizeelem = tinext.tsize();
+    void[] initializer = tinext.init();
+    size_t initsize = initializer.length;
+
+    assert(sizeelem);
+    assert(initsize);
+    assert(initsize <= sizeelem);
+    assert((sizeelem / initsize) * initsize == sizeelem);
+
+    debug(PRINTF)
+    {
+        printf("_d_arraysetlengthiT(sizeelem = %d, newlength = %d, initsize = %d)\n", sizeelem, newlength, initsize);
+        printf("\tp.data = %p, p.length = %d\n", pdata, plength);
+    }
+
+    if (newlength)
+    {
+        version (D_InlineAsm_X86)
+        {
+            size_t newsize = void;
+
+            asm
+            {
+                mov     EAX,newlength   ;
+                mul     EAX,sizeelem    ;
+                mov     newsize,EAX     ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+        {
+            size_t newsize = sizeelem * newlength;
+
+            if (newsize / newlength != sizeelem)
+                goto Loverflow;
+        }
+        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+        size_t size = plength * sizeelem;
+
+        if (pdata)
+        {
+            newdata = pdata;
+            if (newlength > plength)
+            {
+                auto info = gc_query(pdata);
+
+                if (info.size <= newsize || info.base != pdata)
+                {
+                    if (info.size >= PAGESIZE && info.base == pdata)
+                    {   // Try to extend in-place
+                        auto u = gc_extend(pdata, (newsize + 1) - info.size, (newsize + 1) - info.size);
+                        if (u)
+                        {
+                            goto L1;
+                        }
+                    }
+                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
+                    newdata[0 .. size] = pdata[0 .. size];
+                L1: ;
+                }
+            }
+        }
+        else
+        {
+            newdata = cast(byte *)gc_malloc(newsize + 1, !(tinext.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        }
+
+        auto q = initializer.ptr; // pointer to initializer
+
+        if (newsize > size)
+        {
+            if (initsize == 1)
+            {
+                debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q);
+                newdata[size .. newsize] = *(cast(byte*)q);
+            }
+            else
+            {
+                for (size_t u = size; u < newsize; u += initsize)
+                {
+                    memcpy(newdata + u, q, initsize);
+                }
+            }
+        }
+    }
+    else
+    {
+        newdata = pdata;
+    }
+
+    return newdata;
+
+Loverflow:
+    onOutOfMemoryError();
+    return null;
+}
+
+/+
+
+/**
+ * Append y[] to array x[].
+ * size is size of each array element.
+ */
+extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    auto info = gc_query(px.data);
+    auto length = px.length;
+    auto newlength = length + y.length;
+    auto newsize = newlength * sizeelem;
+
+    if (info.size < newsize || info.base != px.data)
+    {   byte* newdata;
+
+        if (info.size >= PAGESIZE && info.base == px.data)
+        {   // Try to extend in-place
+            auto u = gc_extend(px.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+            if (u)
+            {
+                goto L1;
+            }
+        }
+        newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr);
+        memcpy(newdata, px.data, length * sizeelem);
+        px.data = newdata;
+    }
+  L1:
+    px.length = newlength;
+    memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem);
+    return *cast(long*)px;
+}
+
+
+/**
+ *
+ */
+size_t newCapacity(size_t newlength, size_t size)
+{
+    version(none)
+    {
+        size_t newcap = newlength * size;
+    }
+    else
+    {
+        /*
+         * Better version by Dave Fladebo:
+         * This uses an inverse logorithmic algorithm to pre-allocate a bit more
+         * space for larger arrays.
+         * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most
+         * common cases, memory allocation is 1 to 1. The small overhead added
+         * doesn't affect small array perf. (it's virtually the same as
+         * current).
+         * - Larger arrays have some space pre-allocated.
+         * - As the arrays grow, the relative pre-allocated space shrinks.
+         * - The logorithmic algorithm allocates relatively more space for
+         * mid-size arrays, making it very fast for medium arrays (for
+         * mid-to-large arrays, this turns out to be quite a bit faster than the
+         * equivalent realloc() code in C, on Linux at least. Small arrays are
+         * just as fast as GCC).
+         * - Perhaps most importantly, overall memory usage and stress on the GC
+         * is decreased significantly for demanding environments.
+         */
+        size_t newcap = newlength * size;
+        size_t newext = 0;
+
+        if (newcap > PAGESIZE)
+        {
+            //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0)));
+
+            // redo above line using only integer math
+
+            static int log2plus1(size_t c)
+            {   int i;
+
+                if (c == 0)
+                    i = -1;
+                else
+                    for (i = 1; c >>= 1; i++)
+                    {
+                    }
+                return i;
+            }
+
+            /* The following setting for mult sets how much bigger
+             * the new size will be over what is actually needed.
+             * 100 means the same size, more means proportionally more.
+             * More means faster but more memory consumption.
+             */
+            //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap));
+            long mult = 100 + (1000L * size) / log2plus1(newcap);
+
+            // testing shows 1.02 for large arrays is about the point of diminishing return
+            if (mult < 102)
+                mult = 102;
+            newext = cast(size_t)((newcap * mult) / 100);
+            newext -= newext % size;
+            debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size);
+        }
+        newcap = newext > newcap ? newext : newcap;
+        debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
+    }
+    return newcap;
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arrayappendcT(TypeInfo ti, inout byte[] x, ...)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    auto info = gc_query(x.ptr);
+    auto length = x.length;
+    auto newlength = length + 1;
+    auto newsize = newlength * sizeelem;
+
+    assert(info.size == 0 || length * sizeelem <= info.size);
+
+    debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size);
+
+    if (info.size <= newsize || info.base != x.ptr)
+    {   byte* newdata;
+
+        if (info.size >= PAGESIZE && info.base == x.ptr)
+        {   // Try to extend in-place
+            auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size);
+            if (u)
+            {
+                goto L1;
+            }
+        }
+        debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size);
+        auto newcap = newCapacity(newlength, sizeelem);
+        assert(newcap >= newlength * sizeelem);
+        newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
+        memcpy(newdata, x.ptr, length * sizeelem);
+        (cast(void**)(&x))[1] = newdata;
+    }
+  L1:
+    byte *argp = cast(byte *)(&ti + 2);
+
+    *cast(size_t *)&x = newlength;
+    x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
+    assert((cast(size_t)x.ptr & 15) == 0);
+    assert(gc_sizeOf(x.ptr) > x.length * sizeelem);
+    return x;
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr);
+    assert(result.length == x.length + y.length);
+    for (size_t i = 0; i < x.length * sizeelem; i++)
+        assert((cast(byte*)result)[i] == (cast(byte*)x)[i]);
+    for (size_t i = 0; i < y.length * sizeelem; i++)
+        assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]);
+
+    size_t cap = gc_sizeOf(result.ptr);
+    assert(!cap || cap > result.length * sizeelem);
+}
+body
+{
+    version (none)
+    {
+        /* Cannot use this optimization because:
+         *  char[] a, b;
+         *  char c = 'a';
+         *  b = a ~ c;
+         *  c = 'b';
+         * will change the contents of b.
+         */
+        if (!y.length)
+            return x;
+        if (!x.length)
+            return y;
+    }
+
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr);
+    auto sizeelem = ti.next.tsize();            // array element size
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem);
+    size_t xlen = x.length * sizeelem;
+    size_t ylen = y.length * sizeelem;
+    size_t len  = xlen + ylen;
+
+    if (!len)
+        return null;
+
+    byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    memcpy(p, x.ptr, xlen);
+    memcpy(p + xlen, y.ptr, ylen);
+    p[len] = 0;
+    return p[0 .. x.length + y.length];
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
+{   void* a;
+    size_t length;
+    byte[]* p;
+    uint i;
+    byte[] b;
+    auto size = ti.next.tsize(); // array element size
+
+    p = cast(byte[]*)(&n + 1);
+
+    for (i = 0; i < n; i++)
+    {
+        b = *p++;
+        length += b.length;
+    }
+    if (!length)
+        return null;
+
+    a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    p = cast(byte[]*)(&n + 1);
+
+    uint j = 0;
+    for (i = 0; i < n; i++)
+    {
+        b = *p++;
+        if (b.length)
+        {
+            memcpy(a + j, b.ptr, b.length * size);
+            j += b.length * size;
+        }
+    }
+
+    byte[] result;
+    *cast(int *)&result = length;       // jam length
+    (cast(void **)&result)[1] = a;      // jam ptr
+    return result;
+}
+
+
+/**
+ *
+ */
+extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    void* result;
+
+    debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length);
+    if (length == 0 || sizeelem == 0)
+        result = null;
+    else
+    {
+        result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+
+        va_list q;
+        va_start!(size_t)(q, length);
+
+        size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1);
+
+        if (stacksize == sizeelem)
+        {
+            memcpy(result, q, length * sizeelem);
+        }
+        else
+        {
+            for (size_t i = 0; i < length; i++)
+            {
+                memcpy(result + i * sizeelem, q, sizeelem);
+                q += stacksize;
+            }
+        }
+
+        va_end(q);
+    }
+    return result;
+}
+
++/
+
+
+/**
+ * Support for array.dup property.
+ * The actual type is painted on the return value by the frontend
+ * Given length is number of elements
+ * Returned length is number of elements
+ */
+
+
+/**
+ *
+ */
+extern (C) void[] _adDupT(TypeInfo ti, void[] a)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    assert(memcmp(result.ptr, a.ptr, a.length * sizeelem) == 0);
+}
+body
+{
+    void* ptr;
+
+    if (a.length)
+    {
+        auto sizeelem = ti.next.tsize();                // array element size
+        auto size = a.length * sizeelem;
+        ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        memcpy(ptr, a.ptr, size);
+    }
+    return ptr[0 .. a.length];
+}
+
+
+unittest
+{
+    int[] a;
+    int[] b;
+    int i;
+
+    a = new int[3];
+    a[0] = 1; a[1] = 2; a[2] = 3;
+    b = a.dup;
+    assert(b.length == 3);
+    for (i = 0; i < 3; i++)
+        assert(b[i] == i + 1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/mars.h	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,105 @@
+
+/*
+ * Placed into the Public Domain
+ * written by Walter Bright, Digital Mars
+ * www.digitalmars.com
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+#include <stddef.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+struct ClassInfo;
+struct Vtbl;
+
+typedef struct Vtbl
+{
+    size_t len;
+    void **vptr;
+} Vtbl;
+
+typedef struct Interface
+{
+    struct ClassInfo *classinfo;
+    struct Vtbl vtbl;
+    int offset;
+} Interface;
+
+typedef struct Object
+{
+    void **vptr;
+    void *monitor;
+} Object;
+
+typedef struct ClassInfo
+{
+    Object object;
+
+    size_t initlen;
+    void *init;
+
+    size_t namelen;
+    char *name;
+
+    Vtbl vtbl;
+
+    size_t interfacelen;
+    Interface *interfaces;
+
+    struct ClassInfo *baseClass;
+
+    void *destructor;
+    void *invariant;
+
+    int flags;
+} ClassInfo;
+
+typedef struct Exception
+{
+    Object object;
+
+    size_t msglen;
+    char*  msg;
+
+    size_t filelen;
+    char*  file;
+
+    size_t line;
+
+    struct Interface *info;
+    struct Exception *next;
+} Exception;
+
+typedef struct Array
+{
+    size_t length;
+    void *ptr;
+} Array;
+
+typedef struct Delegate
+{
+    void *thisptr;
+    void (*funcptr)();
+} Delegate;
+
+void _d_monitorenter(Object *h);
+void _d_monitorexit(Object *h);
+
+int _d_isbaseof(ClassInfo *b, ClassInfo *c);
+Object *_d_dynamic_cast(Object *o, ClassInfo *ci);
+
+Object * _d_allocclass(ClassInfo *ci);
+void _d_delclass(Object **p);
+
+void _d_OutOfMemory();
+
+#if __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/memory.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,378 @@
+/**
+ * This module exposes functionality for inspecting and manipulating memory.
+ *
+ * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, Sean Kelly
+ */
+module memory;
+
+version = GC_Use_Dynamic_Ranges;
+
+// does Posix suffice?
+version(Posix)
+{
+    version = GC_Use_Data_Proc_Maps;
+}
+
+version(GC_Use_Data_Proc_Maps)
+{
+    version(Posix) {} else {
+        static assert(false, "Proc Maps only supported on Posix systems");
+    }
+
+    version( D_Version2 )
+    {
+    private import stdc.posix.unistd;
+    private import stdc.posix.fcntl;
+    private import stdc.string;
+    }
+    else
+    {
+    private import tango.stdc.posix.unistd;
+    private import tango.stdc.posix.fcntl;
+    private import tango.stdc.string;
+    }
+
+    version = GC_Use_Dynamic_Ranges;
+}
+
+private
+{
+    version( linux )
+    {
+        //version = SimpleLibcStackEnd;
+
+        version( SimpleLibcStackEnd )
+        {
+            extern (C) extern void* __libc_stack_end;
+        }
+        else
+        {
+            version( D_Version2 )
+            import stdc.posix.dlfcn;
+            else
+            import tango.stdc.posix.dlfcn;
+        }
+    }
+    version(LDC)
+    {
+        pragma(intrinsic, "llvm.frameaddress")
+        {
+                void* llvm_frameaddress(uint level=0);
+        }
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void* rt_stackBottom()
+{
+    version( Win32 )
+    {
+        void* bottom;
+        asm
+        {
+            mov EAX, FS:4;
+            mov bottom, EAX;
+        }
+        return bottom;
+    }
+    else version( linux )
+    {
+        version( SimpleLibcStackEnd )
+        {
+            return __libc_stack_end;
+        }
+        else
+        {
+            // See discussion: http://autopackage.org/forums/viewtopic.php?t=22
+                static void** libc_stack_end;
+
+                if( libc_stack_end == libc_stack_end.init )
+                {
+                    void* handle = dlopen( null, RTLD_NOW );
+                    libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" );
+                    dlclose( handle );
+                }
+                return *libc_stack_end;
+        }
+    }
+    else version( darwin )
+    {
+        // darwin has a fixed stack bottom
+        return cast(void*) 0xc0000000;
+    }
+    else
+    {
+        static assert( false, "Operating system not supported." );
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void* rt_stackTop()
+{
+    version(LDC)
+    {
+        return llvm_frameaddress();
+    }
+    else version( D_InlineAsm_X86 )
+    {
+        asm
+        {
+            naked;
+            mov EAX, ESP;
+            ret;
+        }
+    }
+    else
+    {
+            static assert( false, "Architecture not supported." );
+    }
+}
+
+
+private
+{
+    version( Win32 )
+    {
+        extern (C)
+        {
+            extern int _data_start__;
+            extern int _bss_end__;
+
+            alias _data_start__ Data_Start;
+            alias _bss_end__    Data_End;
+        }
+    }
+    else version( linux )
+    {
+        extern (C)
+        {
+            extern int _data;
+            extern int __data_start;
+            extern int _end;
+            extern int _data_start__;
+            extern int _data_end__;
+            extern int _bss_start__;
+            extern int _bss_end__;
+            extern int __fini_array_end;
+        }
+
+            alias __data_start  Data_Start;
+            alias _end          Data_End;
+    }
+
+    version( GC_Use_Dynamic_Ranges )
+    {
+        version( D_Version2 )
+        private import stdc.stdlib;
+        else
+        private import tango.stdc.stdlib;
+
+        struct DataSeg
+        {
+            void* beg;
+            void* end;
+        }
+
+        DataSeg* allSegs = null;
+        size_t   numSegs = 0;
+
+        extern (C) void _d_gc_add_range( void* beg, void* end )
+        {
+            void* ptr = realloc( allSegs, (numSegs + 1) * DataSeg.sizeof );
+
+            if( ptr ) // if realloc fails, we have problems
+            {
+                allSegs = cast(DataSeg*) ptr;
+                allSegs[numSegs].beg = beg;
+                allSegs[numSegs].end = end;
+                numSegs++;
+            }
+        }
+
+        extern (C) void _d_gc_remove_range( void* beg )
+        {
+            for( size_t pos = 0; pos < numSegs; ++pos )
+            {
+                if( beg == allSegs[pos].beg )
+                {
+                    while( ++pos < numSegs )
+                    {
+                        allSegs[pos-1] = allSegs[pos];
+                    }
+                    numSegs--;
+                    return;
+                }
+            }
+        }
+    }
+
+    alias void delegate( void*, void* ) scanFn;
+
+    void* dataStart,  dataEnd;
+}
+
+
+/**
+ *
+ */
+extern (C) void rt_scanStaticData( scanFn scan )
+{
+    scan( dataStart, dataEnd );
+
+    version( GC_Use_Dynamic_Ranges )
+    {
+        for( size_t pos = 0; pos < numSegs; ++pos )
+        {
+            scan( allSegs[pos].beg, allSegs[pos].end );
+        }
+    }
+}
+
+void initStaticDataPtrs()
+{
+    version( D_Version2 )
+    enum { int S = (void*).sizeof }
+    else
+    const int S = (void*).sizeof;
+
+    // Can't assume the input addresses are word-aligned
+    static void* adjust_up( void* p )
+    {
+        return p + ((S - (cast(size_t)p & (S-1))) & (S-1)); // cast ok even if 64-bit
+    }
+
+    static void * adjust_down( void* p )
+    {
+        return p - (cast(size_t) p & (S-1));
+    }
+
+    version( Win32 )
+    {
+        dataStart = adjust_up( &Data_Start );
+        dataEnd   = adjust_down( &Data_End );
+    }
+    else version( GC_Use_Data_Proc_Maps )
+    {
+        // TODO: Exclude zero-mapped regions
+
+        int   fd = open("/proc/self/maps", O_RDONLY);
+        int   count; // %% need to configure ret for read..
+        char  buf[2024];
+        char* p;
+        char* e;
+        char* s;
+        void* start;
+        void* end;
+
+        p = buf.ptr;
+        if (fd != -1)
+        {
+            while ( (count = read(fd, p, buf.sizeof - (p - buf.ptr))) > 0 )
+            {
+                e = p + count;
+                p = buf.ptr;
+                while (true)
+                {
+                    s = p;
+                    while (p < e && *p != '\n')
+                        p++;
+                    if (p < e)
+                    {
+                        // parse the entry in [s, p)
+                        static if( S == 4 )
+                        {
+                            enum Ofs
+                            {
+                                Write_Prot = 19,
+                                Start_Addr = 0,
+                                End_Addr   = 9,
+                                Addr_Len   = 8,
+                            }
+                        }
+                        else static if( S == 8 )
+                        {
+                            enum Ofs
+                            {
+                                Write_Prot = 35,
+                                Start_Addr = 0,
+                                End_Addr   = 9,
+                                Addr_Len   = 17,
+                            }
+                        }
+                        else
+                        {
+                            static assert( false );
+                        }
+
+                        // %% this is wrong for 64-bit:
+                        // uint   strtoul(char *,char **,int);
+
+                        if( s[Ofs.Write_Prot] == 'w' )
+                        {
+                            s[Ofs.Start_Addr + Ofs.Addr_Len] = '\0';
+                            s[Ofs.End_Addr + Ofs.Addr_Len] = '\0';
+                            start = cast(void*) strtoul(s + Ofs.Start_Addr, null, 16);
+                            end   = cast(void*) strtoul(s + Ofs.End_Addr, null, 16);
+
+                            // 1. Exclude anything overlapping [dataStart, dataEnd)
+                            // 2. Exclude stack
+                            if ( ( !dataEnd ||
+                                   !( dataStart >= start && dataEnd <= end ) ) &&
+                                 !( &buf[0] >= start && &buf[0] < end ) )
+                            {
+                                // we already have static data from this region.  anything else
+                                // is heap (%% check)
+                                debug (ProcMaps) printf("Adding map range %p 0%p\n", start, end);
+                                _d_gc_add_range(start, end);
+                            }
+                        }
+                        p++;
+                    }
+                    else
+                    {
+                        count = p - s;
+                        memmove(buf.ptr, s, count);
+                        p = buf.ptr + count;
+                        break;
+                    }
+                }
+            }
+            close(fd);
+        }
+    }
+    else version(linux)
+    {
+        dataStart = adjust_up( &Data_Start );
+        dataEnd   = adjust_down( &Data_End );
+    }
+    else
+    {
+        static assert( false, "Operating system not supported." );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/monitor.c	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,212 @@
+// D programming language runtime library
+// Public Domain
+// written by Walter Bright, Digital Mars
+// www.digitalmars.com
+
+// This is written in C because nobody has written a pthreads interface
+// to D yet.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if _WIN32
+#elif linux || __APPLE__
+#define USE_PTHREADS	1
+#else
+#endif
+
+#if _WIN32
+#include <windows.h>
+#endif
+
+#if USE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include "mars.h"
+
+// This is what the monitor reference in Object points to
+typedef struct Monitor
+{
+    void* impl; // for user-level monitors
+    Array devt; // for internal monitors
+
+#if _WIN32
+    CRITICAL_SECTION mon;
+#endif
+
+#if USE_PTHREADS
+    pthread_mutex_t mon;
+#endif
+} Monitor;
+
+#define MONPTR(h)	(&((Monitor *)(h)->monitor)->mon)
+
+static volatile int inited;
+
+/* =============================== Win32 ============================ */
+
+#if _WIN32
+
+static CRITICAL_SECTION _monitor_critsec;
+
+void _STI_monitor_staticctor()
+{
+    if (!inited)
+    {	InitializeCriticalSection(&_monitor_critsec);
+	inited = 1;
+    }
+}
+
+void _STD_monitor_staticdtor()
+{
+    if (inited)
+    {	inited = 0;
+	DeleteCriticalSection(&_monitor_critsec);
+    }
+}
+
+void _d_monitor_create(Object *h)
+{
+    /*
+     * NOTE: Assume this is only called when h->monitor is null prior to the
+     * call.  However, please note that another thread may call this function
+     * at the same time, so we can not assert this here.  Instead, try and
+     * create a lock, and if one already exists then forget about it.
+     */
+
+    //printf("+_d_monitor_create(%p)\n", h);
+    assert(h);
+    Monitor *cs = NULL;
+    EnterCriticalSection(&_monitor_critsec);
+    if (!h->monitor)
+    {
+        cs = (Monitor *)calloc(sizeof(Monitor), 1);
+        assert(cs);
+        InitializeCriticalSection(&cs->mon);
+        h->monitor = (void *)cs;
+        cs = NULL;
+    }
+    LeaveCriticalSection(&_monitor_critsec);
+    if (cs)
+        free(cs);
+    //printf("-_d_monitor_create(%p)\n", h);
+}
+
+void _d_monitor_destroy(Object *h)
+{
+    //printf("+_d_monitor_destroy(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    DeleteCriticalSection(MONPTR(h));
+    free((void *)h->monitor);
+    h->monitor = NULL;
+    //printf("-_d_monitor_destroy(%p)\n", h);
+}
+
+int _d_monitor_lock(Object *h)
+{
+    //printf("+_d_monitor_acquire(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    EnterCriticalSection(MONPTR(h));
+    //printf("-_d_monitor_acquire(%p)\n", h);
+}
+
+void _d_monitor_unlock(Object *h)
+{
+    //printf("+_d_monitor_release(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    LeaveCriticalSection(MONPTR(h));
+    //printf("-_d_monitor_release(%p)\n", h);
+}
+
+#endif
+
+/* =============================== linux ============================ */
+
+#if USE_PTHREADS
+
+#if !linux
+#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
+#endif
+
+// Includes attribute fixes from David Friedman's GDC port
+
+static pthread_mutex_t _monitor_critsec;
+static pthread_mutexattr_t _monitors_attr;
+
+void _STI_monitor_staticctor()
+{
+    if (!inited)
+    {
+	pthread_mutexattr_init(&_monitors_attr);
+	pthread_mutexattr_settype(&_monitors_attr, PTHREAD_MUTEX_RECURSIVE_NP);
+	pthread_mutex_init(&_monitor_critsec, 0);
+	inited = 1;
+    }
+}
+
+void _STD_monitor_staticdtor()
+{
+    if (inited)
+    {	inited = 0;
+	pthread_mutex_destroy(&_monitor_critsec);
+	pthread_mutexattr_destroy(&_monitors_attr);
+    }
+}
+
+void _d_monitor_create(Object *h)
+{
+    /*
+     * NOTE: Assume this is only called when h->monitor is null prior to the
+     * call.  However, please note that another thread may call this function
+     * at the same time, so we can not assert this here.  Instead, try and
+     * create a lock, and if one already exists then forget about it.
+     */
+
+    //printf("+_d_monitor_create(%p)\n", h);
+    assert(h);
+    Monitor *cs = NULL;
+    pthread_mutex_lock(&_monitor_critsec);
+    if (!h->monitor)
+    {
+        cs = (Monitor *)calloc(sizeof(Monitor), 1);
+        assert(cs);
+        pthread_mutex_init(&cs->mon, & _monitors_attr);
+        h->monitor = (void *)cs;
+        cs = NULL;
+    }
+    pthread_mutex_unlock(&_monitor_critsec);
+    if (cs)
+        free(cs);
+    //printf("-_d_monitor_create(%p)\n", h);
+}
+
+void _d_monitor_destroy(Object *h)
+{
+    //printf("+_d_monitor_destroy(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_destroy(MONPTR(h));
+    free((void *)h->monitor);
+    h->monitor = NULL;
+    //printf("-_d_monitor_destroy(%p)\n", h);
+}
+
+int _d_monitor_lock(Object *h)
+{
+    //printf("+_d_monitor_acquire(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_lock(MONPTR(h));
+    //printf("-_d_monitor_acquire(%p)\n", h);
+}
+
+void _d_monitor_unlock(Object *h)
+{
+    //printf("+_d_monitor_release(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_unlock(MONPTR(h));
+    //printf("-_d_monitor_release(%p)\n", h);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/qsort2.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,67 @@
+
+/*
+ * Placed into Public Domain
+ * written by Walter Bright
+ * www.digitalmars.com
+ *
+ * This is a public domain version of qsort.d.
+ * All it does is call C's qsort(), but runs a little slower since
+ * it needs to synchronize a global variable.
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+//debug=qsort;
+
+version( D_Version2 )
+private import stdlib = stdc.stdlib;
+else
+private import stdlib = tango.stdc.stdlib;
+
+private TypeInfo tiglobal;
+
+extern (C) int cmp(in void* p1, in void* p2)
+{
+    return tiglobal.compare(p1, p2);
+}
+
+extern (C) void[] _adSort(void[] a, TypeInfo ti)
+{
+    synchronized
+    {
+        tiglobal = ti;
+        stdlib.qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp);
+    }
+    return a;
+}
+
+
+
+unittest
+{
+    debug(qsort) printf("array.sort.unittest()\n");
+
+    int a[] = new int[10];
+
+    a[0] = 23;
+    a[1] = 1;
+    a[2] = 64;
+    a[3] = 5;
+    a[4] = 6;
+    a[5] = 5;
+    a[6] = 17;
+    a[7] = 3;
+    a[8] = 0;
+    a[9] = -1;
+
+    a.sort;
+
+    for (int i = 0; i < a.length - 1; i++)
+    {
+        //printf("i = %d", i);
+        //printf(" %d %d\n", a[i], a[i + 1]);
+        assert(a[i] <= a[i + 1]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/switch.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,428 @@
+/*
+ *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/*
+ *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
+ */
+
+version( D_Version2 )
+private import stdc.string;
+else
+private import tango.stdc.string;
+//private import tango.stdc.stdio;
+
+/******************************************************
+ * Support for switch statements switching on strings.
+ * Input:
+ *      table[]         sorted array of strings generated by compiler
+ *      ca              string to look up in table
+ * Output:
+ *      result          index of match in table[]
+ *                      -1 if not in table
+ */
+
+extern (C):
+
+int _d_switch_string(char[][] table, char[] ca)
+in
+{
+    //printf("in _d_switch_string()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        size_t len1 = table[j - 1].length;
+        size_t len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int ci;
+
+            ci = memcmp(table[j - 1].ptr, table[j].ptr, len1);
+            assert(ci < 0); // ci==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int cj;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   cj = memcmp(table[i].ptr, ca.ptr, ca.length);
+                assert(cj != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                cj = memcmp(table[i].ptr, ca.ptr, ca.length);
+                if (cj == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_string(%.*s)\n", ca.length, ca.ptr);
+    size_t low;
+    size_t high;
+    size_t mid;
+    ptrdiff_t c;
+    char[] pca;
+
+    low = 0;
+    high = table.length;
+
+    version (none)
+    {
+        // Print table
+        printf("ca[] = '%s'\n", cast(char *)ca);
+        for (mid = 0; mid < high; mid++)
+        {
+            pca = table[mid];
+            printf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+        }
+    }
+    if (high &&
+        ca.length >= table[0].length &&
+        ca.length <= table[high - 1].length)
+    {
+        // Looking for 0 length string, which would only be at the beginning
+        if (ca.length == 0)
+            return 0;
+
+        char c1 = ca[0];
+
+        // Do binary search
+        while (low < high)
+        {
+            mid = (low + high) >> 1;
+            pca = table[mid];
+            c = cast(ptrdiff_t)(ca.length - pca.length);
+            if (c == 0)
+            {
+                c = cast(ubyte)c1 - cast(ubyte)pca[0];
+                if (c == 0)
+                {
+                    c = memcmp(ca.ptr, pca.ptr, ca.length);
+                    if (c == 0)
+                    {   //printf("found %d\n", mid);
+                        return cast(int)mid;
+                    }
+                }
+            }
+            if (c < 0)
+            {
+                high = mid;
+            }
+            else
+            {
+                low = mid + 1;
+            }
+        }
+    }
+
+    //printf("not found\n");
+    return -1; // not found
+}
+
+unittest
+{
+    switch (cast(char []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
+
+/**********************************
+ * Same thing, but for wide chars.
+ */
+
+int _d_switch_ustring(wchar[][] table, wchar[] ca)
+in
+{
+    //printf("in _d_switch_ustring()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        size_t len1 = table[j - 1].length;
+        size_t len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int c;
+
+            c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof);
+            assert(c < 0);  // c==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int c;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
+                assert(c != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
+                if (c == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_ustring()\n");
+    size_t low;
+    size_t high;
+    size_t mid;
+    ptrdiff_t c;
+    wchar[] pca;
+
+    low = 0;
+    high = table.length;
+
+/*
+    // Print table
+    wprintf("ca[] = '%.*s'\n", ca);
+    for (mid = 0; mid < high; mid++)
+    {
+        pca = table[mid];
+        wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+    }
+*/
+
+    // Do binary search
+    while (low < high)
+    {
+        mid = (low + high) >> 1;
+        pca = table[mid];
+        c = cast(ptrdiff_t)(ca.length - pca.length);
+        if (c == 0)
+        {
+            c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof);
+            if (c == 0)
+            {   //printf("found %d\n", mid);
+                return cast(int)mid;
+            }
+        }
+        if (c < 0)
+        {
+            high = mid;
+        }
+        else
+        {
+            low = mid + 1;
+        }
+    }
+    //printf("not found\n");
+    return -1;              // not found
+}
+
+
+unittest
+{
+    switch (cast(wchar []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
+
+
+/**********************************
+ * Same thing, but for wide chars.
+ */
+
+int _d_switch_dstring(dchar[][] table, dchar[] ca)
+in
+{
+    //printf("in _d_switch_dstring()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        size_t len1 = table[j - 1].length;
+        size_t len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int c;
+
+            c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof);
+            assert(c < 0);  // c==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int c;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
+                assert(c != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
+                if (c == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_ustring()\n");
+    size_t low;
+    size_t high;
+    size_t mid;
+    ptrdiff_t c;
+    dchar[] pca;
+
+    low = 0;
+    high = table.length;
+
+/*
+    // Print table
+    wprintf("ca[] = '%.*s'\n", ca);
+    for (mid = 0; mid < high; mid++)
+    {
+        pca = table[mid];
+        wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+    }
+*/
+
+    // Do binary search
+    while (low < high)
+    {
+        mid = (low + high) >> 1;
+        pca = table[mid];
+        c = cast(ptrdiff_t)(ca.length - pca.length);
+        if (c == 0)
+        {
+            c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof);
+            if (c == 0)
+            {   //printf("found %d\n", mid);
+                return cast(int)mid;
+            }
+        }
+        if (c < 0)
+        {
+            high = mid;
+        }
+        else
+        {
+            low = mid + 1;
+        }
+    }
+    //printf("not found\n");
+    return -1; // not found
+}
+
+
+unittest
+{
+    switch (cast(dchar []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_AC.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,95 @@
+module rt.typeinfo.ti_AC;
+
+// Object[]
+
+class TypeInfo_AC : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {   Object[] s = *cast(Object[]*)p;
+        hash_t hash = 0;
+
+        foreach (Object o; s)
+        {
+            if (o)
+                hash += o.toHash();
+        }
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Object[] s1 = *cast(Object[]*)p1;
+        Object[] s2 = *cast(Object[]*)p2;
+
+        if (s1.length == s2.length)
+        {
+            for (size_t u = 0; u < s1.length; u++)
+            {   Object o1 = s1[u];
+                Object o2 = s2[u];
+
+                // Do not pass null's to Object.opEquals()
+                if (o1 is o2 ||
+                    (!(o1 is null) && !(o2 is null) && o1.opEquals(o2)))
+                    continue;
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object[] s1 = *cast(Object[]*)p1;
+        Object[] s2 = *cast(Object[]*)p2;
+        ptrdiff_t c;
+
+        c = cast(ptrdiff_t)s1.length - cast(ptrdiff_t)s2.length;
+        if (c == 0)
+        {
+            for (size_t u = 0; u < s1.length; u++)
+            {   Object o1 = s1[u];
+                Object o2 = s2[u];
+
+                if (o1 is o2)
+                    continue;
+
+                // Regard null references as always being "less than"
+                if (o1)
+                {
+                    if (!o2)
+                    {   c = 1;
+                        break;
+                    }
+                    c = o1.opCmp(o2);
+                    if (c)
+                        break;
+                }
+                else
+                {   c = -1;
+                    break;
+                }
+            }
+        }
+        if (c < 0)
+            c = -1;
+        else if (c > 0)
+            c = 1;
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return (Object[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(Object);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Acdouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,105 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Acdouble;
+
+private import typeinfo.ti_cdouble;
+
+// cdouble[]
+
+class TypeInfo_Ar : TypeInfo
+{
+    override string toString() { return "cdouble[]"; }
+
+    override hash_t getHash(in void* p)
+    {   cdouble[] s = *cast(cdouble[]*)p;
+        size_t len = s.length;
+        cdouble *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(uint *)str)[2];
+            hash += (cast(uint *)str)[3];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        cdouble[] s1 = *cast(cdouble[]*)p1;
+        cdouble[] s2 = *cast(cdouble[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_r._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        cdouble[] s1 = *cast(cdouble[]*)p1;
+        cdouble[] s2 = *cast(cdouble[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_r._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (cdouble[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(cdouble);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Acfloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Acfloat;
+
+private import typeinfo.ti_cfloat;
+
+// cfloat[]
+
+class TypeInfo_Aq : TypeInfo
+{
+    override string toString() { return "cfloat[]"; }
+
+    override hash_t getHash(in void* p)
+    {   cfloat[] s = *cast(cfloat[]*)p;
+        size_t len = s.length;
+        cfloat *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        cfloat[] s1 = *cast(cfloat[]*)p1;
+        cfloat[] s2 = *cast(cfloat[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_q._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        cfloat[] s1 = *cast(cfloat[]*)p1;
+        cfloat[] s2 = *cast(cfloat[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_q._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (cfloat[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(cfloat);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Acreal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,106 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Acreal;
+
+private import typeinfo.ti_creal;
+
+// creal[]
+
+class TypeInfo_Ac : TypeInfo
+{
+    override string toString() { return "creal[]"; }
+
+    override hash_t getHash(in void* p)
+    {   creal[] s = *cast(creal[]*)p;
+        size_t len = s.length;
+        creal *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(uint *)str)[2];
+            hash += (cast(uint *)str)[3];
+            hash += (cast(uint *)str)[4];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        creal[] s1 = *cast(creal[]*)p1;
+        creal[] s2 = *cast(creal[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_c._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        creal[] s1 = *cast(creal[]*)p1;
+        creal[] s2 = *cast(creal[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_c._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (creal[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(creal);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Adouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Adouble;
+
+private import typeinfo.ti_double;
+
+// double[]
+
+class TypeInfo_Ad : TypeInfo
+{
+    override string toString() { return "double[]"; }
+
+    override hash_t getHash(in void* p)
+    {   double[] s = *cast(double[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        double[] s1 = *cast(double[]*)p1;
+        double[] s2 = *cast(double[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_d._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        double[] s1 = *cast(double[]*)p1;
+        double[] s2 = *cast(double[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_d._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (double[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(double);
+    }
+}
+
+// idouble[]
+
+class TypeInfo_Ap : TypeInfo_Ad
+{
+    override string toString() { return "idouble[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(idouble);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Afloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,114 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Afloat;
+
+private import typeinfo.ti_float;
+
+// float[]
+
+class TypeInfo_Af : TypeInfo
+{
+    override string toString() { return "float[]"; }
+
+    override hash_t getHash(in void* p)
+    {   float[] s = *cast(float[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str;
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        float[] s1 = *cast(float[]*)p1;
+        float[] s2 = *cast(float[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_f._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        float[] s1 = *cast(float[]*)p1;
+        float[] s2 = *cast(float[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_f._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (float[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(float);
+    }
+}
+
+// ifloat[]
+
+class TypeInfo_Ao : TypeInfo_Af
+{
+    override string toString() { return "ifloat[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(ifloat);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Ag.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,204 @@
+
+module rt.typeinfo.ti_Ag;
+
+private import util.string;
+private import stdc.string;
+
+// byte[]
+
+class TypeInfo_Ag : TypeInfo
+{
+    override string toString() { return "byte[]"; }
+
+    override hash_t getHash(in void* p)
+    {   byte[] s = *cast(byte[]*)p;
+        size_t len = s.length;
+        byte *str = s.ptr;
+        hash_t hash = 0;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ubyte *)str;
+                    return hash;
+
+                case 2:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                case 3:
+                    hash *= 9;
+                    hash += (*cast(ushort *)str << 8) +
+                            (cast(ubyte *)str)[2];
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 4;
+                    len -= 4;
+                    break;
+            }
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        byte[] s1 = *cast(byte[]*)p1;
+        byte[] s2 = *cast(byte[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(byte *)s1, cast(byte *)s2, s1.length) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        byte[] s1 = *cast(byte[]*)p1;
+        byte[] s2 = *cast(byte[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (byte[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(byte);
+    }
+}
+
+
+// ubyte[]
+
+class TypeInfo_Ah : TypeInfo_Ag
+{
+    override string toString() { return "ubyte[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        char[] s1 = *cast(char[]*)p1;
+        char[] s2 = *cast(char[]*)p2;
+
+        return dstrcmp(s1, s2);
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ubyte);
+    }
+}
+
+// void[]
+
+class TypeInfo_Av : TypeInfo_Ah
+{
+    override string toString() { return "void[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(void);
+    }
+}
+
+// bool[]
+
+class TypeInfo_Ab : TypeInfo_Ah
+{
+    override string toString() { return "bool[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(bool);
+    }
+}
+
+// char[]
+
+class TypeInfo_Aa : TypeInfo_Ag
+{
+    override string toString() { return "char[]"; }
+
+    override hash_t getHash(in void* p)
+    {   char[] s = *cast(char[]*)p;
+        hash_t hash = 0;
+
+version (all)
+{
+        foreach (char c; s)
+            hash = hash * 11 + c;
+}
+else
+{
+        size_t len = s.length;
+        char *str = s;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ubyte *)str;
+                    return hash;
+
+                case 2:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                case 3:
+                    hash *= 9;
+                    hash += (*cast(ushort *)str << 8) +
+                            (cast(ubyte *)str)[2];
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 4;
+                    len -= 4;
+                    break;
+            }
+        }
+}
+        return hash;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(char);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Aint.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,129 @@
+
+module rt.typeinfo.ti_Aint;
+
+private import stdc.string;
+
+// int[]
+
+class TypeInfo_Ai : TypeInfo
+{
+    override string toString() { return "int[]"; }
+
+    override hash_t getHash(in void* p)
+    {   int[] s = *cast(int[]*)p;
+        auto len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str;
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        int[] s1 = *cast(int[]*)p1;
+        int[] s2 = *cast(int[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * int.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        int[] s1 = *cast(int[]*)p1;
+        int[] s2 = *cast(int[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (int[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(int);
+    }
+}
+
+unittest
+{
+    int[][] a = [[5,3,8,7], [2,5,3,8,7]];
+    a.sort;
+    assert(a == [[2,5,3,8,7], [5,3,8,7]]);
+
+    a = [[5,3,8,7], [5,3,8]];
+    a.sort;
+    assert(a == [[5,3,8], [5,3,8,7]]);
+}
+
+// uint[]
+
+class TypeInfo_Ak : TypeInfo_Ai
+{
+    override string toString() { return "uint[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        uint[] s1 = *cast(uint[]*)p1;
+        uint[] s2 = *cast(uint[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(uint);
+    }
+}
+
+// dchar[]
+
+class TypeInfo_Aw : TypeInfo_Ak
+{
+    override string toString() { return "dchar[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(dchar);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Along.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,109 @@
+
+module rt.typeinfo.ti_Along;
+
+private import stdc.string;
+
+// long[]
+
+class TypeInfo_Al : TypeInfo
+{
+    override string toString() { return "long[]"; }
+
+    override hash_t getHash(in void* p)
+    {   long[] s = *cast(long[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str + *(cast(uint *)str + 1);
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        long[] s1 = *cast(long[]*)p1;
+        long[] s2 = *cast(long[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * long.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        long[] s1 = *cast(long[]*)p1;
+        long[] s2 = *cast(long[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (s1[u] < s2[u])
+                return -1;
+            else if (s1[u] > s2[u])
+                return 1;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (long[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(long);
+    }
+}
+
+
+// ulong[]
+
+class TypeInfo_Am : TypeInfo_Al
+{
+    override string toString() { return "ulong[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        ulong[] s1 = *cast(ulong[]*)p1;
+        ulong[] s2 = *cast(ulong[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (s1[u] < s2[u])
+                return -1;
+            else if (s1[u] > s2[u])
+                return 1;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ulong);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Areal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,116 @@
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_Areal;
+
+private import typeinfo.ti_real;
+
+// real[]
+
+class TypeInfo_Ae : TypeInfo
+{
+    override string toString() { return "real[]"; }
+
+    override hash_t getHash(in void* p)
+    {   real[] s = *cast(real[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(ushort *)str)[4];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        real[] s1 = *cast(real[]*)p1;
+        real[] s2 = *cast(real[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_e._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        real[] s1 = *cast(real[]*)p1;
+        real[] s2 = *cast(real[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_e._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (real[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(real);
+    }
+}
+
+// ireal[]
+
+class TypeInfo_Aj : TypeInfo_Ae
+{
+    override string toString() { return "ireal[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(ireal);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_Ashort.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,132 @@
+
+module rt.typeinfo.ti_Ashort;
+
+private import stdc.string;
+
+// short[]
+
+class TypeInfo_As : TypeInfo
+{
+    override string toString() { return "short[]"; }
+
+    override hash_t getHash(in void* p)
+    {   short[] s = *cast(short[]*)p;
+        size_t len = s.length;
+        short *str = s.ptr;
+        hash_t hash = 0;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 2;
+                    len -= 2;
+                    break;
+            }
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        short[] s1 = *cast(short[]*)p1;
+        short[] s2 = *cast(short[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * short.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        short[] s1 = *cast(short[]*)p1;
+        short[] s2 = *cast(short[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (short[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(short);
+    }
+}
+
+
+// ushort[]
+
+class TypeInfo_At : TypeInfo_As
+{
+    override string toString() { return "ushort[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        ushort[] s1 = *cast(ushort[]*)p1;
+        ushort[] s2 = *cast(ushort[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ushort);
+    }
+}
+
+// wchar[]
+
+class TypeInfo_Au : TypeInfo_At
+{
+    override string toString() { return "wchar[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(wchar);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_C.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module rt.typeinfo.ti_C;
+
+// Object
+
+class TypeInfo_C : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {
+        Object o = *cast(Object*)p;
+        return o ? o.toHash() : 0;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+
+        return o1 == o2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (!(o1 is o2))
+        {
+            if (o1)
+            {   if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_byte.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,38 @@
+
+// byte
+
+module rt.typeinfo.ti_byte;
+
+class TypeInfo_g : TypeInfo
+{
+    override string toString() { return "byte"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(byte *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return byte.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        byte t;
+
+        t = *cast(byte *)p1;
+        *cast(byte *)p1 = *cast(byte *)p2;
+        *cast(byte *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_cdouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,66 @@
+
+// cdouble
+
+module rt.typeinfo.ti_cdouble;
+
+class TypeInfo_r : TypeInfo
+{
+    override string toString() { return "cdouble"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+               (cast(uint *)p)[2] + (cast(uint *)p)[3];
+    }
+
+    static equals_t _equals(cdouble f1, cdouble f2)
+    {
+        return f1 == f2;
+    }
+
+    static int _compare(cdouble f1, cdouble f2)
+    {   int result;
+
+        if (f1.re < f2.re)
+            result = -1;
+        else if (f1.re > f2.re)
+            result = 1;
+        else if (f1.im < f2.im)
+            result = -1;
+        else if (f1.im > f2.im)
+            result = 1;
+        else
+            result = 0;
+        return result;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return cdouble.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        cdouble t;
+
+        t = *cast(cdouble *)p1;
+        *cast(cdouble *)p1 = *cast(cdouble *)p2;
+        *cast(cdouble *)p2 = t;
+    }
+
+    override void[] init()
+    {   static cdouble r;
+
+        return (cast(cdouble *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_cfloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,65 @@
+
+// cfloat
+
+module rt.typeinfo.ti_cfloat;
+
+class TypeInfo_q : TypeInfo
+{
+    override string toString() { return "cfloat"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static equals_t _equals(cfloat f1, cfloat f2)
+    {
+        return f1 == f2;
+    }
+
+    static int _compare(cfloat f1, cfloat f2)
+    {   int result;
+
+        if (f1.re < f2.re)
+            result = -1;
+        else if (f1.re > f2.re)
+            result = 1;
+        else if (f1.im < f2.im)
+            result = -1;
+        else if (f1.im > f2.im)
+            result = 1;
+        else
+            result = 0;
+        return result;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return cfloat.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        cfloat t;
+
+        t = *cast(cfloat *)p1;
+        *cast(cfloat *)p1 = *cast(cfloat *)p2;
+        *cast(cfloat *)p2 = t;
+    }
+
+    override void[] init()
+    {   static cfloat r;
+
+        return (cast(cfloat *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_char.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+module rt.typeinfo.ti_char;
+
+class TypeInfo_a : TypeInfo
+{
+    override string toString() { return "char"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(char *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(char *)p1 == *cast(char *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(char *)p1 - *cast(char *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return char.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        char t;
+
+        t = *cast(char *)p1;
+        *cast(char *)p1 = *cast(char *)p2;
+        *cast(char *)p2 = t;
+    }
+
+    override void[] init()
+    {   static char c;
+
+        return (cast(char *)&c)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_creal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,67 @@
+
+// creal
+
+module rt.typeinfo.ti_creal;
+
+class TypeInfo_c : TypeInfo
+{
+    override string toString() { return "creal"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+               (cast(uint *)p)[2] + (cast(uint *)p)[3] +
+               (cast(uint *)p)[4];
+    }
+
+    static equals_t _equals(creal f1, creal f2)
+    {
+        return f1 == f2;
+    }
+
+    static int _compare(creal f1, creal f2)
+    {   int result;
+
+        if (f1.re < f2.re)
+            result = -1;
+        else if (f1.re > f2.re)
+            result = 1;
+        else if (f1.im < f2.im)
+            result = -1;
+        else if (f1.im > f2.im)
+            result = 1;
+        else
+            result = 0;
+        return result;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return creal.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        creal t;
+
+        t = *cast(creal *)p1;
+        *cast(creal *)p1 = *cast(creal *)p2;
+        *cast(creal *)p2 = t;
+    }
+
+    override void[] init()
+    {   static creal r;
+
+        return (cast(creal *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_dchar.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,44 @@
+
+// dchar
+
+module rt.typeinfo.ti_dchar;
+
+class TypeInfo_w : TypeInfo
+{
+    override string toString() { return "dchar"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(dchar *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(dchar *)p1 == *cast(dchar *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(dchar *)p1 - *cast(dchar *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return dchar.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        dchar t;
+
+        t = *cast(dchar *)p1;
+        *cast(dchar *)p1 = *cast(dchar *)p2;
+        *cast(dchar *)p2 = t;
+    }
+
+    override void[] init()
+    {   static dchar c;
+
+        return (cast(dchar *)&c)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_delegate.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,39 @@
+
+// delegate
+
+module rt.typeinfo.ti_delegate;
+
+alias void delegate(int) dg;
+
+class TypeInfo_D : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {   long l = *cast(long *)p;
+
+        return cast(uint)(l + (l >> 32));
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(dg *)p1 == *cast(dg *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return dg.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        dg t;
+
+        t = *cast(dg *)p1;
+        *cast(dg *)p1 = *cast(dg *)p2;
+        *cast(dg *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_double.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,64 @@
+
+// double
+
+module rt.typeinfo.ti_double;
+
+class TypeInfo_d : TypeInfo
+{
+    override string toString() { return "double"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static equals_t _equals(double f1, double f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(double d1, double d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(double *)p1, *cast(double *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(double *)p1, *cast(double *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return double.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        double t;
+
+        t = *cast(double *)p1;
+        *cast(double *)p1 = *cast(double *)p2;
+        *cast(double *)p2 = t;
+    }
+
+    override void[] init()
+    {   static double r;
+
+        return (cast(double *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_float.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,64 @@
+
+// float
+
+module rt.typeinfo.ti_float;
+
+class TypeInfo_f : TypeInfo
+{
+    override string toString() { return "float"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    static equals_t _equals(float f1, float f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(float d1, float d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(float *)p1, *cast(float *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(float *)p1, *cast(float *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return float.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        float t;
+
+        t = *cast(float *)p1;
+        *cast(float *)p1 = *cast(float *)p2;
+        *cast(float *)p2 = t;
+    }
+
+    override void[] init()
+    {   static float r;
+
+        return (cast(float *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_idouble.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,11 @@
+
+// idouble
+
+module rt.typeinfo.ti_idouble;
+
+private import typeinfo.ti_double;
+
+class TypeInfo_p : TypeInfo_d
+{
+    override string toString() { return "idouble"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_ifloat.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,11 @@
+
+// ifloat
+
+module rt.typeinfo.ti_ifloat;
+
+private import typeinfo.ti_float;
+
+class TypeInfo_o : TypeInfo_f
+{
+    override string toString() { return "ifloat"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_int.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+// int
+
+module rt.typeinfo.ti_int;
+
+class TypeInfo_i : TypeInfo
+{
+    override string toString() { return "int"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(int*) p1 < *cast(int*) p2)
+            return -1;
+        else if (*cast(int*) p1 > *cast(int*) p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return int.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        int t;
+
+        t = *cast(int *)p1;
+        *cast(int *)p1 = *cast(int *)p2;
+        *cast(int *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_ireal.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,11 @@
+
+// ireal
+
+module rt.typeinfo.ti_ireal;
+
+private import typeinfo.ti_real;
+
+class TypeInfo_j : TypeInfo_e
+{
+    override string toString() { return "ireal"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_long.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+// long
+
+module rt.typeinfo.ti_long;
+
+class TypeInfo_l : TypeInfo
+{
+    override string toString() { return "long"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p + (cast(uint *)p)[1];
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(long *)p1 == *cast(long *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(long *)p1 < *cast(long *)p2)
+            return -1;
+        else if (*cast(long *)p1 > *cast(long *)p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return long.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        long t;
+
+        t = *cast(long *)p1;
+        *cast(long *)p1 = *cast(long *)p2;
+        *cast(long *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_ptr.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,46 @@
+
+// pointer
+
+module rt.typeinfo.ti_ptr;
+
+class TypeInfo_P : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {
+        return cast(uint)*cast(void* *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(void* *)p1 == *cast(void* *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        auto c = *cast(void* *)p1 - *cast(void* *)p2;
+        if (c < 0)
+            return -1;
+        else if (c > 0)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (void*).sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        void* t;
+
+        t = *cast(void* *)p1;
+        *cast(void* *)p1 = *cast(void* *)p2;
+        *cast(void* *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_real.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,64 @@
+
+// real
+
+module rt.typeinfo.ti_real;
+
+class TypeInfo_e : TypeInfo
+{
+    override string toString() { return "real"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] + (cast(ushort *)p)[4];
+    }
+
+    static equals_t _equals(real f1, real f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(real d1, real d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(real *)p1, *cast(real *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(real *)p1, *cast(real *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return real.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        real t;
+
+        t = *cast(real *)p1;
+        *cast(real *)p1 = *cast(real *)p2;
+        *cast(real *)p2 = t;
+    }
+
+    override void[] init()
+    {   static real r;
+
+        return (cast(real *)&r)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_short.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,38 @@
+
+// short
+
+module rt.typeinfo.ti_short;
+
+class TypeInfo_s : TypeInfo
+{
+    override string toString() { return "short"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(short *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(short *)p1 == *cast(short *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(short *)p1 - *cast(short *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return short.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        short t;
+
+        t = *cast(short *)p1;
+        *cast(short *)p1 = *cast(short *)p2;
+        *cast(short *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_ubyte.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,43 @@
+
+// ubyte
+
+module rt.typeinfo.ti_ubyte;
+
+class TypeInfo_h : TypeInfo
+{
+    override string toString() { return "ubyte"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(ubyte *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ubyte *)p1 == *cast(ubyte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(ubyte *)p1 - *cast(ubyte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return ubyte.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ubyte t;
+
+        t = *cast(ubyte *)p1;
+        *cast(ubyte *)p1 = *cast(ubyte *)p2;
+        *cast(ubyte *)p2 = t;
+    }
+}
+
+class TypeInfo_b : TypeInfo_h
+{
+    override string toString() { return "bool"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_uint.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+// uint
+
+module rt.typeinfo.ti_uint;
+
+class TypeInfo_k : TypeInfo
+{
+    override string toString() { return "uint"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(uint*) p1 < *cast(uint*) p2)
+            return -1;
+        else if (*cast(uint*) p1 > *cast(uint*) p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return uint.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        int t;
+
+        t = *cast(uint *)p1;
+        *cast(uint *)p1 = *cast(uint *)p2;
+        *cast(uint *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_ulong.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,42 @@
+
+// ulong
+
+module rt.typeinfo.ti_ulong;
+
+class TypeInfo_m : TypeInfo
+{
+    override string toString() { return "ulong"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p + (cast(uint *)p)[1];
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ulong *)p1 == *cast(ulong *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(ulong *)p1 < *cast(ulong *)p2)
+            return -1;
+        else if (*cast(ulong *)p1 > *cast(ulong *)p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return ulong.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ulong t;
+
+        t = *cast(ulong *)p1;
+        *cast(ulong *)p1 = *cast(ulong *)p2;
+        *cast(ulong *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_ushort.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,38 @@
+
+// ushort
+
+module rt.typeinfo.ti_ushort;
+
+class TypeInfo_t : TypeInfo
+{
+    override string toString() { return "ushort"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(ushort *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ushort *)p1 == *cast(ushort *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(ushort *)p1 - *cast(ushort *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return ushort.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ushort t;
+
+        t = *cast(ushort *)p1;
+        *cast(ushort *)p1 = *cast(ushort *)p2;
+        *cast(ushort *)p2 = t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_void.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,43 @@
+
+// void
+
+module rt.typeinfo.ti_void;
+
+class TypeInfo_v : TypeInfo
+{
+    override string toString() { return "void"; }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(0);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return void.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        byte t;
+
+        t = *cast(byte *)p1;
+        *cast(byte *)p1 = *cast(byte *)p2;
+        *cast(byte *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/typeinfo/ti_wchar.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,43 @@
+
+module rt.typeinfo.ti_wchar;
+
+
+class TypeInfo_u : TypeInfo
+{
+    override string toString() { return "wchar"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(wchar *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(wchar *)p1 == *cast(wchar *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(wchar *)p1 - *cast(wchar *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return wchar.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        wchar t;
+
+        t = *cast(wchar *)p1;
+        *cast(wchar *)p1 = *cast(wchar *)p2;
+        *cast(wchar *)p2 = t;
+    }
+
+    override void[] init()
+    {   static wchar c;
+
+        return (cast(wchar *)&c)[0 .. 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/util/console.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,49 @@
+/**
+ * The console module contains some simple routines for console output.
+ *
+ * Copyright: Public Domain
+ * License:   Public Domain
+ * Authors:   Sean Kelly
+ */
+module rt.util.console;
+
+
+private
+{
+    version (Windows)
+    {
+        import sys.windows.windows;
+    }
+    else version( Posix )
+    {
+        import stdc.posix.unistd;
+    }
+    import util.string;
+}
+
+
+struct Console
+{
+    Console opCall( in char[] val )
+    {
+        version( Windows )
+        {
+            uint count = void;
+            WriteFile( GetStdHandle( 0xfffffff5 ), val.ptr, val.length, &count, null );
+        }
+        else version( Posix )
+        {
+            write( 2, val.ptr, val.length );
+        }
+        return *this;
+    }
+
+
+    Console opCall( uint val )
+    {
+            char[10] tmp = void;
+            return opCall( tmp.intToString( val ) );
+    }
+}
+
+Console console;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/util/ctype.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,106 @@
+
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+// Simple ASCII char classification functions
+
+module rt.util.ctype;
+
+int isalnum(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG) : 0; }
+int isalpha(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP)      : 0; }
+int iscntrl(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_CTL)      : 0; }
+int isdigit(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_DIG)      : 0; }
+int islower(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_LC)       : 0; }
+int ispunct(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_PNC)      : 0; }
+int isspace(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_SPC)      : 0; }
+int isupper(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_UC)       : 0; }
+int isxdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_HEX)      : 0; }
+int isgraph(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC) : 0; }
+int isprint(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC|_BLK) : 0; }
+int isascii(dchar c)  { return c <= 0x7F; }
+
+dchar tolower(dchar c)
+    out (result)
+    {
+	assert(!isupper(result));
+    }
+    body
+    {
+	return isupper(c) ? c + (cast(dchar)'a' - 'A') : c;
+    }
+
+dchar toupper(dchar c)
+    out (result)
+    {
+	assert(!islower(result));
+    }
+    body
+    {
+	return islower(c) ? c - (cast(dchar)'a' - 'A') : c;
+    }
+
+private:
+
+enum
+{
+    _SPC =	8,
+    _CTL =	0x20,
+    _BLK =	0x40,
+    _HEX =	0x80,
+    _UC  =	1,
+    _LC  =	2,
+    _PNC =	0x10,
+    _DIG =	4,
+    _ALP =	_UC|_LC,
+}
+
+ubyte _ctype[128] =
+[
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL,
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
+	_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
+	_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC,
+	_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
+	_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
+	_UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC,
+	_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
+	_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
+	_LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL
+];
+
+
+unittest
+{
+    assert(isspace(' '));
+    assert(!isspace('z'));
+    assert(toupper('a') == 'A');
+    assert(tolower('Q') == 'q');
+    assert(!isxdigit('G'));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/util/string.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,35 @@
+/**
+ * The exception module defines all system-level exceptions and provides a
+ * mechanism to alter system-level error handling.
+ *
+ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
+ * License:   BSD Style, see LICENSE
+ * Authors:   Sean Kelly
+ */
+module rt.util.string;
+
+private import stdc.string;
+
+char[] intToString( char[] buf, uint val )
+{
+    assert( buf.length > 9 );
+    auto p = buf.ptr + buf.length;
+
+    do
+    {
+        *--p = cast(char)(val % 10 + '0');
+    } while( val /= 10 );
+
+    return buf[p - buf.ptr .. $];
+}
+
+
+int dstrcmp( in char[] s1, in char[] s2 )
+{
+    auto len = s1.length;
+    if( s2.length < len )
+        len = s2.length;
+    if( memcmp( s1.ptr, s2.ptr, len ) == 0 )
+        return 0;
+    return s1.length > s2.length ? 1 : -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/compiler/ldc/util/utf.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,917 @@
+// Written in the D programming language
+
+/*
+ *  Copyright (C) 2003-2004 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/********************************************
+ * Encode and decode UTF-8, UTF-16 and UTF-32 strings.
+ *
+ * For Win32 systems, the C wchar_t type is UTF-16 and corresponds to the D
+ * wchar type.
+ * For linux systems, the C wchar_t type is UTF-32 and corresponds to
+ * the D utf.dchar type.
+ *
+ * UTF character support is restricted to (\u0000 &lt;= character &lt;= \U0010FFFF).
+ *
+ * See_Also:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)<br>
+ *	$(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)<br>
+ *	$(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335)
+ * Macros:
+ *	WIKI = Phobos/StdUtf
+ */
+
+module rt.util.utf;
+
+
+extern (C) void onUnicodeError( string msg, size_t idx );
+
+/*******************************
+ * Test if c is a valid UTF-32 character.
+ *
+ * \uFFFE and \uFFFF are considered valid by this function,
+ * as they are permitted for internal use by an application,
+ * but they are not allowed for interchange by the Unicode standard.
+ *
+ * Returns: true if it is, false if not.
+ */
+
+bool isValidDchar(dchar c)
+{
+    /* Note: FFFE and FFFF are specifically permitted by the
+     * Unicode standard for application internal use, but are not
+     * allowed for interchange.
+     * (thanks to Arcane Jill)
+     */
+
+    return c < 0xD800 ||
+	(c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/);
+}
+
+unittest
+{
+    debug(utf) printf("utf.isValidDchar.unittest\n");
+    assert(isValidDchar(cast(dchar)'a') == true);
+    assert(isValidDchar(cast(dchar)0x1FFFFF) == false);
+}
+
+
+
+auto UTF8stride =
+[
+    cast(ubyte)
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+    4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF,
+];
+
+/**
+ * stride() returns the length of a UTF-8 sequence starting at index i
+ * in string s.
+ * Returns:
+ *	The number of bytes in the UTF-8 sequence or
+ *	0xFF meaning s[i] is not the start of of UTF-8 sequence.
+ */
+uint stride(in char[] s, size_t i)
+{
+    return UTF8stride[s[i]];
+}
+
+/**
+ * stride() returns the length of a UTF-16 sequence starting at index i
+ * in string s.
+ */
+uint stride(in wchar[] s, size_t i)
+{   uint u = s[i];
+    return 1 + (u >= 0xD800 && u <= 0xDBFF);
+}
+
+/**
+ * stride() returns the length of a UTF-32 sequence starting at index i
+ * in string s.
+ * Returns: The return value will always be 1.
+ */
+uint stride(in dchar[] s, size_t i)
+{
+    return 1;
+}
+
+/*******************************************
+ * Given an index i into an array of characters s[],
+ * and assuming that index i is at the start of a UTF character,
+ * determine the number of UCS characters up to that index i.
+ */
+
+size_t toUCSindex(in char[] s, size_t i)
+{
+    size_t n;
+    size_t j;
+
+    for (j = 0; j < i; )
+    {
+	j += stride(s, j);
+	n++;
+    }
+    if (j > i)
+    {
+        onUnicodeError("invalid UTF-8 sequence", j);
+    }
+    return n;
+}
+
+/** ditto */
+size_t toUCSindex(in wchar[] s, size_t i)
+{
+    size_t n;
+    size_t j;
+
+    for (j = 0; j < i; )
+    {
+	j += stride(s, j);
+	n++;
+    }
+    if (j > i)
+    {
+        onUnicodeError("invalid UTF-16 sequence", j);
+    }
+    return n;
+}
+
+/** ditto */
+size_t toUCSindex(in dchar[] s, size_t i)
+{
+    return i;
+}
+
+/******************************************
+ * Given a UCS index n into an array of characters s[], return the UTF index.
+ */
+
+size_t toUTFindex(in char[] s, size_t n)
+{
+    size_t i;
+
+    while (n--)
+    {
+	uint j = UTF8stride[s[i]];
+	if (j == 0xFF)
+	    onUnicodeError("invalid UTF-8 sequence", i);
+	i += j;
+    }
+    return i;
+}
+
+/** ditto */
+size_t toUTFindex(in wchar[] s, size_t n)
+{
+    size_t i;
+
+    while (n--)
+    {	wchar u = s[i];
+
+	i += 1 + (u >= 0xD800 && u <= 0xDBFF);
+    }
+    return i;
+}
+
+/** ditto */
+size_t toUTFindex(in dchar[] s, size_t n)
+{
+    return n;
+}
+
+/* =================== Decode ======================= */
+
+/***************
+ * Decodes and returns character starting at s[idx]. idx is advanced past the
+ * decoded character. If the character is not well formed, a UtfException is
+ * thrown and idx remains unchanged.
+ */
+dchar decode(in char[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    out (result)
+    {
+	assert(isValidDchar(result));
+    }
+    body
+    {
+	size_t len = s.length;
+	dchar V;
+	size_t i = idx;
+	char u = s[i];
+
+	if (u & 0x80)
+	{   uint n;
+	    char u2;
+
+	    /* The following encodings are valid, except for the 5 and 6 byte
+	     * combinations:
+	     *	0xxxxxxx
+	     *	110xxxxx 10xxxxxx
+	     *	1110xxxx 10xxxxxx 10xxxxxx
+	     *	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     *	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     *	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     */
+	    for (n = 1; ; n++)
+	    {
+		if (n > 4)
+		    goto Lerr;		// only do the first 4 of 6 encodings
+		if (((u << n) & 0x80) == 0)
+		{
+		    if (n == 1)
+			goto Lerr;
+		    break;
+		}
+	    }
+
+	    // Pick off (7 - n) significant bits of B from first byte of octet
+	    V = cast(dchar)(u & ((1 << (7 - n)) - 1));
+
+	    if (i + (n - 1) >= len)
+		goto Lerr;			// off end of string
+
+	    /* The following combinations are overlong, and illegal:
+	     *	1100000x (10xxxxxx)
+	     *	11100000 100xxxxx (10xxxxxx)
+	     *	11110000 1000xxxx (10xxxxxx 10xxxxxx)
+	     *	11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
+	     *	11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+	     */
+	    u2 = s[i + 1];
+	    if ((u & 0xFE) == 0xC0 ||
+		(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
+		(u == 0xF0 && (u2 & 0xF0) == 0x80) ||
+		(u == 0xF8 && (u2 & 0xF8) == 0x80) ||
+		(u == 0xFC && (u2 & 0xFC) == 0x80))
+		goto Lerr;			// overlong combination
+
+	    for (uint j = 1; j != n; j++)
+	    {
+		u = s[i + j];
+		if ((u & 0xC0) != 0x80)
+		    goto Lerr;			// trailing bytes are 10xxxxxx
+		V = (V << 6) | (u & 0x3F);
+	    }
+	    if (!isValidDchar(V))
+		goto Lerr;
+	    i += n;
+	}
+	else
+	{
+	    V = cast(dchar) u;
+	    i++;
+	}
+
+	idx = i;
+	return V;
+
+      Lerr:
+      onUnicodeError("invalid UTF-8 sequence", i);
+    return V; // dummy return
+    }
+
+unittest
+{   size_t i;
+    dchar c;
+
+    debug(utf) printf("utf.decode.unittest\n");
+
+    static s1 = "abcd"c;
+    i = 0;
+    c = decode(s1, i);
+    assert(c == cast(dchar)'a');
+    assert(i == 1);
+    c = decode(s1, i);
+    assert(c == cast(dchar)'b');
+    assert(i == 2);
+
+    static s2 = "\xC2\xA9"c;
+    i = 0;
+    c = decode(s2, i);
+    assert(c == cast(dchar)'\u00A9');
+    assert(i == 2);
+
+    static s3 = "\xE2\x89\xA0"c;
+    i = 0;
+    c = decode(s3, i);
+    assert(c == cast(dchar)'\u2260');
+    assert(i == 3);
+
+    static s4 =
+    [	"\xE2\x89"c,		// too short
+	"\xC0\x8A",
+	"\xE0\x80\x8A",
+	"\xF0\x80\x80\x8A",
+	"\xF8\x80\x80\x80\x8A",
+	"\xFC\x80\x80\x80\x80\x8A",
+    ];
+
+    for (int j = 0; j < s4.length; j++)
+    {
+	try
+	{
+	    i = 0;
+	    c = decode(s4[j], i);
+	    assert(0);
+	}
+	catch (Object o)
+	{
+	    i = 23;
+	}
+	assert(i == 23);
+    }
+}
+
+/** ditto */
+
+dchar decode(in wchar[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    out (result)
+    {
+	assert(isValidDchar(result));
+    }
+    body
+    {
+	string msg;
+	dchar V;
+	size_t i = idx;
+	uint u = s[i];
+
+	if (u & ~0x7F)
+	{   if (u >= 0xD800 && u <= 0xDBFF)
+	    {   uint u2;
+
+		if (i + 1 == s.length)
+		{   msg = "surrogate UTF-16 high value past end of string";
+		    goto Lerr;
+		}
+		u2 = s[i + 1];
+		if (u2 < 0xDC00 || u2 > 0xDFFF)
+		{   msg = "surrogate UTF-16 low value out of range";
+		    goto Lerr;
+		}
+		u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
+		i += 2;
+	    }
+	    else if (u >= 0xDC00 && u <= 0xDFFF)
+	    {   msg = "unpaired surrogate UTF-16 value";
+		goto Lerr;
+	    }
+	    else if (u == 0xFFFE || u == 0xFFFF)
+	    {   msg = "illegal UTF-16 value";
+		goto Lerr;
+	    }
+	    else
+		i++;
+	}
+	else
+	{
+	    i++;
+	}
+
+	idx = i;
+	return cast(dchar)u;
+
+      Lerr:
+	  onUnicodeError(msg, i);
+	return cast(dchar)u; // dummy return
+    }
+
+/** ditto */
+
+dchar decode(in dchar[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    body
+    {
+	size_t i = idx;
+	dchar c = s[i];
+
+	if (!isValidDchar(c))
+	    goto Lerr;
+	idx = i + 1;
+	return c;
+
+      Lerr:
+	  onUnicodeError("invalid UTF-32 value", i);
+	return c; // dummy return
+    }
+
+
+/* =================== Encode ======================= */
+
+/*******************************
+ * Encodes character c and appends it to array s[].
+ */
+void encode(inout char[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	char[] r = s;
+
+	if (c <= 0x7F)
+	{
+	    r ~= cast(char) c;
+	}
+	else
+	{
+	    char[4] buf;
+	    uint L;
+
+	    if (c <= 0x7FF)
+	    {
+		buf[0] = cast(char)(0xC0 | (c >> 6));
+		buf[1] = cast(char)(0x80 | (c & 0x3F));
+		L = 2;
+	    }
+	    else if (c <= 0xFFFF)
+	    {
+		buf[0] = cast(char)(0xE0 | (c >> 12));
+		buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+		buf[2] = cast(char)(0x80 | (c & 0x3F));
+		L = 3;
+	    }
+	    else if (c <= 0x10FFFF)
+	    {
+		buf[0] = cast(char)(0xF0 | (c >> 18));
+		buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
+		buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+		buf[3] = cast(char)(0x80 | (c & 0x3F));
+		L = 4;
+	    }
+	    else
+	    {
+		assert(0);
+	    }
+	    r ~= buf[0 .. L];
+	}
+	s = r;
+    }
+
+unittest
+{
+    debug(utf) printf("utf.encode.unittest\n");
+
+    char[] s = "abcd".dup;
+    encode(s, cast(dchar)'a');
+    assert(s.length == 5);
+    assert(s == "abcda");
+
+    encode(s, cast(dchar)'\u00A9');
+    assert(s.length == 7);
+    assert(s == "abcda\xC2\xA9");
+    //assert(s == "abcda\u00A9");	// BUG: fix compiler
+
+    encode(s, cast(dchar)'\u2260');
+    assert(s.length == 10);
+    assert(s == "abcda\xC2\xA9\xE2\x89\xA0");
+}
+
+/** ditto */
+
+void encode(inout wchar[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	wchar[] r = s;
+
+	if (c <= 0xFFFF)
+	{
+	    r ~= cast(wchar) c;
+	}
+	else
+	{
+	    wchar[2] buf;
+
+	    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
+	    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
+	    r ~= buf;
+	}
+	s = r;
+    }
+
+/** ditto */
+void encode(inout dchar[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	s ~= c;
+    }
+
+/**
+Returns the code length of $(D c) in the encoding using $(D C) as a
+code point. The code is returned in character count, not in bytes.
+ */
+
+ubyte codeLength(C)(dchar c)
+{
+
+    static if (C.sizeof == 1)
+    {
+        return
+            c <= 0x7F ? 1
+            : c <= 0x7FF ? 2
+            : c <= 0xFFFF ? 3
+            : c <= 0x10FFFF ? 4
+            : (assert(false), 6);
+}
+
+    else static if (C.sizeof == 2)
+{
+	return c <= 0xFFFF ? 1 : 2;
+    }
+    else
+    {
+        static assert(C.sizeof == 4);
+        return 1;
+    }
+}
+
+/* =================== Validation ======================= */
+
+/***********************************
+Checks to see if string is well formed or not. $(D S) can be an array
+ of $(D char), $(D wchar), or $(D dchar). Throws a $(D UtfException)
+ if it is not. Use to check all untrusted input for correctness.
+ */
+void validate(S)(in S s)
+{
+    auto len = s.length;
+    for (size_t i = 0; i < len; )
+    {
+	decode(s, i);
+    }
+}
+
+/* =================== Conversion to UTF8 ======================= */
+
+char[] toUTF8(char[4] buf, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	if (c <= 0x7F)
+	{
+	    buf[0] = cast(char) c;
+	    return buf[0 .. 1];
+	}
+	else if (c <= 0x7FF)
+	{
+	    buf[0] = cast(char)(0xC0 | (c >> 6));
+	    buf[1] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 2];
+	}
+	else if (c <= 0xFFFF)
+	{
+	    buf[0] = cast(char)(0xE0 | (c >> 12));
+	    buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+	    buf[2] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 3];
+	}
+	else if (c <= 0x10FFFF)
+	{
+	    buf[0] = cast(char)(0xF0 | (c >> 18));
+	    buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
+	    buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+	    buf[3] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 4];
+	}
+	assert(0);
+    }
+
+/*******************
+ * Encodes string s into UTF-8 and returns the encoded string.
+ */
+string toUTF8(string s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/** ditto */
+string toUTF8(in wchar[] s)
+{
+    char[] r;
+    size_t i;
+    size_t slen = s.length;
+
+    r.length = slen;
+
+    for (i = 0; i < slen; i++)
+    {	wchar c = s[i];
+
+	if (c <= 0x7F)
+	    r[i] = cast(char)c;		// fast path for ascii
+	else
+	{
+	    r.length = i;
+	    foreach (dchar c; s[i .. slen])
+	    {
+		encode(r, c);
+	    }
+	    break;
+	}
+    }
+    return cast(string)r;
+}
+
+/** ditto */
+string toUTF8(in dchar[] s)
+{
+    char[] r;
+    size_t i;
+    size_t slen = s.length;
+
+    r.length = slen;
+
+    for (i = 0; i < slen; i++)
+    {	dchar c = s[i];
+
+	if (c <= 0x7F)
+	    r[i] = cast(char)c;		// fast path for ascii
+	else
+	{
+	    r.length = i;
+	    foreach (dchar d; s[i .. slen])
+	    {
+		encode(r, d);
+	    }
+	    break;
+	}
+    }
+    return cast(string)r;
+}
+
+/* =================== Conversion to UTF16 ======================= */
+
+wchar[] toUTF16(wchar[2] buf, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	if (c <= 0xFFFF)
+	{
+	    buf[0] = cast(wchar) c;
+	    return buf[0 .. 1];
+	}
+	else
+	{
+	    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
+	    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
+	    return buf[0 .. 2];
+	}
+    }
+
+/****************
+ * Encodes string s into UTF-16 and returns the encoded string.
+ * toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take
+ * an LPWSTR or LPCWSTR argument.
+ */
+wstring toUTF16(in char[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen;
+    r.length = 0;
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c <= 0x7F)
+	{
+	    i++;
+	    r ~= cast(wchar)c;
+	}
+	else
+	{
+	    c = decode(s, i);
+	    encode(r, c);
+	}
+    }
+    return cast(wstring)r;
+}
+
+alias const(wchar)* wptr;
+/** ditto */
+wptr toUTF16z(in char[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen + 1;
+    r.length = 0;
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c <= 0x7F)
+	{
+	    i++;
+	    r ~= cast(wchar)c;
+	}
+	else
+	{
+	    c = decode(s, i);
+	    encode(r, c);
+	}
+    }
+    r ~= "\000";
+    return r.ptr;
+}
+
+/** ditto */
+wstring toUTF16(wstring s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/** ditto */
+wstring toUTF16(in dchar[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen;
+    r.length = 0;
+    for (size_t i = 0; i < slen; i++)
+    {
+	encode(r, s[i]);
+    }
+    return cast(wstring)r;
+}
+
+/* =================== Conversion to UTF32 ======================= */
+
+/*****
+ * Encodes string s into UTF-32 and returns the encoded string.
+ */
+dstring toUTF32(in char[] s)
+{
+    dchar[] r;
+    size_t slen = s.length;
+    size_t j = 0;
+
+    r.length = slen;		// r[] will never be longer than s[]
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c >= 0x80)
+	    c = decode(s, i);
+	else
+	    i++;		// c is ascii, no need for decode
+	r[j++] = c;
+    }
+    return cast(dstring)r[0 .. j];
+}
+
+/** ditto */
+dstring toUTF32(in wchar[] s)
+{
+    dchar[] r;
+    size_t slen = s.length;
+    size_t j = 0;
+
+    r.length = slen;		// r[] will never be longer than s[]
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c >= 0x80)
+	    c = decode(s, i);
+	else
+	    i++;		// c is ascii, no need for decode
+	r[j++] = c;
+    }
+    return cast(dstring)r[0 .. j];
+}
+
+/** ditto */
+dstring toUTF32(dstring s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/* ================================ tests ================================== */
+
+unittest
+{
+    debug(utf) printf("utf.toUTF.unittest\n");
+
+    auto c = "hello"c;
+    auto w = toUTF16(c);
+    assert(w == "hello");
+    auto d = toUTF32(c);
+    assert(d == "hello");
+
+    c = toUTF8(w);
+    assert(c == "hello");
+    d = toUTF32(w);
+    assert(d == "hello");
+
+    c = toUTF8(d);
+    assert(c == "hello");
+    w = toUTF16(d);
+    assert(w == "hello");
+
+
+    c = "hel\u1234o";
+    w = toUTF16(c);
+    assert(w == "hel\u1234o");
+    d = toUTF32(c);
+    assert(d == "hel\u1234o");
+
+    c = toUTF8(w);
+    assert(c == "hel\u1234o");
+    d = toUTF32(w);
+    assert(d == "hel\u1234o");
+
+    c = toUTF8(d);
+    assert(c == "hel\u1234o");
+    w = toUTF16(d);
+    assert(w == "hel\u1234o");
+
+
+    c = "he\U0010AAAAllo";
+    w = toUTF16(c);
+    //foreach (wchar c; w) printf("c = x%x\n", c);
+    //foreach (wchar c; cast(wstring)"he\U0010AAAAllo") printf("c = x%x\n", c);
+    assert(w == "he\U0010AAAAllo");
+    d = toUTF32(c);
+    assert(d == "he\U0010AAAAllo");
+
+    c = toUTF8(w);
+    assert(c == "he\U0010AAAAllo");
+    d = toUTF32(w);
+    assert(d == "he\U0010AAAAllo");
+
+    c = toUTF8(d);
+    assert(c == "he\U0010AAAAllo");
+    w = toUTF16(d);
+    assert(w == "he\U0010AAAAllo");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/dmd-posix.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,78 @@
+# Makefile to build the composite D runtime library for Linux
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the runtime library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=libdruntime-dmd.a
+DUP_TARGET=libdruntime.a
+LIB_MASK=libdruntime*.a
+
+DIR_CC=common
+DIR_RT=compiler/dmd
+DIR_GC=gc/basic
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+CC=gcc
+LC=$(AR) -qsv
+DC=dmd
+
+LIB_DEST=../lib
+
+ADD_CFLAGS=-m32
+ADD_DFLAGS=
+
+targets : lib doc
+all     : lib doc
+
+######################################################
+
+ALL_OBJS=
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+lib : $(ALL_OBJS)
+	make -C $(DIR_CC) -fposix.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	make -C $(DIR_RT) -fposix.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	make -C $(DIR_GC) -fposix.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	$(RM) $(LIB_TARGET)
+	$(LC) $(LIB_TARGET) `find $(DIR_CC) -name "*.o" | xargs echo`
+	$(LC) $(LIB_TARGET) `find $(DIR_RT) -name "*.o" | xargs echo`
+	$(LC) $(LIB_TARGET) `find $(DIR_GC) -name "*.o" | xargs echo`
+	$(RM) $(DUP_TARGET)
+	$(CP) $(LIB_TARGET) $(DUP_TARGET)
+
+doc : $(ALL_DOCS)
+	make -C $(DIR_CC) -fposix.mak doc DC=$(DC)
+	make -C $(DIR_RT) -fposix.mak doc DC=$(DC)
+	make -C $(DIR_GC) -fposix.mak doc DC=$(DC)
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	make -C $(DIR_CC) -fposix.mak clean
+	make -C $(DIR_RT) -fposix.mak clean
+	make -C $(DIR_GC) -fposix.mak clean
+	$(RM) $(LIB_MASK)
+
+install :
+	make -C $(DIR_CC) -fposix.mak install
+	make -C $(DIR_RT) -fposix.mak install
+	make -C $(DIR_GC) -fposix.mak install
+	$(CP) $(LIB_MASK) $(LIB_DEST)/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/dmd-win32.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,118 @@
+# Makefile to build the composite D runtime library for Win32
+# Designed to work with DigitalMars make
+# Targets:
+#   make
+#       Same as make all
+#   make lib
+#       Build the runtime library
+#   make doc
+#       Generate documentation
+#   make clean
+#       Delete unneeded files created by build process
+
+LIB_TARGET=druntime-dmd.lib
+DUP_TARGET=druntime.lib
+LIB_MASK=druntime*.lib
+
+DIR_CC=common
+DIR_RT=compiler\dmd
+DIR_GC=gc\basic
+DIR_GC_STUB=gc\stub
+
+LIB_CC=$(DIR_CC)\druntime-core.lib
+LIB_RT=$(DIR_RT)\druntime-rt-dmd.lib
+LIB_GC=$(DIR_GC)\druntime-gc-basic.lib
+
+CP=xcopy /y
+RM=del /f
+MD=mkdir
+
+CC=dmc
+LC=lib
+DC=dmd
+
+LIB_DEST=..\lib
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+targets : lib doc
+all     : lib doc
+
+######################################################
+
+ALL_OBJS=
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+lib : $(ALL_OBJS)
+	cd $(DIR_CC)
+	make -fwin32.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	cd ..
+	cd $(DIR_RT)
+	make -fwin32.mak lib DC=$(DC)
+	cd ..\..
+	cd $(DIR_GC)
+	make -fwin32.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	cd ..\..
+	cd $(DIR_GC_STUB)
+	make -fwin32.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	cd ..\..
+	$(RM) $(LIB_TARGET)
+	$(LC) -c -n $(LIB_TARGET) $(LIB_CC) $(LIB_RT) $(LIB_GC)
+	$(RM) $(DUP_TARGET)
+	copy $(LIB_TARGET) $(DUP_TARGET)
+
+
+doc : $(ALL_DOCS)
+	cd $(DIR_CC)
+	make -fwin32.mak doc DC=$(DC)
+	cd ..
+	cd $(DIR_RT)
+	make -fwin32.mak doc DC=$(DC)
+	cd ..\..
+	cd $(DIR_GC)
+	make -fwin32.mak doc DC=$(DC)
+	cd ..\..
+	cd $(DIR_GC_STUB)
+	make -fwin32.mak doc DC=$(DC)
+	cd ..\..
+
+######################################################
+
+clean :
+	$(RM) /s *.di
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	cd $(DIR_CC)
+	make -fwin32.mak clean
+	cd ..
+	cd $(DIR_RT)
+	make -fwin32.mak clean
+	cd ..\..
+	cd $(DIR_GC)
+	make -fwin32.mak clean
+	cd ..\..
+	cd $(DIR_GC_STUB)
+	make -fwin32.mak clean
+	cd ..\..
+	$(RM) $(LIB_MASK)
+
+install :
+	cd $(DIR_CC)
+	make -fwin32.mak install
+	cd ..
+	cd $(DIR_RT)
+	make -fwin32.mak install
+	cd ..\..
+	cd $(DIR_GC)
+	make -fwin32.mak install
+	cd ..\..
+	cd $(DIR_GC_STUB)
+	make -fwin32.mak install
+	cd ..\..
+	$(CP) $(LIB_MASK) $(LIB_DEST)\.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/dmd.conf	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,2 @@
+[Environment]
+DFLAGS=-version=Posix "-I%HOME%/common" "-I%HOME%/../import"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/basic/gc.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,211 @@
+/**
+ * This module contains the garbage collector front-end.
+ *
+ * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, Sean Kelly
+ */
+
+module gc.gc;
+
+private import gcx;
+private import gcstats;
+private import stdc.stdlib;
+
+version=GCCLASS;
+
+version (GCCLASS)
+    alias GC gc_t;
+else
+    alias GC* gc_t;
+
+gc_t _gc;
+
+extern (C) void thread_init();
+
+extern (C) void gc_init()
+{
+    version (GCCLASS)
+    {   void* p;
+        ClassInfo ci = GC.classinfo;
+
+        p = malloc(ci.init.length);
+        (cast(byte*)p)[0 .. ci.init.length] = ci.init[];
+        _gc = cast(GC)p;
+    }
+    else
+    {
+        _gc = cast(GC*) calloc(1, GC.sizeof);
+    }
+    _gc.initialize();
+    // NOTE: The GC must initialize the thread library
+    //       before its first collection.
+    thread_init();
+}
+
+extern (C) void gc_term()
+{
+    // NOTE: There may be daemons threads still running when this routine is
+    //       called.  If so, cleaning memory out from under then is a good
+    //       way to make them crash horribly.  This probably doesn't matter
+    //       much since the app is supposed to be shutting down anyway, but
+    //       I'm disabling cleanup for now until I can think about it some
+    //       more.
+    //
+    // NOTE: Due to popular demand, this has been re-enabled.  It still has
+    //       the problems mentioned above though, so I guess we'll see.
+    _gc.fullCollectNoStack(); // not really a 'collect all' -- still scans
+                              // static data area, roots, and ranges.
+    _gc.Dtor();
+}
+
+extern (C) void gc_enable()
+{
+    _gc.enable();
+}
+
+extern (C) void gc_disable()
+{
+    _gc.disable();
+}
+
+extern (C) void gc_collect()
+{
+    _gc.fullCollect();
+}
+
+
+extern (C) void gc_minimize()
+{
+    _gc.minimize();
+}
+
+extern (C) uint gc_getAttr( void* p )
+{
+    return _gc.getAttr( p );
+}
+
+extern (C) uint gc_setAttr( void* p, uint a )
+{
+    return _gc.setAttr( p, a );
+}
+
+extern (C) uint gc_clrAttr( void* p, uint a )
+{
+    return _gc.clrAttr( p, a );
+}
+
+extern (C) void* gc_malloc( size_t sz, uint ba = 0 )
+{
+    return _gc.malloc( sz, ba );
+}
+
+extern (C) void* gc_calloc( size_t sz, uint ba = 0 )
+{
+    return _gc.calloc( sz, ba );
+}
+
+extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 )
+{
+    return _gc.realloc( p, sz, ba );
+}
+
+extern (C) size_t gc_extend( void* p, size_t mx, size_t sz )
+{
+    return _gc.extend( p, mx, sz );
+}
+
+extern (C) size_t gc_reserve( size_t sz )
+{
+    return _gc.reserve( sz );
+}
+
+extern (C) void gc_free( void* p )
+{
+    _gc.free( p );
+}
+
+extern (C) void* gc_addrOf( void* p )
+{
+    return _gc.addrOf( p );
+}
+
+extern (C) size_t gc_sizeOf( void* p )
+{
+    return _gc.sizeOf( p );
+}
+
+extern (C) BlkInfo gc_query( void* p )
+{
+    return _gc.query( p );
+}
+
+// NOTE: This routine is experimental.  The stats or function name may change
+//       before it is made officially available.
+extern (C) GCStats gc_stats()
+{
+    GCStats stats = void;
+    _gc.getStats( stats );
+    return stats;
+}
+
+extern (C) void gc_addRoot( void* p )
+{
+    _gc.addRoot( p );
+}
+
+extern (C) void gc_addRange( void* p, size_t sz )
+{
+    _gc.addRange( p, sz );
+}
+
+extern (C) void gc_removeRoot( void *p )
+{
+    _gc.removeRoot( p );
+}
+
+extern (C) void gc_removeRange( void *p )
+{
+    _gc.removeRange( p );
+}
+
+extern (C) void* gc_getHandle()
+{
+    return cast(void*)_gc;
+}
+
+extern (C) void gc_setHandle(void* p)
+{
+    void* oldp = gc_getHandle();
+    gc_t g = cast(gc_t)p;
+    if (g.gcversion != gcx.GCVERSION)
+        throw new Error("incompatible gc versions");
+
+    // Add our static data to the new gc
+    GC.scanStaticData(g);
+
+    _gc = g;
+}
+
+extern (C) void gc_endHandle()
+{
+    GC.unscanStaticData(_gc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/basic/gcalloc.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,215 @@
+/**
+ * This module contains allocation functions for the garbage collector.
+ *
+ * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, David Friedman, Sean Kelly
+ */
+
+module gc.gcalloc;
+
+
+version (Windows)
+{
+    private import sys.windows.windows;
+
+    alias int pthread_t;
+
+    pthread_t pthread_self()
+    {
+        return cast(pthread_t) GetCurrentThreadId();
+    }
+
+    //version = GC_Use_Alloc_Win32;
+}
+else version (Posix)
+{
+    private import stdc.posix.sys.mman;
+    private import stdc.stdlib;
+
+    //version = GC_Use_Alloc_MMap;
+}
+else
+{
+    private import stdc.stdlib;
+
+    //version = GC_Use_Alloc_Malloc;
+}
+
+/+
+static if(is(typeof(VirtualAlloc)))
+    version = GC_Use_Alloc_Win32;
+else static if (is(typeof(mmap)))
+    version = GC_Use_Alloc_MMap;
+else static if (is(typeof(valloc)))
+    version = GC_Use_Alloc_Valloc;
+else static if (is(typeof(malloc)))
+    version = GC_Use_Alloc_Malloc;
+else static assert(false, "No supported allocation methods available.");
++/
+
+static if (is(typeof(VirtualAlloc))) // version (GC_Use_Alloc_Win32)
+{
+    /**
+     * Map memory.
+     */
+    void *os_mem_map(size_t nbytes)
+    {
+        return VirtualAlloc(null, nbytes, MEM_RESERVE, PAGE_READWRITE);
+    }
+
+
+    /**
+     * Commit memory.
+     * Returns:
+     *      0       success
+     *      !=0     failure
+     */
+    int os_mem_commit(void *base, size_t offset, size_t nbytes)
+    {   void *p;
+
+        p = VirtualAlloc(base + offset, nbytes, MEM_COMMIT, PAGE_READWRITE);
+    return cast(int)(p is null);
+    }
+
+
+    /**
+     * Decommit memory.
+     * Returns:
+     *      0       success
+     *      !=0     failure
+     */
+    int os_mem_decommit(void *base, size_t offset, size_t nbytes)
+    {
+    return cast(int)(VirtualFree(base + offset, nbytes, MEM_DECOMMIT) == 0);
+    }
+
+
+    /**
+     * Unmap memory allocated with os_mem_map().
+     * Memory must have already been decommitted.
+     * Returns:
+     *      0       success
+     *      !=0     failure
+     */
+    int os_mem_unmap(void *base, size_t nbytes)
+    {
+        return cast(int)(VirtualFree(base, 0, MEM_RELEASE) == 0);
+    }
+}
+else static if (is(typeof(mmap)))  // else version (GC_Use_Alloc_MMap)
+{
+    void *os_mem_map(size_t nbytes)
+    {   void *p;
+
+        p = mmap(null, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+        return (p == MAP_FAILED) ? null : p;
+    }
+
+
+    int os_mem_commit(void *base, size_t offset, size_t nbytes)
+    {
+        return 0;
+    }
+
+
+    int os_mem_decommit(void *base, size_t offset, size_t nbytes)
+    {
+        return 0;
+    }
+
+
+    int os_mem_unmap(void *base, size_t nbytes)
+    {
+        return munmap(base, nbytes);
+    }
+}
+else static if (is(typeof(valloc))) // else version (GC_Use_Alloc_Valloc)
+{
+    void *os_mem_map(size_t nbytes)
+    {
+        return valloc(nbytes);
+    }
+
+
+    int os_mem_commit(void *base, size_t offset, size_t nbytes)
+    {
+        return 0;
+    }
+
+
+    int os_mem_decommit(void *base, size_t offset, size_t nbytes)
+    {
+        return 0;
+    }
+
+
+    int os_mem_unmap(void *base, size_t nbytes)
+    {
+        free(base);
+        return 0;
+    }
+}
+else static if (is(typeof(malloc))) // else version (GC_Use_Alloc_Malloc)
+{
+    // NOTE: This assumes malloc granularity is at least (void*).sizeof.  If
+    //       (req_size + PAGESIZE) is allocated, and the pointer is rounded up
+    //       to PAGESIZE alignment, there will be space for a void* at the end
+    //       after PAGESIZE bytes used by the GC.
+
+
+    private import gcx : PAGESIZE;
+
+
+    const size_t PAGE_MASK = PAGESIZE - 1;
+
+
+    void *os_mem_map(size_t nbytes)
+    {   byte *p, q;
+        p = cast(byte *) malloc(nbytes + PAGESIZE);
+        q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK);
+        * cast(void**)(q + nbytes) = p;
+        return q;
+    }
+
+
+    int os_mem_commit(void *base, size_t offset, size_t nbytes)
+    {
+        return 0;
+    }
+
+
+    int os_mem_decommit(void *base, size_t offset, size_t nbytes)
+    {
+        return 0;
+    }
+
+
+    int os_mem_unmap(void *base, size_t nbytes)
+    {
+        free( *cast(void**)( cast(byte*) base + nbytes ) );
+        return 0;
+    }
+}
+else
+{
+    static assert(false, "No supported allocation methods available.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/basic/gcbits.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,207 @@
+/**
+ * This module contains a specialized bitset implementation.
+ *
+ * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, David Friedman, Sean Kelly
+ */
+
+module gc.gcbits;
+
+
+private
+{
+    import core.bitmanip;
+    import stdc.string;
+    import stdc.stdlib;
+    extern (C) void onOutOfMemoryError();
+}
+
+
+version (DigitalMars)
+{
+    version = bitops;
+}
+else version (GNU)
+{
+    // use the unoptimized version
+}
+else version (D_InlineAsm_X86)
+{
+    version = Asm86;
+}
+
+struct GCBits
+{
+    const int BITS_PER_WORD = 32;
+    const int BITS_SHIFT = 5;
+    const int BITS_MASK = 31;
+
+    uint*  data = null;
+    size_t nwords = 0;    // allocated words in data[] excluding sentinals
+    size_t nbits = 0;     // number of bits in data[] excluding sentinals
+
+    void Dtor()
+    {
+        if (data)
+        {
+            free(data);
+            data = null;
+        }
+    }
+
+    invariant()
+    {
+        if (data)
+        {
+            assert(nwords * data[0].sizeof * 8 >= nbits);
+        }
+    }
+
+    void alloc(size_t nbits)
+    {
+        this.nbits = nbits;
+        nwords = (nbits + (BITS_PER_WORD - 1)) >> BITS_SHIFT;
+        data = cast(uint*)calloc(nwords + 2, uint.sizeof);
+        if (!data)
+            onOutOfMemoryError();
+    }
+
+    uint test(size_t i)
+    in
+    {
+        assert(i < nbits);
+    }
+    body
+    {
+        //return (cast(bit *)(data + 1))[i];
+        return data[1 + (i >> BITS_SHIFT)] & (1 << (i & BITS_MASK));
+    }
+
+    void set(size_t i)
+    in
+    {
+        assert(i < nbits);
+    }
+    body
+    {
+        //(cast(bit *)(data + 1))[i] = 1;
+        data[1 + (i >> BITS_SHIFT)] |= (1 << (i & BITS_MASK));
+    }
+
+    void clear(size_t i)
+    in
+    {
+        assert(i < nbits);
+    }
+    body
+    {
+        //(cast(bit *)(data + 1))[i] = 0;
+        data[1 + (i >> BITS_SHIFT)] &= ~(1 << (i & BITS_MASK));
+    }
+
+    uint testClear(size_t i)
+    {
+        version (bitops)
+        {
+            return std.intrinsic.btr(data + 1, i);
+        }
+        else version (Asm86)
+        {
+            asm
+            {
+                naked                   ;
+                mov     EAX,data[EAX]   ;
+                mov     ECX,i-4[ESP]    ;
+                btr     4[EAX],ECX      ;
+                sbb     EAX,EAX         ;
+                ret     4               ;
+            }
+        }
+        else
+        {   uint result;
+
+            //result = (cast(bit *)(data + 1))[i];
+            //(cast(bit *)(data + 1))[i] = 0;
+
+            uint* p = &data[1 + (i >> BITS_SHIFT)];
+            uint  mask = (1 << (i & BITS_MASK));
+            result = *p & mask;
+            *p &= ~mask;
+            return result;
+        }
+    }
+
+    void zero()
+    {
+        memset(data + 1, 0, nwords * uint.sizeof);
+    }
+
+    void copy(GCBits *f)
+    in
+    {
+        assert(nwords == f.nwords);
+    }
+    body
+    {
+        memcpy(data + 1, f.data + 1, nwords * uint.sizeof);
+    }
+
+    uint* base()
+    in
+    {
+        assert(data);
+    }
+    body
+    {
+        return data + 1;
+    }
+}
+
+unittest
+{
+    GCBits b;
+
+    b.alloc(786);
+    assert(b.test(123) == 0);
+    assert(b.testClear(123) == 0);
+    b.set(123);
+    assert(b.test(123) != 0);
+    assert(b.testClear(123) != 0);
+    assert(b.test(123) == 0);
+
+    b.set(785);
+    b.set(0);
+    assert(b.test(785) != 0);
+    assert(b.test(0) != 0);
+    b.zero();
+    assert(b.test(785) == 0);
+    assert(b.test(0) == 0);
+
+    GCBits b2;
+    b2.alloc(786);
+    b2.set(38);
+    b.copy(&b2);
+    assert(b.test(38) != 0);
+    b2.Dtor();
+
+    b.Dtor();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/basic/gcstats.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,40 @@
+/**
+ * This module contains garbage collector statistics functionality.
+ *
+ * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, Sean Kelly
+ */
+
+module gc.gcstats;
+
+
+/**
+ *
+ */
+struct GCStats
+{
+    size_t poolsize;        // total size of pool
+    size_t usedsize;        // bytes allocated
+    size_t freeblocks;      // number of blocks marked FREE
+    size_t freelistsize;    // total of memory on free lists
+    size_t pageblocks;      // number of blocks marked PAGE
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/basic/gcx.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,3000 @@
+/**
+ * This module contains the garbage collector implementation.
+ *
+ * Copyright: Copyright (C) 2001-2007 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ * Authors:   Walter Bright, David Friedman, Sean Kelly
+ */
+
+module gc.gcx;
+
+// D Programming Language Garbage Collector implementation
+
+/************** Debugging ***************************/
+
+//debug = PRINTF;               // turn on printf's
+//debug = COLLECT_PRINTF;       // turn on printf's
+//debug = THREADINVARIANT;      // check thread integrity
+//debug = LOGGING;              // log allocations / frees
+//debug = MEMSTOMP;             // stomp on memory
+//debug = SENTINEL;             // add underrun/overrrun protection
+//debug = PTRCHECK;             // more pointer checking
+//debug = PTRCHECK2;            // thorough but slow pointer checking
+
+/*************** Configuration *********************/
+
+version = STACKGROWSDOWN;       // growing the stack means subtracting from the stack pointer
+                                // (use for Intel X86 CPUs)
+                                // else growing the stack means adding to the stack pointer
+version = MULTI_THREADED;       // produce multithreaded version
+
+/***************************************************/
+
+private import gcbits;
+private import gcstats;
+private import gcalloc;
+
+private import cstdlib = stdc.stdlib : calloc, free, malloc, realloc;
+private import stdc.string;
+
+debug private import stdc.stdio;
+
+version (GNU)
+{
+    // BUG: The following import will likely not work, since the gcc
+    //      subdirectory is elsewhere.  Instead, perhaps the functions
+    //      could be declared directly or some other resolution could
+    //      be found.
+    private import gcc.builtins; // for __builtin_unwind_init
+}
+
+struct BlkInfo
+{
+    void*  base;
+    size_t size;
+    uint   attr;
+}
+
+private
+{
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    extern (C) void* rt_stackBottom();
+    extern (C) void* rt_stackTop();
+    extern (C) void* rt_staticDataBottom();
+    extern (C) void* rt_staticDataTop();
+
+    extern (C) void rt_finalize( void* p, bool det = true );
+
+    alias void delegate( void*, void* ) scanFn;
+
+    extern (C) void rt_scanStaticData( scanFn scan );
+
+    version (MULTI_THREADED)
+    {
+        extern (C) bool thread_needLock();
+        extern (C) void thread_suspendAll();
+        extern (C) void thread_resumeAll();
+
+        extern (C) void thread_scanAll( scanFn fn, void* curStackTop = null );
+    }
+
+    extern (C) void onOutOfMemoryError();
+
+    enum
+    {
+        OPFAIL = ~cast(size_t)0
+    }
+}
+
+
+alias GC gc_t;
+
+
+/* ======================= Leak Detector =========================== */
+
+
+debug (LOGGING)
+{
+    struct Log
+    {
+        void*  p;
+        size_t size;
+        size_t line;
+        char*  file;
+        void*  parent;
+
+        void print()
+        {
+            printf("    p = %x, size = %d, parent = %x ", p, size, parent);
+            if (file)
+            {
+                printf("%s(%u)", file, line);
+            }
+            printf("\n");
+        }
+    }
+
+
+    struct LogArray
+    {
+        size_t dim;
+        size_t allocdim;
+        Log *data;
+
+        void Dtor()
+        {
+            if (data)
+                cstdlib.free(data);
+            data = null;
+        }
+
+        void reserve(size_t nentries)
+        {
+            assert(dim <= allocdim);
+            if (allocdim - dim < nentries)
+            {
+                allocdim = (dim + nentries) * 2;
+                assert(dim + nentries <= allocdim);
+                if (!data)
+                {
+                    data = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
+                    if (!data && allocdim)
+                        onOutOfMemoryError();
+                }
+                else
+                {   Log *newdata;
+
+                    newdata = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
+                    if (!newdata && allocdim)
+                        onOutOfMemoryError();
+                    memcpy(newdata, data, dim * Log.sizeof);
+                    cstdlib.free(data);
+                    data = newdata;
+                }
+            }
+        }
+
+
+        void push(Log log)
+        {
+            reserve(1);
+            data[dim++] = log;
+        }
+
+        void remove(size_t i)
+        {
+            memmove(data + i, data + i + 1, (dim - i) * Log.sizeof);
+            dim--;
+        }
+
+
+        size_t find(void *p)
+        {
+            for (size_t i = 0; i < dim; i++)
+            {
+                if (data[i].p == p)
+                    return i;
+            }
+            return OPFAIL; // not found
+        }
+
+
+        void copy(LogArray *from)
+        {
+            reserve(from.dim - dim);
+            assert(from.dim <= allocdim);
+            memcpy(data, from.data, from.dim * Log.sizeof);
+            dim = from.dim;
+        }
+    }
+}
+
+
+/* ============================ GC =============================== */
+
+
+class GCLock { }                // just a dummy so we can get a global lock
+
+
+const uint GCVERSION = 1;       // increment every time we change interface
+                                // to GC.
+
+class GC
+{
+    // For passing to debug code
+    static size_t line;
+    static char*  file;
+
+    uint gcversion = GCVERSION;
+
+    Gcx *gcx;                   // implementation
+    static ClassInfo gcLock;    // global lock
+
+
+    void initialize()
+    {
+        gcLock = GCLock.classinfo;
+        gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof);
+        if (!gcx)
+            onOutOfMemoryError();
+        gcx.initialize();
+        setStackBottom(rt_stackBottom());
+    }
+
+
+    void Dtor()
+    {
+        version (linux)
+        {
+            //debug(PRINTF) printf("Thread %x ", pthread_self());
+            //debug(PRINTF) printf("GC.Dtor()\n");
+        }
+
+        if (gcx)
+        {
+            gcx.Dtor();
+            cstdlib.free(gcx);
+            gcx = null;
+        }
+    }
+
+
+    invariant()
+    {
+        if (gcx)
+        {
+            gcx.thread_Invariant();
+        }
+    }
+
+
+    /**
+     *
+     */
+    void enable()
+    {
+        if (!thread_needLock())
+        {
+            assert(gcx.disabled > 0);
+            gcx.disabled--;
+        }
+        else synchronized (gcLock)
+        {
+            assert(gcx.disabled > 0);
+            gcx.disabled--;
+        }
+    }
+
+
+    /**
+     *
+     */
+    void disable()
+    {
+        if (!thread_needLock())
+        {
+            gcx.disabled++;
+        }
+        else synchronized (gcLock)
+        {
+            gcx.disabled++;
+        }
+    }
+
+
+    /**
+     *
+     */
+    uint getAttr(void* p)
+    {
+        if (!p)
+        {
+            return 0;
+        }
+
+        uint go()
+        {
+            Pool* pool = gcx.findPool(p);
+            uint  oldb = 0;
+
+            if (pool)
+            {
+                auto biti = cast(size_t)(p - pool.baseAddr) / 16;
+
+                oldb = gcx.getBits(pool, biti);
+            }
+            return oldb;
+        }
+
+        if (!thread_needLock())
+        {
+            return go();
+        }
+        else synchronized (gcLock)
+        {
+            return go();
+        }
+    }
+
+
+    /**
+     *
+     */
+    uint setAttr(void* p, uint mask)
+    {
+        if (!p)
+        {
+            return 0;
+        }
+
+        uint go()
+        {
+            Pool* pool = gcx.findPool(p);
+            uint  oldb = 0;
+
+            if (pool)
+            {
+                auto biti = cast(size_t)(p - pool.baseAddr) / 16;
+
+                oldb = gcx.getBits(pool, biti);
+                gcx.setBits(pool, biti, mask);
+            }
+            return oldb;
+        }
+
+        if (!thread_needLock())
+        {
+            return go();
+        }
+        else synchronized (gcLock)
+        {
+            return go();
+        }
+    }
+
+
+    /**
+     *
+     */
+    uint clrAttr(void* p, uint mask)
+    {
+        if (!p)
+        {
+            return 0;
+        }
+
+        uint go()
+        {
+            Pool* pool = gcx.findPool(p);
+            uint  oldb = 0;
+
+            if (pool)
+            {
+                auto biti = cast(size_t)(p - pool.baseAddr) / 16;
+
+                oldb = gcx.getBits(pool, biti);
+                gcx.clrBits(pool, biti, mask);
+            }
+            return oldb;
+        }
+
+        if (!thread_needLock())
+        {
+            return go();
+        }
+        else synchronized (gcLock)
+        {
+            return go();
+        }
+    }
+
+
+    /**
+     *
+     */
+    void *malloc(size_t size, uint bits = 0)
+    {
+        if (!size)
+        {
+            return null;
+        }
+
+        if (!thread_needLock())
+        {
+            return mallocNoSync(size, bits);
+        }
+        else synchronized (gcLock)
+        {
+            return mallocNoSync(size, bits);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void *mallocNoSync(size_t size, uint bits = 0)
+    {
+        assert(size != 0);
+
+        void *p = null;
+        Bins bin;
+
+        //debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx);
+        assert(gcx);
+        //debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self());
+
+        size += SENTINEL_EXTRA;
+
+        // Compute size bin
+        // Cache previous binsize lookup - Dave Fladebo.
+        static size_t lastsize = -1;
+        static Bins lastbin;
+        if (size == lastsize)
+            bin = lastbin;
+        else
+        {
+            bin = gcx.findBin(size);
+            lastsize = size;
+            lastbin = bin;
+        }
+
+        if (bin < B_PAGE)
+        {
+            p = gcx.bucket[bin];
+            if (p is null)
+            {
+                if (!gcx.allocPage(bin) && !gcx.disabled)   // try to find a new page
+                {
+                    if (!thread_needLock())
+                    {
+                        /* Then we haven't locked it yet. Be sure
+                         * and lock for a collection, since a finalizer
+                         * may start a new thread.
+                         */
+                        synchronized (gcLock)
+                        {
+                            gcx.fullcollectshell();
+                        }
+                    }
+                    else if (!gcx.fullcollectshell())       // collect to find a new page
+                    {
+                        //gcx.newPool(1);
+                    }
+                }
+                if (!gcx.bucket[bin] && !gcx.allocPage(bin))
+                {   int result;
+
+                    gcx.newPool(1);         // allocate new pool to find a new page
+                    result = gcx.allocPage(bin);
+                    if (!result)
+                        onOutOfMemoryError();
+                }
+                p = gcx.bucket[bin];
+            }
+
+            // Return next item from free list
+            gcx.bucket[bin] = (cast(List*)p).next;
+            if( !(bits & BlkAttr.NO_SCAN) )
+                memset(p + size, 0, binsize[bin] - size);
+            //debug(PRINTF) printf("\tmalloc => %x\n", p);
+            debug (MEMSTOMP) memset(p, 0xF0, size);
+        }
+        else
+        {
+            p = gcx.bigAlloc(size);
+            if (!p)
+                onOutOfMemoryError();
+        }
+        size -= SENTINEL_EXTRA;
+        p = sentinel_add(p);
+        sentinel_init(p, size);
+        gcx.log_malloc(p, size);
+
+        if (bits)
+        {
+            Pool *pool = gcx.findPool(p);
+            assert(pool);
+
+            gcx.setBits(pool, cast(size_t)(p - pool.baseAddr) / 16, bits);
+        }
+        return p;
+    }
+
+
+    /**
+     *
+     */
+    void *calloc(size_t size, uint bits = 0)
+    {
+        if (!size)
+        {
+            return null;
+        }
+
+        if (!thread_needLock())
+        {
+            return callocNoSync(size, bits);
+        }
+        else synchronized (gcLock)
+        {
+            return callocNoSync(size, bits);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void *callocNoSync(size_t size, uint bits = 0)
+    {
+        assert(size != 0);
+
+        //debug(PRINTF) printf("calloc: %x len %d\n", p, len);
+        void *p = mallocNoSync(size, bits);
+        memset(p, 0, size);
+        return p;
+    }
+
+
+    /**
+     *
+     */
+    void *realloc(void *p, size_t size, uint bits = 0)
+    {
+        if (!thread_needLock())
+        {
+            return reallocNoSync(p, size, bits);
+        }
+        else synchronized (gcLock)
+        {
+            return reallocNoSync(p, size, bits);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void *reallocNoSync(void *p, size_t size, uint bits = 0)
+    {
+        if (!size)
+        {   if (p)
+            {   freeNoSync(p);
+                p = null;
+            }
+        }
+        else if (!p)
+        {
+            p = mallocNoSync(size, bits);
+        }
+        else
+        {   void *p2;
+            size_t psize;
+
+            //debug(PRINTF) printf("GC::realloc(p = %x, size = %u)\n", p, size);
+            version (SENTINEL)
+            {
+                sentinel_Invariant(p);
+                psize = *sentinel_size(p);
+                if (psize != size)
+                {
+                    if (psize)
+                    {
+                        Pool *pool = gcx.findPool(p);
+
+                        if (pool)
+                        {
+                            auto biti = cast(size_t)(p - pool.baseAddr) / 16;
+
+                            if (bits)
+                            {
+                                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
+                                gcx.setBits(pool, biti, bits);
+                            }
+                            else
+                            {
+                                bits = gcx.getBits(pool, biti);
+                            }
+                        }
+                    }
+                    p2 = mallocNoSync(size, bits);
+                    if (psize < size)
+                        size = psize;
+                    //debug(PRINTF) printf("\tcopying %d bytes\n",size);
+                    memcpy(p2, p, size);
+                    p = p2;
+                }
+            }
+            else
+            {
+                psize = gcx.findSize(p);        // find allocated size
+                if (psize >= PAGESIZE && size >= PAGESIZE)
+                {
+                    auto psz = psize / PAGESIZE;
+                    auto newsz = (size + PAGESIZE - 1) / PAGESIZE;
+                    if (newsz == psz)
+                        return p;
+
+                    auto pool = gcx.findPool(p);
+                    auto pagenum = (p - pool.baseAddr) / PAGESIZE;
+
+                    if (newsz < psz)
+                    {   // Shrink in place
+                        synchronized (gcLock)
+                        {
+                            debug (MEMSTOMP) memset(p + size, 0xF2, psize - size);
+                            pool.freePages(pagenum + newsz, psz - newsz);
+                        }
+                        return p;
+                    }
+                    else if (pagenum + newsz <= pool.npages)
+                    {
+                        // Attempt to expand in place
+                        synchronized (gcLock)
+                        {
+                            for (size_t i = pagenum + psz; 1;)
+                            {
+                                if (i == pagenum + newsz)
+                                {
+                                    debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize);
+                                    memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz);
+                                    return p;
+                                }
+                                if (i == pool.ncommitted)
+                                {
+                                    auto u = pool.extendPages(pagenum + newsz - pool.ncommitted);
+                                    if (u == OPFAIL)
+                                        break;
+                                    i = pagenum + newsz;
+                                    continue;
+                                }
+                                if (pool.pagetable[i] != B_FREE)
+                                    break;
+                                i++;
+                            }
+                        }
+                    }
+                }
+                if (psize < size ||             // if new size is bigger
+                    psize > size * 2)           // or less than half
+                {
+                    if (psize)
+                    {
+                        Pool *pool = gcx.findPool(p);
+
+                        if (pool)
+                        {
+                            auto biti = cast(size_t)(p - pool.baseAddr) / 16;
+
+                            if (bits)
+                            {
+                                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
+                                gcx.setBits(pool, biti, bits);
+                            }
+                            else
+                            {
+                                bits = gcx.getBits(pool, biti);
+                            }
+                        }
+                    }
+                    p2 = mallocNoSync(size, bits);
+                    if (psize < size)
+                        size = psize;
+                    //debug(PRINTF) printf("\tcopying %d bytes\n",size);
+                    memcpy(p2, p, size);
+                    p = p2;
+                }
+            }
+        }
+        return p;
+    }
+
+
+    /**
+     * Attempt to in-place enlarge the memory block pointed to by p by at least
+     * minbytes beyond its current capacity, up to a maximum of maxsize.  This
+     * does not attempt to move the memory block (like realloc() does).
+     *
+     * Returns:
+     *  0 if could not extend p,
+     *  total size of entire memory block if successful.
+     */
+    size_t extend(void* p, size_t minsize, size_t maxsize)
+    {
+        if (!thread_needLock())
+        {
+            return extendNoSync(p, minsize, maxsize);
+        }
+        else synchronized (gcLock)
+        {
+            return extendNoSync(p, minsize, maxsize);
+        }
+    }
+
+
+    //
+    //
+    //
+    private size_t extendNoSync(void* p, size_t minsize, size_t maxsize)
+    in
+    {
+        assert( minsize <= maxsize );
+    }
+    body
+    {
+        //debug(PRINTF) printf("GC::extend(p = %x, minsize = %u, maxsize = %u)\n", p, minsize, maxsize);
+        version (SENTINEL)
+        {
+            return 0;
+        }
+        auto psize = gcx.findSize(p);   // find allocated size
+        if (psize < PAGESIZE)
+            return 0;                   // cannot extend buckets
+
+        auto psz = psize / PAGESIZE;
+        auto minsz = (minsize + PAGESIZE - 1) / PAGESIZE;
+        auto maxsz = (maxsize + PAGESIZE - 1) / PAGESIZE;
+
+        auto pool = gcx.findPool(p);
+        auto pagenum = (p - pool.baseAddr) / PAGESIZE;
+
+        size_t sz;
+        for (sz = 0; sz < maxsz; sz++)
+        {
+            auto i = pagenum + psz + sz;
+            if (i == pool.ncommitted)
+                break;
+            if (pool.pagetable[i] != B_FREE)
+            {   if (sz < minsz)
+                    return 0;
+                break;
+            }
+        }
+        if (sz >= minsz)
+        {
+        }
+        else if (pagenum + psz + sz == pool.ncommitted)
+        {
+            auto u = pool.extendPages(minsz - sz);
+            if (u == OPFAIL)
+                return 0;
+            sz = minsz;
+        }
+        else
+            return 0;
+        debug (MEMSTOMP) memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize);
+        memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
+        gcx.p_cache = null;
+        gcx.size_cache = 0;
+        return (psz + sz) * PAGESIZE;
+    }
+
+
+    /**
+     *
+     */
+    size_t reserve(size_t size)
+    {
+        if (!size)
+        {
+            return 0;
+        }
+
+        if (!thread_needLock())
+        {
+            return reserveNoSync(size);
+        }
+        else synchronized (gcLock)
+        {
+            return reserveNoSync(size);
+        }
+    }
+
+
+    //
+    //
+    //
+    private size_t reserveNoSync(size_t size)
+    {
+        assert(size != 0);
+        assert(gcx);
+
+        return gcx.reserve(size);
+    }
+
+
+    /**
+     *
+     */
+    void free(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+            return freeNoSync(p);
+        }
+        else synchronized (gcLock)
+        {
+            return freeNoSync(p);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void freeNoSync(void *p)
+    {
+        assert (p);
+
+        Pool*  pool;
+        size_t pagenum;
+        Bins   bin;
+        size_t biti;
+
+        // Find which page it is in
+        pool = gcx.findPool(p);
+        if (!pool)                              // if not one of ours
+            return;                             // ignore
+        sentinel_Invariant(p);
+        p = sentinel_sub(p);
+        pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
+        biti = cast(size_t)(p - pool.baseAddr) / 16;
+        gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
+
+        bin = cast(Bins)pool.pagetable[pagenum];
+        if (bin == B_PAGE)              // if large alloc
+        {   size_t npages;
+            size_t n;
+
+            // Free pages
+            npages = 1;
+            n = pagenum;
+            while (++n < pool.ncommitted && pool.pagetable[n] == B_PAGEPLUS)
+                npages++;
+            debug (MEMSTOMP) memset(p, 0xF2, npages * PAGESIZE);
+            pool.freePages(pagenum, npages);
+        }
+        else
+        {   // Add to free list
+            List *list = cast(List*)p;
+
+            debug (MEMSTOMP) memset(p, 0xF2, binsize[bin]);
+
+            list.next = gcx.bucket[bin];
+            gcx.bucket[bin] = list;
+        }
+        gcx.log_free(sentinel_add(p));
+    }
+
+
+    /**
+     * Determine the base address of the block containing p.  If p is not a gc
+     * allocated pointer, return null.
+     */
+    void* addrOf(void *p)
+    {
+        if (!p)
+        {
+            return null;
+        }
+
+        if (!thread_needLock())
+        {
+            return addrOfNoSync(p);
+        }
+        else synchronized (gcLock)
+        {
+            return addrOfNoSync(p);
+        }
+    }
+
+
+    //
+    //
+    //
+    void* addrOfNoSync(void *p)
+    {
+        if (!p)
+        {
+            return null;
+        }
+
+        return gcx.findBase(p);
+    }
+
+
+    /**
+     * Determine the allocated size of pointer p.  If p is an interior pointer
+     * or not a gc allocated pointer, return 0.
+     */
+    size_t sizeOf(void *p)
+    {
+        if (!p)
+        {
+            return 0;
+        }
+
+        if (!thread_needLock())
+        {
+            return sizeOfNoSync(p);
+        }
+        else synchronized (gcLock)
+        {
+            return sizeOfNoSync(p);
+        }
+    }
+
+
+    //
+    //
+    //
+    private size_t sizeOfNoSync(void *p)
+    {
+        assert (p);
+
+        version (SENTINEL)
+        {
+            p = sentinel_sub(p);
+            size_t size = gcx.findSize(p);
+
+            // Check for interior pointer
+            // This depends on:
+            // 1) size is a power of 2 for less than PAGESIZE values
+            // 2) base of memory pool is aligned on PAGESIZE boundary
+            if (cast(size_t)p & (size - 1) & (PAGESIZE - 1))
+                size = 0;
+            return size ? size - SENTINEL_EXTRA : 0;
+        }
+        else
+        {
+            if (p == gcx.p_cache)
+                return gcx.size_cache;
+
+            size_t size = gcx.findSize(p);
+
+            // Check for interior pointer
+            // This depends on:
+            // 1) size is a power of 2 for less than PAGESIZE values
+            // 2) base of memory pool is aligned on PAGESIZE boundary
+            if (cast(size_t)p & (size - 1) & (PAGESIZE - 1))
+                size = 0;
+            else
+            {
+                gcx.p_cache = p;
+                gcx.size_cache = size;
+            }
+
+            return size;
+        }
+    }
+
+
+    /**
+     * Determine the base address of the block containing p.  If p is not a gc
+     * allocated pointer, return null.
+     */
+    BlkInfo query(void *p)
+    {
+        if (!p)
+        {
+            BlkInfo i;
+            return  i;
+        }
+
+        if (!thread_needLock())
+        {
+            return queryNoSync(p);
+        }
+        else synchronized (gcLock)
+        {
+            return queryNoSync(p);
+        }
+    }
+
+
+    //
+    //
+    //
+    BlkInfo queryNoSync(void *p)
+    {
+        assert(p);
+
+        return gcx.getInfo(p);
+    }
+
+
+    /**
+     * Verify that pointer p:
+     *  1) belongs to this memory pool
+     *  2) points to the start of an allocated piece of memory
+     *  3) is not on a free list
+     */
+    void check(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+            checkNoSync(p);
+        }
+        else synchronized (gcLock)
+        {
+            checkNoSync(p);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void checkNoSync(void *p)
+    {
+        assert(p);
+
+        sentinel_Invariant(p);
+        debug (PTRCHECK)
+        {
+            Pool*  pool;
+            size_t pagenum;
+            Bins   bin;
+            size_t size;
+
+            p = sentinel_sub(p);
+            pool = gcx.findPool(p);
+            assert(pool);
+            pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
+            bin = cast(Bins)pool.pagetable[pagenum];
+            assert(bin <= B_PAGE);
+            size = binsize[bin];
+            assert((cast(size_t)p & (size - 1)) == 0);
+
+            debug (PTRCHECK2)
+            {
+                if (bin < B_PAGE)
+                {
+                    // Check that p is not on a free list
+                    List *list;
+
+                    for (list = gcx.bucket[bin]; list; list = list.next)
+                    {
+                        assert(cast(void*)list != p);
+                    }
+                }
+            }
+        }
+    }
+
+
+    //
+    //
+    //
+    private void setStackBottom(void *p)
+    {
+        version (STACKGROWSDOWN)
+        {
+            //p = (void *)((uint *)p + 4);
+            if (p > gcx.stackBottom)
+            {
+                //debug(PRINTF) printf("setStackBottom(%x)\n", p);
+                gcx.stackBottom = p;
+            }
+        }
+        else
+        {
+            //p = (void *)((uint *)p - 4);
+            if (p < gcx.stackBottom)
+            {
+                //debug(PRINTF) printf("setStackBottom(%x)\n", p);
+                gcx.stackBottom = cast(char*)p;
+            }
+        }
+    }
+
+
+    static void scanStaticData(gc_t g)
+    {
+        //debug(PRINTF) printf("+GC.scanStaticData()\n");
+        auto pbot = rt_staticDataBottom();
+        auto ptop = rt_staticDataTop();
+        g.addRange(pbot, ptop - pbot);
+        //debug(PRINTF) printf("-GC.scanStaticData()\n");
+    }
+
+    static void unscanStaticData(gc_t g)
+    {
+        auto pbot = rt_staticDataBottom();
+        g.removeRange(pbot);
+    }
+
+    /**
+     * add p to list of roots
+     */
+    void addRoot(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+            gcx.addRoot(p);
+        }
+        else synchronized (gcLock)
+        {
+            gcx.addRoot(p);
+        }
+    }
+
+
+    /**
+     * remove p from list of roots
+     */
+    void removeRoot(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+            gcx.removeRoot(p);
+        }
+        else synchronized (gcLock)
+        {
+            gcx.removeRoot(p);
+        }
+    }
+
+
+    /**
+     * add range to scan for roots
+     */
+    void addRange(void *p, size_t sz)
+    {
+        if (!p || !sz)
+        {
+            return;
+        }
+
+        //debug(PRINTF) printf("+GC.addRange(pbot = x%x, ptop = x%x)\n", pbot, ptop);
+        if (!thread_needLock())
+        {
+            gcx.addRange(p, p + sz);
+        }
+        else synchronized (gcLock)
+        {
+            gcx.addRange(p, p + sz);
+        }
+        //debug(PRINTF) printf("-GC.addRange()\n");
+    }
+
+
+    /**
+     * remove range
+     */
+    void removeRange(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+            gcx.removeRange(p);
+        }
+        else synchronized (gcLock)
+        {
+            gcx.removeRange(p);
+        }
+    }
+
+
+    /**
+     * do full garbage collection
+     */
+    void fullCollect()
+    {
+        debug(PRINTF) printf("GC.fullCollect()\n");
+
+        if (!thread_needLock())
+        {
+            gcx.fullcollectshell();
+        }
+        else synchronized (gcLock)
+        {
+            gcx.fullcollectshell();
+        }
+
+        version (none)
+        {
+            GCStats stats;
+
+            getStats(stats);
+            debug(PRINTF) printf("poolsize = %x, usedsize = %x, freelistsize = %x\n",
+                    stats.poolsize, stats.usedsize, stats.freelistsize);
+        }
+
+        gcx.log_collect();
+    }
+
+
+    /**
+     * do full garbage collection ignoring roots
+     */
+    void fullCollectNoStack()
+    {
+        if (!thread_needLock())
+        {
+            gcx.noStack++;
+            gcx.fullcollectshell();
+            gcx.noStack--;
+        }
+        else synchronized (gcLock)
+        {
+            gcx.noStack++;
+            gcx.fullcollectshell();
+            gcx.noStack--;
+        }
+    }
+
+
+    /**
+     * minimize free space usage
+     */
+    void minimize()
+    {
+        if (!thread_needLock())
+        {
+            gcx.minimize();
+        }
+        else synchronized (gcLock)
+        {
+            gcx.minimize();
+        }
+    }
+
+
+    /**
+     * Retrieve statistics about garbage collection.
+     * Useful for debugging and tuning.
+     */
+    void getStats(out GCStats stats)
+    {
+        if (!thread_needLock())
+        {
+            getStatsNoSync(stats);
+        }
+        else synchronized (gcLock)
+        {
+            getStatsNoSync(stats);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void getStatsNoSync(out GCStats stats)
+    {
+        size_t psize = 0;
+        size_t usize = 0;
+        size_t flsize = 0;
+
+        size_t n;
+        size_t bsize = 0;
+
+        //debug(PRINTF) printf("getStats()\n");
+        memset(&stats, 0, GCStats.sizeof);
+
+        for (n = 0; n < gcx.npools; n++)
+        {   Pool *pool = gcx.pooltable[n];
+
+            psize += pool.ncommitted * PAGESIZE;
+            for (size_t j = 0; j < pool.ncommitted; j++)
+            {
+                Bins bin = cast(Bins)pool.pagetable[j];
+                if (bin == B_FREE)
+                    stats.freeblocks++;
+                else if (bin == B_PAGE)
+                    stats.pageblocks++;
+                else if (bin < B_PAGE)
+                    bsize += PAGESIZE;
+            }
+        }
+
+        for (n = 0; n < B_PAGE; n++)
+        {
+            //debug(PRINTF) printf("bin %d\n", n);
+            for (List *list = gcx.bucket[n]; list; list = list.next)
+            {
+                //debug(PRINTF) printf("\tlist %x\n", list);
+                flsize += binsize[n];
+            }
+        }
+
+        usize = bsize - flsize;
+
+        stats.poolsize = psize;
+        stats.usedsize = bsize - flsize;
+        stats.freelistsize = flsize;
+    }
+}
+
+
+/* ============================ Gcx =============================== */
+
+enum
+{   PAGESIZE =    4096,
+    COMMITSIZE = (4096*16),
+    POOLSIZE =   (4096*256),
+}
+
+
+enum
+{
+    B_16,
+    B_32,
+    B_64,
+    B_128,
+    B_256,
+    B_512,
+    B_1024,
+    B_2048,
+    B_PAGE,             // start of large alloc
+    B_PAGEPLUS,         // continuation of large alloc
+    B_FREE,             // free page
+    B_UNCOMMITTED,      // memory not committed for this page
+    B_MAX
+}
+
+
+alias ubyte Bins;
+
+
+struct List
+{
+    List *next;
+}
+
+
+struct Range
+{
+    void *pbot;
+    void *ptop;
+}
+
+
+const uint binsize[B_MAX] = [ 16,32,64,128,256,512,1024,2048,4096 ];
+const uint notbinsize[B_MAX] = [ ~(16u-1),~(32u-1),~(64u-1),~(128u-1),~(256u-1),
+                                ~(512u-1),~(1024u-1),~(2048u-1),~(4096u-1) ];
+
+/* ============================ Gcx =============================== */
+
+
+struct Gcx
+{
+    debug (THREADINVARIANT)
+    {
+        pthread_t self;
+        void thread_Invariant()
+        {
+            if (self != pthread_self())
+                printf("thread_Invariant(): gcx = %x, self = %x, pthread_self() = %x\n", this, self, pthread_self());
+            assert(self == pthread_self());
+        }
+    }
+    else
+    {
+        void thread_Invariant() { }
+    }
+
+    void *p_cache;
+    size_t size_cache;
+
+    size_t nroots;
+    size_t rootdim;
+    void **roots;
+
+    size_t nranges;
+    size_t rangedim;
+    Range *ranges;
+
+    uint noStack;       // !=0 means don't scan stack
+    uint log;           // turn on logging
+    uint anychanges;
+    void *stackBottom;
+    uint inited;
+    int disabled;       // turn off collections if >0
+
+    byte *minAddr;      // min(baseAddr)
+    byte *maxAddr;      // max(topAddr)
+
+    size_t npools;
+    Pool **pooltable;
+
+    List *bucket[B_MAX];        // free list for each size
+
+
+    void initialize()
+    {   int dummy;
+
+        (cast(byte*)this)[0 .. Gcx.sizeof] = 0;
+        stackBottom = cast(char*)&dummy;
+        log_init();
+        debug (THREADINVARIANT)
+            self = pthread_self();
+        //printf("gcx = %p, self = %x\n", this, self);
+        inited = 1;
+    }
+
+
+    void Dtor()
+    {
+        inited = 0;
+
+        for (size_t i = 0; i < npools; i++)
+        {   Pool *pool = pooltable[i];
+
+            pool.Dtor();
+            cstdlib.free(pool);
+        }
+        if (pooltable)
+            cstdlib.free(pooltable);
+
+        if (roots)
+            cstdlib.free(roots);
+
+        if (ranges)
+            cstdlib.free(ranges);
+    }
+
+
+    void Invariant() { }
+
+
+    invariant()
+    {
+        if (inited)
+        {
+        //printf("Gcx.invariant(): this = %p\n", this);
+            size_t i;
+
+            // Assure we're called on the right thread
+            debug (THREADINVARIANT) assert(self == pthread_self());
+
+            for (i = 0; i < npools; i++)
+            {   Pool *pool = pooltable[i];
+
+                pool.Invariant();
+                if (i == 0)
+                {
+                    assert(minAddr == pool.baseAddr);
+                }
+                if (i + 1 < npools)
+                {
+                    assert(pool.opCmp(pooltable[i + 1]) < 0);
+                }
+                else if (i + 1 == npools)
+                {
+                    assert(maxAddr == pool.topAddr);
+                }
+            }
+
+            if (roots)
+            {
+                assert(rootdim != 0);
+                assert(nroots <= rootdim);
+            }
+
+            if (ranges)
+            {
+                assert(rangedim != 0);
+                assert(nranges <= rangedim);
+
+                for (i = 0; i < nranges; i++)
+                {
+                    assert(ranges[i].pbot);
+                    assert(ranges[i].ptop);
+                    assert(ranges[i].pbot <= ranges[i].ptop);
+                }
+            }
+
+            for (i = 0; i < B_PAGE; i++)
+            {
+                for (List *list = bucket[i]; list; list = list.next)
+                {
+                }
+            }
+        }
+    }
+
+
+    /**
+     *
+     */
+    void addRoot(void *p)
+    {
+        if (nroots == rootdim)
+        {
+            size_t newdim = rootdim * 2 + 16;
+            void** newroots;
+
+            newroots = cast(void**)cstdlib.malloc(newdim * newroots[0].sizeof);
+            if (!newroots)
+                onOutOfMemoryError();
+            if (roots)
+            {   memcpy(newroots, roots, nroots * newroots[0].sizeof);
+                cstdlib.free(roots);
+            }
+            roots = newroots;
+            rootdim = newdim;
+        }
+        roots[nroots] = p;
+        nroots++;
+    }
+
+
+    /**
+     *
+     */
+    void removeRoot(void *p)
+    {
+        for (size_t i = nroots; i--;)
+        {
+            if (roots[i] == p)
+            {
+                nroots--;
+                memmove(roots + i, roots + i + 1, (nroots - i) * roots[0].sizeof);
+                return;
+            }
+        }
+        assert(0);
+    }
+
+
+    /**
+     *
+     */
+    void addRange(void *pbot, void *ptop)
+    {
+        debug(PRINTF) printf("Thread %x ", pthread_self());
+        debug(PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this, pbot, ptop, nranges);
+        if (nranges == rangedim)
+        {
+            size_t newdim = rangedim * 2 + 16;
+            Range *newranges;
+
+            newranges = cast(Range*)cstdlib.malloc(newdim * newranges[0].sizeof);
+            if (!newranges)
+                onOutOfMemoryError();
+            if (ranges)
+            {   memcpy(newranges, ranges, nranges * newranges[0].sizeof);
+                cstdlib.free(ranges);
+            }
+            ranges = newranges;
+            rangedim = newdim;
+        }
+        ranges[nranges].pbot = pbot;
+        ranges[nranges].ptop = ptop;
+        nranges++;
+    }
+
+
+    /**
+     *
+     */
+    void removeRange(void *pbot)
+    {
+        debug(PRINTF) printf("Thread %x ", pthread_self());
+        debug(PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this, pbot, nranges);
+        for (size_t i = nranges; i--;)
+        {
+            if (ranges[i].pbot == pbot)
+            {
+                nranges--;
+                memmove(ranges + i, ranges + i + 1, (nranges - i) * ranges[0].sizeof);
+                return;
+            }
+        }
+        debug(PRINTF) printf("Wrong thread\n");
+
+        // This is a fatal error, but ignore it.
+        // The problem is that we can get a Close() call on a thread
+        // other than the one the range was allocated on.
+        //assert(zero);
+    }
+
+
+    /**
+     * Find Pool that pointer is in.
+     * Return null if not in a Pool.
+     * Assume pooltable[] is sorted.
+     */
+    Pool *findPool(void *p)
+    {
+        if (p >= minAddr && p < maxAddr)
+        {
+            if (npools == 1)
+            {
+                return pooltable[0];
+            }
+
+            for (size_t i = 0; i < npools; i++)
+            {   Pool *pool;
+
+                pool = pooltable[i];
+                if (p < pool.topAddr)
+                {   if (pool.baseAddr <= p)
+                        return pool;
+                    break;
+                }
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Find base address of block containing pointer p.
+     * Returns null if not a gc'd pointer
+     */
+    void* findBase(void *p)
+    {
+        Pool *pool;
+
+        pool = findPool(p);
+        if (pool)
+        {
+            size_t offset = cast(size_t)(p - pool.baseAddr);
+            size_t pn = offset / PAGESIZE;
+            Bins   bin = cast(Bins)pool.pagetable[pn];
+
+            // Adjust bit to be at start of allocated memory block
+            if (bin <= B_PAGE)
+            {
+                return pool.baseAddr + (offset & notbinsize[bin]);
+            }
+            else if (bin == B_PAGEPLUS)
+            {
+                do
+                {   --pn, offset -= PAGESIZE;
+                } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
+
+                return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
+            }
+            else
+            {
+                // we are in a B_FREE or B_UNCOMMITTED page
+                return null;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Find size of pointer p.
+     * Returns 0 if not a gc'd pointer
+     */
+    size_t findSize(void *p)
+    {
+        Pool*  pool;
+        size_t size = 0;
+
+        pool = findPool(p);
+        if (pool)
+        {
+            size_t pagenum;
+            Bins   bin;
+
+            pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
+            bin = cast(Bins)pool.pagetable[pagenum];
+            size = binsize[bin];
+            if (bin == B_PAGE)
+            {   size_t npages = pool.ncommitted;
+                ubyte* pt;
+                size_t i;
+
+                pt = &pool.pagetable[0];
+                for (i = pagenum + 1; i < npages; i++)
+                {
+                    if (pt[i] != B_PAGEPLUS)
+                        break;
+                }
+                size = (i - pagenum) * PAGESIZE;
+            }
+        }
+        return size;
+    }
+
+
+    /**
+     *
+     */
+    BlkInfo getInfo(void* p)
+    {
+        Pool*   pool;
+        BlkInfo info;
+
+        pool = findPool(p);
+        if (pool)
+        {
+            size_t offset = cast(size_t)(p - pool.baseAddr);
+            size_t pn = offset / PAGESIZE;
+            Bins   bin = cast(Bins)pool.pagetable[pn];
+
+            ////////////////////////////////////////////////////////////////////
+            // findAddr
+            ////////////////////////////////////////////////////////////////////
+
+            if (bin <= B_PAGE)
+            {
+                info.base = pool.baseAddr + (offset & notbinsize[bin]);
+            }
+            else if (bin == B_PAGEPLUS)
+            {
+                do
+                {   --pn, offset -= PAGESIZE;
+                } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
+
+                info.base = pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
+
+                // fix bin for use by size calc below
+                bin = cast(Bins)pool.pagetable[pn];
+            }
+
+            ////////////////////////////////////////////////////////////////////
+            // findSize
+            ////////////////////////////////////////////////////////////////////
+
+            info.size = binsize[bin];
+            if (bin == B_PAGE)
+            {   size_t npages = pool.ncommitted;
+                ubyte* pt;
+                size_t i;
+
+                pt = &pool.pagetable[0];
+                for (i = pn + 1; i < npages; i++)
+                {
+                    if (pt[i] != B_PAGEPLUS)
+                        break;
+                }
+                info.size = (i - pn) * PAGESIZE;
+            }
+
+            ////////////////////////////////////////////////////////////////////
+            // getBits
+            ////////////////////////////////////////////////////////////////////
+
+            info.attr = getBits(pool, cast(size_t)(offset / 16));
+        }
+        return info;
+    }
+
+
+    /**
+     * Compute bin for size.
+     */
+    static Bins findBin(size_t size)
+    {   Bins bin;
+
+        if (size <= 256)
+        {
+            if (size <= 64)
+            {
+                if (size <= 16)
+                    bin = B_16;
+                else if (size <= 32)
+                    bin = B_32;
+                else
+                    bin = B_64;
+            }
+            else
+            {
+                if (size <= 128)
+                    bin = B_128;
+                else
+                    bin = B_256;
+            }
+        }
+        else
+        {
+            if (size <= 1024)
+            {
+                if (size <= 512)
+                    bin = B_512;
+                else
+                    bin = B_1024;
+            }
+            else
+            {
+                if (size <= 2048)
+                    bin = B_2048;
+                else
+                    bin = B_PAGE;
+            }
+        }
+        return bin;
+    }
+
+
+    /**
+     * Allocate a new pool of at least size bytes.
+     * Sort it into pooltable[].
+     * Mark all memory in the pool as B_FREE.
+     * Return the actual number of bytes reserved or 0 on error.
+     */
+    size_t reserve(size_t size)
+    {
+        size_t npages = (size + PAGESIZE - 1) / PAGESIZE;
+        Pool*  pool = newPool(npages);
+
+        if (!pool || pool.extendPages(npages) == OPFAIL)
+            return 0;
+        return pool.ncommitted * PAGESIZE;
+    }
+
+
+    /**
+     * Minimizes physical memory usage by returning free pools to the OS.
+     */
+    void minimize()
+    {
+        size_t n;
+        size_t pn;
+        Pool*  pool;
+        size_t ncommitted;
+
+        for (n = 0; n < npools; n++)
+        {
+            pool = pooltable[n];
+            ncommitted = pool.ncommitted;
+            for (pn = 0; pn < ncommitted; pn++)
+            {
+                if (cast(Bins)pool.pagetable[pn] != B_FREE)
+                    break;
+            }
+            if (pn < ncommitted)
+            {
+                n++;
+                continue;
+            }
+            pool.Dtor();
+            cstdlib.free(pool);
+            memmove(pooltable + n,
+                    pooltable + n + 1,
+                    (--npools - n) * (Pool*).sizeof);
+            minAddr = pooltable[0].baseAddr;
+            maxAddr = pooltable[npools - 1].topAddr;
+        }
+    }
+
+
+    /**
+     * Allocate a chunk of memory that is larger than a page.
+     * Return null if out of memory.
+     */
+    void *bigAlloc(size_t size)
+    {
+        Pool*  pool;
+        size_t npages;
+        size_t n;
+        size_t pn;
+        size_t freedpages;
+        void*  p;
+        int    state;
+
+        npages = (size + PAGESIZE - 1) / PAGESIZE;
+
+        for (state = 0; ; )
+        {
+            // This code could use some refinement when repeatedly
+            // allocating very large arrays.
+
+            for (n = 0; n < npools; n++)
+            {
+                pool = pooltable[n];
+                pn = pool.allocPages(npages);
+                if (pn != OPFAIL)
+                    goto L1;
+            }
+
+            // Failed
+            switch (state)
+            {
+            case 0:
+                if (disabled)
+                {   state = 1;
+                    continue;
+                }
+                // Try collecting
+                freedpages = fullcollectshell();
+                if (freedpages >= npools * ((POOLSIZE / PAGESIZE) / 4))
+                {   state = 1;
+                    continue;
+                }
+                // Release empty pools to prevent bloat
+                minimize();
+                // Allocate new pool
+                pool = newPool(npages);
+                if (!pool)
+                {   state = 2;
+                    continue;
+                }
+                pn = pool.allocPages(npages);
+                assert(pn != OPFAIL);
+                goto L1;
+            case 1:
+                // Release empty pools to prevent bloat
+                minimize();
+                // Allocate new pool
+                pool = newPool(npages);
+                if (!pool)
+                    goto Lnomemory;
+                pn = pool.allocPages(npages);
+                assert(pn != OPFAIL);
+                goto L1;
+            case 2:
+                goto Lnomemory;
+            default:
+                assert(false);
+            }
+        }
+
+      L1:
+        pool.pagetable[pn] = B_PAGE;
+        if (npages > 1)
+            memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
+        p = pool.baseAddr + pn * PAGESIZE;
+        memset(cast(char *)p + size, 0, npages * PAGESIZE - size);
+        debug (MEMSTOMP) memset(p, 0xF1, size);
+        //debug(PRINTF) printf("\tp = %x\n", p);
+        return p;
+
+      Lnomemory:
+        return null; // let mallocNoSync handle the error
+    }
+
+
+    /**
+     * Allocate a new pool with at least npages in it.
+     * Sort it into pooltable[].
+     * Return null if failed.
+     */
+    Pool *newPool(size_t npages)
+    {
+        Pool*  pool;
+        Pool** newpooltable;
+        size_t newnpools;
+        size_t i;
+
+        //debug(PRINTF) printf("************Gcx::newPool(npages = %d)****************\n", npages);
+
+        // Round up to COMMITSIZE pages
+        npages = (npages + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1);
+
+        // Minimum of POOLSIZE
+        if (npages < POOLSIZE/PAGESIZE)
+            npages = POOLSIZE/PAGESIZE;
+        else if (npages > POOLSIZE/PAGESIZE)
+        {   // Give us 150% of requested size, so there's room to extend
+            auto n = npages + (npages >> 1);
+            if (n < size_t.max/PAGESIZE)
+                npages = n;
+        }
+
+        // Allocate successively larger pools up to 8 megs
+        if (npools)
+        {   size_t n;
+
+            n = npools;
+            if (n > 8)
+                n = 8;                  // cap pool size at 8 megs
+            n *= (POOLSIZE / PAGESIZE);
+            if (npages < n)
+                npages = n;
+        }
+
+        pool = cast(Pool *)cstdlib.calloc(1, Pool.sizeof);
+        if (pool)
+        {
+            pool.initialize(npages);
+            if (!pool.baseAddr)
+                goto Lerr;
+
+            newnpools = npools + 1;
+            newpooltable = cast(Pool **)cstdlib.realloc(pooltable, newnpools * (Pool *).sizeof);
+            if (!newpooltable)
+                goto Lerr;
+
+            // Sort pool into newpooltable[]
+            for (i = 0; i < npools; i++)
+            {
+                if (pool.opCmp(newpooltable[i]) < 0)
+                     break;
+            }
+            memmove(newpooltable + i + 1, newpooltable + i, (npools - i) * (Pool *).sizeof);
+            newpooltable[i] = pool;
+
+            pooltable = newpooltable;
+            npools = newnpools;
+
+            minAddr = pooltable[0].baseAddr;
+            maxAddr = pooltable[npools - 1].topAddr;
+        }
+        return pool;
+
+      Lerr:
+        pool.Dtor();
+        cstdlib.free(pool);
+        return null;
+    }
+
+
+    /**
+     * Allocate a page of bin's.
+     * Returns:
+     *  0       failed
+     */
+    int allocPage(Bins bin)
+    {
+        Pool*  pool;
+        size_t n;
+        size_t pn;
+        byte*  p;
+        byte*  ptop;
+
+        //debug(PRINTF) printf("Gcx::allocPage(bin = %d)\n", bin);
+        for (n = 0; n < npools; n++)
+        {
+            pool = pooltable[n];
+            pn = pool.allocPages(1);
+            if (pn != OPFAIL)
+                goto L1;
+        }
+        return 0;               // failed
+
+      L1:
+        pool.pagetable[pn] = cast(ubyte)bin;
+
+        // Convert page to free list
+        size_t size = binsize[bin];
+        List **b = &bucket[bin];
+
+        p = pool.baseAddr + pn * PAGESIZE;
+        ptop = p + PAGESIZE;
+        for (; p < ptop; p += size)
+        {
+            (cast(List *)p).next = *b;
+            *b = cast(List *)p;
+        }
+        return 1;
+    }
+
+
+    /**
+     * Search a range of memory values and mark any pointers into the GC pool.
+     */
+    void mark(void *pbot, void *ptop)
+    {
+        void **p1 = cast(void **)pbot;
+        void **p2 = cast(void **)ptop;
+        size_t pcache = 0;
+        uint changes = 0;
+
+        //printf("marking range: %p -> %p\n", pbot, ptop);
+        for (; p1 < p2; p1++)
+        {
+            Pool *pool;
+            byte *p = cast(byte *)(*p1);
+
+            //if (log) debug(PRINTF) printf("\tmark %x\n", p);
+            if (p >= minAddr && p < maxAddr)
+            {
+                if ((cast(size_t)p & ~(PAGESIZE-1)) == pcache)
+                    continue;
+
+                pool = findPool(p);
+                if (pool)
+                {
+                    size_t offset = cast(size_t)(p - pool.baseAddr);
+                    size_t biti;
+                    size_t pn = offset / PAGESIZE;
+                    Bins   bin = cast(Bins)pool.pagetable[pn];
+
+                    //debug(PRINTF) printf("\t\tfound pool %x, base=%x, pn = %d, bin = %d, biti = x%x\n", pool, pool.baseAddr, pn, bin, biti);
+
+                    // Adjust bit to be at start of allocated memory block
+                    if (bin <= B_PAGE)
+                    {
+                        biti = (offset & notbinsize[bin]) >> 4;
+                        //debug(PRINTF) printf("\t\tbiti = x%x\n", biti);
+                    }
+                    else if (bin == B_PAGEPLUS)
+                    {
+                        do
+                        {   --pn;
+                        } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
+                        biti = pn * (PAGESIZE / 16);
+                    }
+                    else
+                    {
+                        // Don't mark bits in B_FREE or B_UNCOMMITTED pages
+                        continue;
+                    }
+
+                    if (bin >= B_PAGE) // Cache B_PAGE and B_PAGEPLUS lookups
+                        pcache = cast(size_t)p & ~(PAGESIZE-1);
+
+                    //debug(PRINTF) printf("\t\tmark(x%x) = %d\n", biti, pool.mark.test(biti));
+                    if (!pool.mark.test(biti))
+                    {
+                        //if (log) debug(PRINTF) printf("\t\tmarking %x\n", p);
+                        pool.mark.set(biti);
+                        if (!pool.noscan.test(biti))
+                        {
+                            pool.scan.set(biti);
+                            changes = 1;
+                        }
+                        log_parent(sentinel_add(pool.baseAddr + biti * 16), sentinel_add(pbot));
+                    }
+                }
+            }
+        }
+        anychanges |= changes;
+    }
+
+
+    /**
+     * Return number of full pages free'd.
+     */
+    size_t fullcollectshell()
+    {
+        // The purpose of the 'shell' is to ensure all the registers
+        // get put on the stack so they'll be scanned
+        void *sp;
+        size_t result;
+        version (GNU)
+        {
+            __builtin_unwind_init();
+            sp = & sp;
+        }
+        else
+        {
+        asm
+        {
+            pushad              ;
+            mov sp[EBP],ESP     ;
+        }
+        }
+        result = fullcollect(sp);
+        version (GNU)
+        {
+            // nothing to do
+        }
+        else
+        {
+        asm
+        {
+            popad               ;
+        }
+        }
+        return result;
+    }
+
+
+    /**
+     *
+     */
+    size_t fullcollect(void *stackTop)
+    {
+        size_t n;
+        Pool*  pool;
+
+        debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n");
+
+        thread_suspendAll();
+
+        p_cache = null;
+        size_cache = 0;
+
+        anychanges = 0;
+        for (n = 0; n < npools; n++)
+        {
+            pool = pooltable[n];
+            pool.mark.zero();
+            pool.scan.zero();
+            pool.freebits.zero();
+        }
+
+        // Mark each free entry, so it doesn't get scanned
+        for (n = 0; n < B_PAGE; n++)
+        {
+            for (List *list = bucket[n]; list; list = list.next)
+            {
+                pool = findPool(list);
+                assert(pool);
+                pool.freebits.set(cast(size_t)(cast(byte*)list - pool.baseAddr) / 16);
+            }
+        }
+
+        for (n = 0; n < npools; n++)
+        {
+            pool = pooltable[n];
+            pool.mark.copy(&pool.freebits);
+        }
+
+        rt_scanStaticData( &mark );
+
+        version (MULTI_THREADED)
+        {
+            if (!noStack)
+            {
+                // Scan stacks and registers for each paused thread
+                thread_scanAll( &mark, stackTop );
+            }
+        }
+        else
+        {
+            if (!noStack)
+            {
+                // Scan stack for main thread
+                debug(PRINTF) printf(" scan stack bot = %x, top = %x\n", stackTop, stackBottom);
+                version (STACKGROWSDOWN)
+                    mark(stackTop, stackBottom);
+                else
+                    mark(stackBottom, stackTop);
+            }
+        }
+
+        // Scan roots[]
+        debug(COLLECT_PRINTF) printf("scan roots[]\n");
+        mark(roots, roots + nroots);
+
+        // Scan ranges[]
+        debug(COLLECT_PRINTF) printf("scan ranges[]\n");
+        //log++;
+        for (n = 0; n < nranges; n++)
+        {
+            debug(COLLECT_PRINTF) printf("\t%x .. %x\n", ranges[n].pbot, ranges[n].ptop);
+            mark(ranges[n].pbot, ranges[n].ptop);
+        }
+        //log--;
+
+        debug(COLLECT_PRINTF) printf("\tscan heap\n");
+        while (anychanges)
+        {
+            anychanges = 0;
+            for (n = 0; n < npools; n++)
+            {
+                uint *bbase;
+                uint *b;
+                uint *btop;
+
+                pool = pooltable[n];
+
+                bbase = pool.scan.base();
+                btop = bbase + pool.scan.nwords;
+                for (b = bbase; b < btop;)
+                {   Bins   bin;
+                    size_t pn;
+                    size_t u;
+                    size_t bitm;
+                    byte*  o;
+
+                    bitm = *b;
+                    if (!bitm)
+                    {   b++;
+                        continue;
+                    }
+                    *b = 0;
+
+                    o = pool.baseAddr + (b - bbase) * 32 * 16;
+                    if (!(bitm & 0xFFFF))
+                    {
+                        bitm >>= 16;
+                        o += 16 * 16;
+                    }
+                    for (; bitm; o += 16, bitm >>= 1)
+                    {
+                        if (!(bitm & 1))
+                            continue;
+
+                        pn = cast(size_t)(o - pool.baseAddr) / PAGESIZE;
+                        bin = cast(Bins)pool.pagetable[pn];
+                        if (bin < B_PAGE)
+                        {
+                            mark(o, o + binsize[bin]);
+                        }
+                        else if (bin == B_PAGE || bin == B_PAGEPLUS)
+                        {
+                            if (bin == B_PAGEPLUS)
+                            {
+                                while (pool.pagetable[pn - 1] != B_PAGE)
+                                    pn--;
+                            }
+                            u = 1;
+                            while (pn + u < pool.ncommitted && pool.pagetable[pn + u] == B_PAGEPLUS)
+                                u++;
+                            mark(o, o + u * PAGESIZE);
+                        }
+                    }
+                }
+            }
+        }
+
+        thread_resumeAll();
+
+        // Free up everything not marked
+        debug(COLLECT_PRINTF) printf("\tfree'ing\n");
+        size_t freedpages = 0;
+        size_t freed = 0;
+        for (n = 0; n < npools; n++)
+        {   size_t pn;
+            size_t ncommitted;
+            uint*  bbase;
+
+            pool = pooltable[n];
+            bbase = pool.mark.base();
+            ncommitted = pool.ncommitted;
+            for (pn = 0; pn < ncommitted; pn++, bbase += PAGESIZE / (32 * 16))
+            {
+                Bins bin = cast(Bins)pool.pagetable[pn];
+
+                if (bin < B_PAGE)
+                {   byte* p;
+                    byte* ptop;
+                    size_t biti;
+                    size_t bitstride;
+                    auto   size = binsize[bin];
+
+                    p = pool.baseAddr + pn * PAGESIZE;
+                    ptop = p + PAGESIZE;
+                    biti = pn * (PAGESIZE/16);
+                    bitstride = size / 16;
+
+    version(none) // BUG: doesn't work because freebits() must also be cleared
+    {
+                    // If free'd entire page
+                    if (bbase[0] == 0 && bbase[1] == 0 && bbase[2] == 0 && bbase[3] == 0 &&
+                        bbase[4] == 0 && bbase[5] == 0 && bbase[6] == 0 && bbase[7] == 0)
+                    {
+                        for (; p < ptop; p += size, biti += bitstride)
+                        {
+                            if (pool.finals.nbits && pool.finals.testClear(biti))
+                                rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/);
+                            gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
+
+                            List *list = cast(List *)p;
+                            //debug(PRINTF) printf("\tcollecting %x\n", list);
+                            log_free(sentinel_add(list));
+
+                            debug (MEMSTOMP) memset(p, 0xF3, size);
+                        }
+                        pool.pagetable[pn] = B_FREE;
+                        freed += PAGESIZE;
+                        //debug(PRINTF) printf("freeing entire page %d\n", pn);
+                        continue;
+                    }
+    }
+                    for (; p < ptop; p += size, biti += bitstride)
+                    {
+                        if (!pool.mark.test(biti))
+                        {
+                            sentinel_Invariant(sentinel_add(p));
+
+                            pool.freebits.set(biti);
+                            if (pool.finals.nbits && pool.finals.testClear(biti))
+                                rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/);
+                            clrBits(pool, biti, BlkAttr.ALL_BITS);
+
+                            List *list = cast(List *)p;
+                            debug(PRINTF) printf("\tcollecting %x\n", list);
+                            log_free(sentinel_add(list));
+
+                            debug (MEMSTOMP) memset(p, 0xF3, size);
+
+                            freed += size;
+                        }
+                    }
+                }
+                else if (bin == B_PAGE)
+                {   size_t biti = pn * (PAGESIZE / 16);
+
+                    if (!pool.mark.test(biti))
+                    {   byte *p = pool.baseAddr + pn * PAGESIZE;
+
+                        sentinel_Invariant(sentinel_add(p));
+                        if (pool.finals.nbits && pool.finals.testClear(biti))
+                            rt_finalize(sentinel_add(p), false/*noStack > 0*/);
+                        clrBits(pool, biti, BlkAttr.ALL_BITS);
+
+                        debug(COLLECT_PRINTF) printf("\tcollecting big %x\n", p);
+                        log_free(sentinel_add(p));
+                        pool.pagetable[pn] = B_FREE;
+                        freedpages++;
+                        debug (MEMSTOMP) memset(p, 0xF3, PAGESIZE);
+                        while (pn + 1 < ncommitted && pool.pagetable[pn + 1] == B_PAGEPLUS)
+                        {
+                            pn++;
+                            pool.pagetable[pn] = B_FREE;
+                            freedpages++;
+
+                            debug (MEMSTOMP)
+                            {   p += PAGESIZE;
+                                memset(p, 0xF3, PAGESIZE);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Zero buckets
+        bucket[] = null;
+
+        // Free complete pages, rebuild free list
+        debug(COLLECT_PRINTF) printf("\tfree complete pages\n");
+        size_t recoveredpages = 0;
+        for (n = 0; n < npools; n++)
+        {   size_t pn;
+            size_t ncommitted;
+
+            pool = pooltable[n];
+            ncommitted = pool.ncommitted;
+            for (pn = 0; pn < ncommitted; pn++)
+            {
+                Bins   bin = cast(Bins)pool.pagetable[pn];
+                size_t biti;
+                size_t u;
+
+                if (bin < B_PAGE)
+                {
+                    size_t size = binsize[bin];
+                    size_t bitstride = size / 16;
+                    size_t bitbase = pn * (PAGESIZE / 16);
+                    size_t bittop = bitbase + (PAGESIZE / 16);
+                    byte*  p;
+
+                    biti = bitbase;
+                    for (biti = bitbase; biti < bittop; biti += bitstride)
+                    {   if (!pool.freebits.test(biti))
+                            goto Lnotfree;
+                    }
+                    pool.pagetable[pn] = B_FREE;
+                    recoveredpages++;
+                    continue;
+
+                 Lnotfree:
+                    p = pool.baseAddr + pn * PAGESIZE;
+                    for (u = 0; u < PAGESIZE; u += size)
+                    {   biti = bitbase + u / 16;
+                        if (pool.freebits.test(biti))
+                        {   List *list;
+
+                            list = cast(List *)(p + u);
+                            if (list.next != bucket[bin])       // avoid unnecessary writes
+                                list.next = bucket[bin];
+                            bucket[bin] = list;
+                        }
+                    }
+                }
+            }
+        }
+
+        debug(COLLECT_PRINTF) printf("recovered pages = %d\n", recoveredpages);
+        debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedpages, npools);
+
+        return freedpages + recoveredpages;
+    }
+
+
+    /**
+     *
+     */
+    uint getBits(Pool* pool, size_t biti)
+    in
+    {
+        assert( pool );
+    }
+    body
+    {
+        uint bits;
+
+        if (pool.finals.nbits &&
+            pool.finals.test(biti))
+            bits |= BlkAttr.FINALIZE;
+        if (pool.noscan.test(biti))
+            bits |= BlkAttr.NO_SCAN;
+//        if (pool.nomove.nbits &&
+//            pool.nomove.test(biti))
+//            bits |= BlkAttr.NO_MOVE;
+        return bits;
+    }
+
+
+    /**
+     *
+     */
+    void setBits(Pool* pool, size_t biti, uint mask)
+    in
+    {
+        assert( pool );
+    }
+    body
+    {
+        if (mask & BlkAttr.FINALIZE)
+        {
+            if (!pool.finals.nbits)
+                pool.finals.alloc(pool.mark.nbits);
+            pool.finals.set(biti);
+        }
+        if (mask & BlkAttr.NO_SCAN)
+        {
+            pool.noscan.set(biti);
+        }
+//        if (mask & BlkAttr.NO_MOVE)
+//        {
+//            if (!pool.nomove.nbits)
+//                pool.nomove.alloc(pool.mark.nbits);
+//            pool.nomove.set(biti);
+//        }
+    }
+
+
+    /**
+     *
+     */
+    void clrBits(Pool* pool, size_t biti, uint mask)
+    in
+    {
+        assert( pool );
+    }
+    body
+    {
+        if (mask & BlkAttr.FINALIZE && pool.finals.nbits)
+            pool.finals.clear(biti);
+        if (mask & BlkAttr.NO_SCAN)
+            pool.noscan.clear(biti);
+//        if (mask & BlkAttr.NO_MOVE && pool.nomove.nbits)
+//            pool.nomove.clear(biti);
+    }
+
+
+    /***** Leak Detector ******/
+
+
+    debug (LOGGING)
+    {
+        LogArray current;
+        LogArray prev;
+
+
+        void log_init()
+        {
+            //debug(PRINTF) printf("+log_init()\n");
+            current.reserve(1000);
+            prev.reserve(1000);
+            //debug(PRINTF) printf("-log_init()\n");
+        }
+
+
+        void log_malloc(void *p, size_t size)
+        {
+            //debug(PRINTF) printf("+log_malloc(p = %x, size = %d)\n", p, size);
+            Log log;
+
+            log.p = p;
+            log.size = size;
+            log.line = GC.line;
+            log.file = GC.file;
+            log.parent = null;
+
+            GC.line = 0;
+            GC.file = null;
+
+            current.push(log);
+            //debug(PRINTF) printf("-log_malloc()\n");
+        }
+
+
+        void log_free(void *p)
+        {
+            //debug(PRINTF) printf("+log_free(%x)\n", p);
+            size_t i;
+
+            i = current.find(p);
+            if (i == OPFAIL)
+            {
+                debug(PRINTF) printf("free'ing unallocated memory %x\n", p);
+            }
+            else
+                current.remove(i);
+            //debug(PRINTF) printf("-log_free()\n");
+        }
+
+
+        void log_collect()
+        {
+            //debug(PRINTF) printf("+log_collect()\n");
+            // Print everything in current that is not in prev
+
+            debug(PRINTF) printf("New pointers this cycle: --------------------------------\n");
+            size_t used = 0;
+            for (size_t i = 0; i < current.dim; i++)
+            {
+                size_t j;
+
+                j = prev.find(current.data[i].p);
+                if (j == OPFAIL)
+                    current.data[i].print();
+                else
+                    used++;
+            }
+
+            debug(PRINTF) printf("All roots this cycle: --------------------------------\n");
+            for (size_t i = 0; i < current.dim; i++)
+            {
+                void *p;
+                size_t j;
+
+                p = current.data[i].p;
+                if (!findPool(current.data[i].parent))
+                {
+                    j = prev.find(current.data[i].p);
+                    if (j == OPFAIL)
+                        debug(PRINTF) printf("N");
+                    else
+                        debug(PRINTF) printf(" ");;
+                    current.data[i].print();
+                }
+            }
+
+            debug(PRINTF) printf("Used = %d-------------------------------------------------\n", used);
+            prev.copy(&current);
+
+            debug(PRINTF) printf("-log_collect()\n");
+        }
+
+
+        void log_parent(void *p, void *parent)
+        {
+            //debug(PRINTF) printf("+log_parent()\n");
+            size_t i;
+
+            i = current.find(p);
+            if (i == OPFAIL)
+            {
+                debug(PRINTF) printf("parent'ing unallocated memory %x, parent = %x\n", p, parent);
+                Pool *pool;
+                pool = findPool(p);
+                assert(pool);
+                size_t offset = cast(size_t)(p - pool.baseAddr);
+                size_t biti;
+                size_t pn = offset / PAGESIZE;
+                Bins bin = cast(Bins)pool.pagetable[pn];
+                biti = (offset & notbinsize[bin]);
+                debug(PRINTF) printf("\tbin = %d, offset = x%x, biti = x%x\n", bin, offset, biti);
+            }
+            else
+            {
+                current.data[i].parent = parent;
+            }
+            //debug(PRINTF) printf("-log_parent()\n");
+        }
+
+    }
+    else
+    {
+        void log_init() { }
+        void log_malloc(void *p, size_t size) { }
+        void log_free(void *p) { }
+        void log_collect() { }
+        void log_parent(void *p, void *parent) { }
+    }
+}
+
+
+/* ============================ Pool  =============================== */
+
+
+struct Pool
+{
+    byte* baseAddr;
+    byte* topAddr;
+    GCBits mark;        // entries already scanned, or should not be scanned
+    GCBits scan;        // entries that need to be scanned
+    GCBits freebits;    // entries that are on the free list
+    GCBits finals;      // entries that need finalizer run on them
+    GCBits noscan;      // entries that should not be scanned
+
+    size_t npages;
+    size_t ncommitted;    // ncommitted <= npages
+    ubyte* pagetable;
+
+
+    void initialize(size_t npages)
+    {
+        size_t poolsize;
+
+        //debug(PRINTF) printf("Pool::Pool(%u)\n", npages);
+        poolsize = npages * PAGESIZE;
+        assert(poolsize >= POOLSIZE);
+        baseAddr = cast(byte *)os_mem_map(poolsize);
+
+        // Some of the code depends on page alignment of memory pools
+        assert((cast(size_t)baseAddr & (PAGESIZE - 1)) == 0);
+
+        if (!baseAddr)
+        {
+            //debug(PRINTF) printf("GC fail: poolsize = x%x, errno = %d\n", poolsize, errno);
+            //debug(PRINTF) printf("message = '%s'\n", sys_errlist[errno]);
+
+            npages = 0;
+            poolsize = 0;
+        }
+        //assert(baseAddr);
+        topAddr = baseAddr + poolsize;
+
+        mark.alloc(cast(size_t)poolsize / 16);
+        scan.alloc(cast(size_t)poolsize / 16);
+        freebits.alloc(cast(size_t)poolsize / 16);
+        noscan.alloc(cast(size_t)poolsize / 16);
+
+        pagetable = cast(ubyte*)cstdlib.malloc(npages);
+        if (!pagetable)
+            onOutOfMemoryError();
+        memset(pagetable, B_UNCOMMITTED, npages);
+
+        this.npages = npages;
+        ncommitted = 0;
+    }
+
+
+    void Dtor()
+    {
+        if (baseAddr)
+        {
+            int result;
+
+            if (ncommitted)
+            {
+                result = os_mem_decommit(baseAddr, 0, ncommitted * PAGESIZE);
+                assert(result == 0);
+                ncommitted = 0;
+            }
+
+            if (npages)
+            {
+                result = os_mem_unmap(baseAddr, npages * PAGESIZE);
+                assert(result == 0);
+                npages = 0;
+            }
+
+            baseAddr = null;
+            topAddr = null;
+        }
+        if (pagetable)
+            cstdlib.free(pagetable);
+
+        mark.Dtor();
+        scan.Dtor();
+        freebits.Dtor();
+        finals.Dtor();
+        noscan.Dtor();
+    }
+
+
+    void Invariant() { }
+
+
+    invariant()
+    {
+        //mark.Invariant();
+        //scan.Invariant();
+        //freebits.Invariant();
+        //finals.Invariant();
+        //noscan.Invariant();
+
+        if (baseAddr)
+        {
+            //if (baseAddr + npages * PAGESIZE != topAddr)
+                //printf("baseAddr = %p, npages = %d, topAddr = %p\n", baseAddr, npages, topAddr);
+            assert(baseAddr + npages * PAGESIZE == topAddr);
+            assert(ncommitted <= npages);
+        }
+
+        for (size_t i = 0; i < npages; i++)
+        {   Bins bin = cast(Bins)pagetable[i];
+
+            assert(bin < B_MAX);
+        }
+    }
+
+
+    /**
+     * Allocate n pages from Pool.
+     * Returns OPFAIL on failure.
+     */
+    size_t allocPages(size_t n)
+    {
+        size_t i;
+        size_t n2;
+
+        //debug(PRINTF) printf("Pool::allocPages(n = %d)\n", n);
+        n2 = n;
+        for (i = 0; i < ncommitted; i++)
+        {
+            if (pagetable[i] == B_FREE)
+            {
+                if (--n2 == 0)
+                {   //debug(PRINTF) printf("\texisting pn = %d\n", i - n + 1);
+                    return i - n + 1;
+                }
+            }
+            else
+                n2 = n;
+        }
+        return extendPages(n);
+    }
+
+    /**
+     * Extend Pool by n pages.
+     * Returns OPFAIL on failure.
+     */
+    size_t extendPages(size_t n)
+    {
+        //debug(PRINTF) printf("Pool::extendPages(n = %d)\n", n);
+        if (ncommitted + n <= npages)
+        {
+            size_t tocommit;
+
+            tocommit = (n + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1);
+            if (ncommitted + tocommit > npages)
+                tocommit = npages - ncommitted;
+            //debug(PRINTF) printf("\tlooking to commit %d more pages\n", tocommit);
+            //fflush(stdout);
+            if (os_mem_commit(baseAddr, ncommitted * PAGESIZE, tocommit * PAGESIZE) == 0)
+            {
+                memset(pagetable + ncommitted, B_FREE, tocommit);
+                auto i = ncommitted;
+                ncommitted += tocommit;
+
+                while (i && pagetable[i - 1] == B_FREE)
+                    i--;
+
+                return i;
+            }
+            //debug(PRINTF) printf("\tfailed to commit %d pages\n", tocommit);
+        }
+
+        return OPFAIL;
+    }
+
+
+    /**
+     * Free npages pages starting with pagenum.
+     */
+    void freePages(size_t pagenum, size_t npages)
+    {
+        memset(&pagetable[pagenum], B_FREE, npages);
+    }
+
+
+    /**
+     * Used for sorting pooltable[]
+     */
+    int opCmp(Pool *p2)
+    {
+        if (baseAddr < p2.baseAddr)
+            return -1;
+        else
+        return cast(int)(baseAddr > p2.baseAddr);
+    }
+}
+
+
+/* ============================ SENTINEL =============================== */
+
+
+version (SENTINEL)
+{
+    const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL; // 32 or 64 bits
+    const ubyte SENTINEL_POST = 0xF5;           // 8 bits
+    const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1;
+
+
+    size_t* sentinel_size(void *p)  { return &(cast(size_t *)p)[-2]; }
+    size_t* sentinel_pre(void *p)   { return &(cast(size_t *)p)[-1]; }
+    ubyte* sentinel_post(void *p) { return &(cast(ubyte *)p)[*sentinel_size(p)]; }
+
+
+    void sentinel_init(void *p, size_t size)
+    {
+        *sentinel_size(p) = size;
+        *sentinel_pre(p) = SENTINEL_PRE;
+        *sentinel_post(p) = SENTINEL_POST;
+    }
+
+
+    void sentinel_Invariant(void *p)
+    {
+        assert(*sentinel_pre(p) == SENTINEL_PRE);
+        assert(*sentinel_post(p) == SENTINEL_POST);
+    }
+
+
+    void *sentinel_add(void *p)
+    {
+        return p + 2 * size_t.sizeof;
+    }
+
+
+    void *sentinel_sub(void *p)
+    {
+        return p - 2 * size_t.sizeof;
+    }
+}
+else
+{
+    const uint SENTINEL_EXTRA = 0;
+
+
+    void sentinel_init(void *p, size_t size)
+    {
+    }
+
+
+    void sentinel_Invariant(void *p)
+    {
+    }
+
+
+    void *sentinel_add(void *p)
+    {
+        return p;
+    }
+
+
+    void *sentinel_sub(void *p)
+    {
+        return p;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/basic/ldc.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,100 @@
+# Makefile to build the garbage collector D library for Posix
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the garbage collector library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=libdruntime-gc-basic.a
+LIB_MASK=libdruntime-gc-basic*.a
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-O $(ADD_CFLAGS)
+#CFLAGS=-g $(ADD_CFLAGS)
+
+DFLAGS=-release -O -inline -w $(ADD_DFLAGS)
+#DFLAGS=-g -w $(ADD_DFLAGS)
+
+TFLAGS=-O -inline -w $(ADD_DFLAGS)
+#TFLAGS=-g -w $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=gcc
+LC=$(AR) -qsv
+DC=ldc2
+
+LIB_DEST=../../../lib
+
+.SUFFIXES: .s .S .c .cpp .d .html .o
+
+.s.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.S.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.o:
+	g++ -c $(CFLAGS) $< -o$@
+
+.d.o:
+	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+#	$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
+
+targets : lib doc
+all     : lib doc
+lib     : basic.lib
+doc     : basic.doc
+
+######################################################
+
+ALL_OBJS= \
+    gc.o \
+    gcalloc.o \
+    gcbits.o \
+    gcstats.o \
+    gcx.o
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+basic.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) $@ $(ALL_OBJS)
+
+basic.doc : $(ALL_DOCS)
+	echo No documentation available.
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/basic/posix.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,100 @@
+# Makefile to build the garbage collector D library for Posix
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the garbage collector library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=libdruntime-gc-basic.a
+LIB_MASK=libdruntime-gc-basic*.a
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-O $(ADD_CFLAGS)
+#CFLAGS=-g $(ADD_CFLAGS)
+
+DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
+#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
+#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=gcc
+LC=$(AR) -qsv
+DC=dmd
+
+LIB_DEST=../../../lib
+
+.SUFFIXES: .s .S .c .cpp .d .html .o
+
+.s.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.S.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.o:
+	g++ -c $(CFLAGS) $< -o$@
+
+.d.o:
+	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+#	$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
+
+targets : lib doc
+all     : lib doc
+lib     : basic.lib
+doc     : basic.doc
+
+######################################################
+
+ALL_OBJS= \
+    gc.o \
+    gcalloc.o \
+    gcbits.o \
+    gcstats.o \
+    gcx.o
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+basic.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) $@ $(ALL_OBJS)
+
+basic.doc : $(ALL_DOCS)
+	echo No documentation available.
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/basic/win32.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,97 @@
+# Makefile to build the garbage collector D library for Win32
+# Designed to work with DigitalMars make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the garbage collector library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=druntime-gc-basic.lib
+LIB_MASK=druntime-gc-basic*.lib
+
+CP=xcopy /y
+RM=del /f
+MD=mkdir
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-mn -6 -r $(ADD_CFLAGS)
+#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS)
+
+DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
+#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+TFLAGS=-O -inline -w  -nofloat $(ADD_DFLAGS)
+#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=dmc
+LC=lib
+DC=dmd
+
+LIB_DEST=..\..\..\lib
+
+.DEFAULT: .asm .c .cpp .d .html .obj
+
+.asm.obj:
+	$(CC) -c $<
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.obj:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.d.obj:
+	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+#	$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
+
+targets : lib doc
+all     : lib doc
+lib     : basic.lib
+doc     : basic.doc
+
+######################################################
+
+ALL_OBJS= \
+    gc.obj \
+    gcalloc.obj \
+    gcbits.obj \
+    gcstats.obj \
+    gcx.obj
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+basic.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) -c -n $@ $(ALL_OBJS)
+
+basic.doc : $(ALL_DOCS)
+	@echo No documentation available.
+
+######################################################
+
+clean :
+	$(RM) /s *.di
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)\.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/stub/gc.d	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,182 @@
+/**
+ * This module contains a minimal garbage collector implementation according to
+ * published requirements.  This library is mostly intended to serve as an
+ * example, but it is usable in applications which do not rely on a garbage
+ * collector to clean up memory (ie. when dynamic array resizing is not used,
+ * and all memory allocated with 'new' is freed deterministically with
+ * 'delete').
+ *
+ * Please note that block attribute data must be tracked, or at a minimum, the
+ * FINALIZE bit must be tracked for any allocated memory block because calling
+ * rt_finalize on a non-object block can result in an access violation.  In the
+ * allocator below, this tracking is done via a leading uint bitmask.  A real
+ * allocator may do better to store this data separately, similar to the basic
+ * GC.
+ *
+ * Copyright: Public Domain
+ * License:   Public Domain
+ * Authors:   Sean Kelly
+ */
+
+module gc.gc;
+
+private import stdc.stdlib;
+
+private
+{
+   enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    struct BlkInfo
+    {
+        void*  base;
+        size_t size;
+        uint   attr;
+    }
+
+    extern (C) void thread_init();
+    extern (C) void onOutOfMemoryError();
+}
+
+extern (C) void gc_init()
+{
+    // NOTE: The GC must initialize the thread library before its first
+    //       collection, and always before returning from gc_init().
+    thread_init();
+}
+
+extern (C) void gc_term()
+{
+
+}
+
+extern (C) void gc_enable()
+{
+
+}
+
+extern (C) void gc_disable()
+{
+
+}
+
+extern (C) void gc_collect()
+{
+
+}
+
+extern (C) void gc_minimize()
+{
+
+}
+
+extern (C) uint gc_getAttr( void* p )
+{
+    return 0;
+}
+
+extern (C) uint gc_setAttr( void* p, uint a )
+{
+    return 0;
+}
+
+extern (C) uint gc_clrAttr( void* p, uint a )
+{
+    return 0;
+}
+
+extern (C) void* gc_malloc( size_t sz, uint ba = 0 )
+{
+    void* p = malloc( sz );
+
+    if( sz && p is null )
+        onOutOfMemoryError();
+    return p;
+}
+
+extern (C) void* gc_calloc( size_t sz, uint ba = 0 )
+{
+    void* p = calloc( 1, sz );
+
+    if( sz && p is null )
+        onOutOfMemoryError();
+    return p;
+}
+
+extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 )
+{
+    p = realloc( p, sz );
+
+    if( sz && p is null )
+        onOutOfMemoryError();
+    return p;
+}
+
+extern (C) size_t gc_extend( void* p, size_t mx, size_t sz )
+{
+    return 0;
+}
+
+extern (C) size_t gc_reserve( size_t sz )
+{
+    return 0;
+}
+
+extern (C) void gc_free( void* p )
+{
+    free( p );
+}
+
+extern (C) void* gc_addrOf( void* p )
+{
+    return null;
+}
+
+extern (C) size_t gc_sizeOf( void* p )
+{
+    return 0;
+}
+
+extern (C) BlkInfo gc_query( void* p )
+{
+    return BlkInfo.init;
+}
+
+extern (C) void gc_addRoot( void* p )
+{
+
+}
+
+extern (C) void gc_addRange( void* p, size_t sz )
+{
+
+}
+
+extern (C) void gc_removeRoot( void *p )
+{
+
+}
+
+extern (C) void gc_removeRange( void *p )
+{
+
+}
+
+extern (C) void* gc_getHandle()
+{
+    return null;
+}
+
+extern (C) void gc_setHandle(void* p)
+{
+}
+
+extern (C) void gc_endHandle()
+{
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/stub/ldc.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,98 @@
+# Makefile to build the garbage collector D library for Posix
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the garbage collector library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=druntime-gc-stub.a
+LIB_MASK=druntime-gc-stub*.a
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-O -m32 $(ADD_CFLAGS)
+#CFLAGS=-g -m32 $(ADD_CFLAGS)
+
+### warnings disabled because gcx has issues ###
+
+DFLAGS=-release -O -inline $(ADD_DFLAGS)
+#DFLAGS=-g $(ADD_DFLAGS)
+
+TFLAGS=-O -inline $(ADD_DFLAGS)
+#TFLAGS=-g $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=gcc
+LC=$(AR) -qsv
+DC=ldc2
+
+LIB_DEST=..
+
+.SUFFIXES: .s .S .c .cpp .d .html .o
+
+.s.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.S.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.o:
+	g++ -c $(CFLAGS) $< -o$@
+
+.d.o:
+	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+#	$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
+
+targets : lib doc
+all     : lib doc
+lib     : stub.lib
+doc     : stub.doc
+
+######################################################
+
+ALL_OBJS= \
+    gc.o
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+stub.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) $@ $(ALL_OBJS)
+
+stub.doc : $(ALL_DOCS)
+	echo No documentation available.
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/stub/posix.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,98 @@
+# Makefile to build the garbage collector D library for Posix
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the garbage collector library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=druntime-gc-stub.a
+LIB_MASK=druntime-gc-stub*.a
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-O -m32 $(ADD_CFLAGS)
+#CFLAGS=-g -m32 $(ADD_CFLAGS)
+
+### warnings disabled because gcx has issues ###
+
+DFLAGS=-release -O -inline $(ADD_DFLAGS)
+#DFLAGS=-g $(ADD_DFLAGS)
+
+TFLAGS=-O -inline $(ADD_DFLAGS)
+#TFLAGS=-g $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=gcc
+LC=$(AR) -qsv
+DC=dmd
+
+LIB_DEST=..
+
+.SUFFIXES: .s .S .c .cpp .d .html .o
+
+.s.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.S.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.o:
+	g++ -c $(CFLAGS) $< -o$@
+
+.d.o:
+	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+#	$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
+
+targets : lib doc
+all     : lib doc
+lib     : stub.lib
+doc     : stub.doc
+
+######################################################
+
+ALL_OBJS= \
+    gc.o
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+stub.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) $@ $(ALL_OBJS)
+
+stub.doc : $(ALL_DOCS)
+	echo No documentation available.
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/gc/stub/win32.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,96 @@
+# Makefile to build the garbage collector D library for Win32
+# Designed to work with DigitalMars make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the garbage collector library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=druntime-gc-stub.lib
+LIB_MASK=druntime-gc-stub*.lib
+
+CP=xcopy /y
+RM=del /f
+MD=mkdir
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+CFLAGS=-mn -6 -r $(ADD_CFLAGS)
+#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS)
+
+### warnings disabled because gcx has issues ###
+
+DFLAGS=-release -O -inline $(ADD_DFLAGS)
+#DFLAGS=-g -release $(ADD_DFLAGS)
+
+TFLAGS=-O -inline $(ADD_DFLAGS)
+#TFLAGS=-g $(ADD_DFLAGS)
+
+DOCFLAGS=-version=DDoc
+
+CC=dmc
+LC=lib
+DC=dmd
+
+LIB_DEST=..\..\..\lib
+
+.DEFAULT: .asm .c .cpp .d .html .obj
+
+.asm.obj:
+	$(CC) -c $<
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.cpp.obj:
+	$(CC) -c $(CFLAGS) $< -o$@
+
+.d.obj:
+	$(DC) -c $(DFLAGS) $< -of$@
+
+.d.html:
+	$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
+#	$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
+
+targets : lib doc
+all     : lib doc
+lib     : stub.lib
+doc     : stub.doc
+
+######################################################
+
+ALL_OBJS= \
+    gc.obj
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+stub.lib : $(LIB_TARGET)
+
+$(LIB_TARGET) : $(ALL_OBJS)
+	$(RM) $@
+	$(LC) -c -n $@ $(ALL_OBJS)
+
+stub.doc : $(ALL_DOCS)
+	@echo No documentation available.
+
+######################################################
+
+clean :
+	$(RM) /s *.di
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	$(RM) $(LIB_MASK)
+
+install :
+	$(MD) $(LIB_DEST)
+	$(CP) $(LIB_MASK) $(LIB_DEST)\.
+	copy gc.obj $(LIB_DEST)\gcstub.obj
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/ldc-gcc.mak	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,78 @@
+# Makefile to build the composite D runtime library for Linux
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make lib
+#		Build the runtime library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete unneeded files created by build process
+
+LIB_TARGET=libdruntime-ldc.a
+DUP_TARGET=libdruntime.a
+LIB_MASK=libdruntime*.a
+
+DIR_CC=common
+DIR_RT=compiler/ldc
+DIR_GC=gc/basic
+
+CP=cp -f
+RM=rm -f
+MD=mkdir -p
+
+CC=gcc
+LC=$(AR) -qsv
+DC=ldc2
+
+LIB_DEST=../lib
+
+ADD_CFLAGS=
+ADD_DFLAGS=
+
+targets : lib doc
+all     : lib doc
+
+######################################################
+
+ALL_OBJS=
+
+######################################################
+
+ALL_DOCS=
+
+######################################################
+
+lib : $(ALL_OBJS)
+	make -C $(DIR_CC) -fldc.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	make -C $(DIR_RT) -fldc.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	make -C $(DIR_GC) -fldc.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)"
+	$(RM) $(LIB_TARGET)
+	$(LC) $(LIB_TARGET) `find $(DIR_CC) -name "*.o" | xargs echo`
+	$(LC) $(LIB_TARGET) `find $(DIR_RT) -name "*.o" | xargs echo`
+	$(LC) $(LIB_TARGET) `find $(DIR_GC) -name "*.o" | xargs echo`
+	$(RM) $(DUP_TARGET)
+	$(CP) $(LIB_TARGET) $(DUP_TARGET)
+
+doc : $(ALL_DOCS)
+	make -C $(DIR_CC) -fldc.mak doc DC=$(DC)
+	make -C $(DIR_RT) -fldc.mak doc DC=$(DC)
+	make -C $(DIR_GC) -fldc.mak doc DC=$(DC)
+
+######################################################
+
+clean :
+	find . -name "*.di" | xargs $(RM)
+	$(RM) $(ALL_OBJS)
+	$(RM) $(ALL_DOCS)
+	make -C $(DIR_CC) -fldc.mak clean
+	make -C $(DIR_RT) -fldc.mak clean
+	make -C $(DIR_GC) -fldc.mak clean
+	$(RM) $(LIB_MASK)
+
+install :
+	make -C $(DIR_CC) -fldc.mak install
+	make -C $(DIR_RT) -fldc.mak install
+	make -C $(DIR_GC) -fldc.mak install
+	$(CP) $(LIB_MASK) $(LIB_DEST)/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/ldc2.conf	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,2 @@
+[Environment]
+DFLAGS="-I%HOME%/common" "-I%HOME%/../import"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/sc.ini	Tue Nov 11 01:52:37 2008 +0100
@@ -0,0 +1,7 @@
+[Version]
+version=7.51 Build 020
+
+[Environment]
+LIB=%@P%\..\lib;\dm\lib
+DFLAGS="-I%HOME%\common" "-I%HOME%\..\import"
+LINKCMD=%@P%\..\..\dm\bin\link.exe