changeset 768:85e2093edd73

Updated runtime README a bit. Messed up the druntime patch earlier :/
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Wed, 12 Nov 2008 06:26:45 +0100
parents eb1ce70ee01c
children 038ea84f2d9d
files runtime/README runtime/ldc2.diff
diffstat 2 files changed, 12826 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/README	Wed Nov 12 05:43:12 2008 +0100
+++ b/runtime/README	Wed Nov 12 06:26:45 2008 +0100
@@ -1,32 +1,40 @@
+This should help get the runtime built.
 FOR D1:
 =======
-1) Do a checkout of tango trunk in the ldc root dir (along dmd, gen, runtime etc).
+1) Do a checkout of tango trunk into the ldc root dir (along dmd, gen, runtime etc).
 
-    *    svn co http://svn.dsource.org/projects/tango/trunk ../tango
+    *   $ ls
+    *   dmd dmd2 gen ir ...
+    *   $ svn co http://svn.dsource.org/projects/tango/trunk tango
 
 2) Patch the runtime
 
-    *    sh patch-tango.sh
+    *   cd runtime
+    *   sh patch-tango.sh
 
 3) Compile the runtime
 
-    *    sh build.sh
+    *   sh build.sh
 
 FOR D2:
 =======
 Highly experimental!!!
 
-1) Do a checkout of druntime trunk in the ldc root dir (along dmd, gen, runtime etc).
+1) Do a checkout of druntime trunk into the ldc root dir (along dmd, gen, runtime etc).
 
-    *    svn co http://svn.dsource.org/projects/druntime/trunk ../druntime
+    *   $ ls
+    *   dmd dmd2 gen ir ...
+    *   $ svn co http://svn.dsource.org/projects/druntime/trunk druntime
 
 2) Patch druntime
 
-    *    sh patch-druntime.sh
+    *   cd runtime
+    *   sh patch-druntime.sh
 
 3) Compile druntime
 
-    *    cd ../druntime/src
-    *    sh build-ldc.sh
+    *   cd ../druntime/src
+    *   sh build-ldc.sh
 
+=======
 Enjoy!
--- a/runtime/ldc2.diff	Wed Nov 12 05:43:12 2008 +0100
+++ b/runtime/ldc2.diff	Wed Nov 12 06:26:45 2008 +0100
@@ -177,6 +177,181 @@
          else version( AsmPPC_Posix )
          {
              version( StackGrowsDown )
+Index: src/common/ldc.mak
+===================================================================
+--- src/common/ldc.mak	(revision 0)
++++ src/common/ldc.mak	(revision 0)
+@@ -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= \
++    core/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)/{} \;
+Index: src/build-ldc.sh
+===================================================================
+--- src/build-ldc.sh	(revision 0)
++++ src/build-ldc.sh	(revision 0)
+@@ -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.mak              || goerror
++make lib doc install -fldc.mak $@ || goerror
++make clean -fldc.mak              || goerror
++chmod 644 ../import/*.di          || goerror
++
++export HOME=$OLDHOME
+Index: src/ldc2.conf
+===================================================================
+--- src/ldc2.conf	(revision 0)
++++ src/ldc2.conf	(revision 0)
+@@ -0,0 +1,2 @@
++[Environment]
++DFLAGS="-I%HOME%/common" "-I%HOME%/../import"
 Index: src/gc/basic/gcx.d
 ===================================================================
 --- src/gc/basic/gcx.d	(revision 46)
@@ -230,6 +405,12258 @@
          stackBottom = cast(char*)&dummy;
          log_init();
          debug (THREADINVARIANT)
+Index: src/gc/basic/ldc.mak
+===================================================================
+--- src/gc/basic/ldc.mak	(revision 0)
++++ src/gc/basic/ldc.mak	(revision 0)
+@@ -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 -disable-invariants $(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)/.
+Index: src/gc/stub/ldc.mak
+===================================================================
+--- src/gc/stub/ldc.mak	(revision 0)
++++ src/gc/stub/ldc.mak	(revision 0)
+@@ -0,0 +1,97 @@
++# 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-stub.a
++LIB_MASK=libdruntime-gc-stub*.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     : 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)/.
+Index: src/compiler/ldc/adi.d
+===================================================================
+--- src/compiler/ldc/adi.d	(revision 0)
++++ src/compiler/ldc/adi.d	(revision 0)
+@@ -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 core.stdc.stdlib;
++    import core.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");
++}
+Index: src/compiler/ldc/lifetime.d
+===================================================================
+--- src/compiler/ldc/lifetime.d	(revision 0)
++++ src/compiler/ldc/lifetime.d	(revision 0)
+@@ -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 core.stdc.stdlib;
++    import core.stdc.string;
++    import core.stdc.stdarg;
++    debug(PRINTF) import core.stdc.stdio;
++    else debug(PRINTF2) import core.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);
++}
+Index: src/compiler/ldc/switch.d
+===================================================================
+--- src/compiler/ldc/switch.d	(revision 0)
++++ src/compiler/ldc/switch.d	(revision 0)
+@@ -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 core.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;
++    }
++}
+Index: src/compiler/ldc/arrayInit.d
+===================================================================
+--- src/compiler/ldc/arrayInit.d	(revision 0)
++++ src/compiler/ldc/arrayInit.d	(revision 0)
+@@ -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;
++}
+Index: src/compiler/ldc/genobj.d
+===================================================================
+--- src/compiler/ldc/genobj.d	(revision 0)
++++ src/compiler/ldc/genobj.d	(revision 0)
+@@ -0,0 +1,1527 @@
++/**
++ * 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;
++
++//debug = PRINTF;
++
++private
++{
++    import core.stdc.string;
++    import core.stdc.stdlib;
++    import util.string;
++    debug(PRINTF) import core.stdc.stdio;
++
++    extern (C) void onOutOfMemoryError();
++    extern (C) Object _d_allocclass(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_allocclass(this);
++        // initialize it
++        (cast(byte*) o)[0 .. init.length] = init[];
++
++        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;
++            }
++        }
++    }
++}
+Index: src/compiler/ldc/mars.h
+===================================================================
+--- src/compiler/ldc/mars.h	(revision 0)
++++ src/compiler/ldc/mars.h	(revision 0)
+@@ -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
++
+Index: src/compiler/ldc/aApplyR.d
+===================================================================
+--- src/compiler/ldc/aApplyR.d	(revision 0)
++++ src/compiler/ldc/aApplyR.d	(revision 0)
+@@ -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);
++}
++
++
+Index: src/compiler/ldc/memory.d
+===================================================================
+--- src/compiler/ldc/memory.d	(revision 0)
++++ src/compiler/ldc/memory.d	(revision 0)
+@@ -0,0 +1,323 @@
++/**
++ * 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 core.sys.posix.unistd;
++    private import core.sys.posix.fcntl;
++    private import core.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 core.sys.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( D_InlineAsm_X86 )
++    {
++        asm
++        {
++            naked;
++            mov EAX, ESP;
++            ret;
++        }
++    }
++    else
++    {
++        return llvm_frameaddress();
++    }
++}
++
++
++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 core.stdc.stdlib;
++        else
++        private import tango.stdc.stdlib;
++    }
++
++    extern (C) void gc_addRange( void* p, size_t sz );
++    extern (C) void gc_removeRange( void *p );
++}
++
++
++void initStaticDataGC()
++{
++    enum 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 )
++    {
++        void* start = adjust_up( &Data_Start );
++        void* end = adjust_down( &Data_End );
++        gc_addRange(start, cast(size_t)end - cast(size_t)start);
++    }
++    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;
++
++        void* dataStart = adjust_up( &Data_Start );
++        void* dataEnd = adjust_down( &Data_End );
++
++        gc_addRange(dataStart, cast(size_t)dataEnd - cast(size_t)dataStart);
++
++        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);
++                                gc_addRange(start, cast(size_t)end - cast(size_t)start);
++                            }
++                        }
++                        p++;
++                    }
++                    else
++                    {
++                        count = p - s;
++                        memmove(buf.ptr, s, count);
++                        p = buf.ptr + count;
++                        break;
++                    }
++                }
++            }
++            close(fd);
++        }
++    }
++    else version(linux)
++    {
++        void* start = adjust_up( &Data_Start );
++        void* end = adjust_down( &Data_End );
++        gc_addRange(start, cast(size_t)end - cast(size_t)start);
++    }
++    else
++    {
++        static assert( false, "Operating system not supported." );
++    }
++}
+Index: src/compiler/ldc/dmain2.d
+===================================================================
+--- src/compiler/ldc/dmain2.d	(revision 0)
++++ src/compiler/ldc/dmain2.d	(revision 0)
+@@ -0,0 +1,378 @@
++/*
++ * Placed into the Public Domain.
++ * written by Walter Bright
++ * www.digitalmars.com
++ */
++
++/*
++ *  Modified by Sean Kelly for use with the D Runtime Project
++ */
++
++/*
++ * Modified by Tomas Lindquist Olsen for use with the LLVM D Compiler
++ */
++
++module rt.dmain2;
++
++private
++{
++    import memory;
++    import util.console;
++    import core.stdc.stddef;
++    import core.stdc.stdlib;
++    import core.stdc.string;
++}
++
++version (Windows)
++{
++    extern (Windows) alias int function() FARPROC;
++    extern (Windows) FARPROC    GetProcAddress(void*, in char*);
++    extern (Windows) void*      LoadLibraryA(in char*);
++    extern (Windows) int        FreeLibrary(void*);
++    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 are a temporary means of providing a GC hook for DLL use.  They may be
++ * replaced with some other similar functionality later.
++ */
++extern (C)
++{
++    void* gc_getProxy();
++    void  gc_setProxy(void* p);
++    void  gc_clrProxy();
++
++    alias void* function()      gcGetFn;
++    alias void  function(void*) gcSetFn;
++    alias void  function()      gcClrFn;
++}
++
++extern (C) void* rt_loadLibrary(in char[] name)
++{
++    version (Windows)
++    {
++        char[260] temp = void;
++        temp[0 .. name.length] = name[];
++        temp[name.length] = cast(char) 0;
++        void* ptr = LoadLibraryA(temp.ptr);
++        if (ptr is null)
++            return ptr;
++        gcSetFn gcSet = cast(gcSetFn) GetProcAddress(ptr, "gc_setProxy");
++        if (gcSet !is null)
++            gcSet(gc_getProxy());
++        return ptr;
++
++    }
++    else version (linux)
++    {
++        throw new Exception("rt_loadLibrary not yet implemented on linux.");
++    }
++}
++
++extern (C) bool rt_unloadLibrary(void* ptr)
++{
++    version (Windows)
++    {
++        gcClrFn gcClr  = cast(gcClrFn) GetProcAddress(ptr, "gc_clrProxy");
++        if (gcClr !is null)
++            gcClr();
++        return FreeLibrary(ptr) != 0;
++    }
++    else version (linux)
++    {
++        throw new Exception("rt_unloadLibrary not yet implemented on linux.");
++    }
++}
++
++/***********************************
++ * 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 onRangeError(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)
++{
++    onRangeError(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();
++        initStaticDataGC();
++        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(scope 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();
++        initStaticDataGC();
++        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;
++}
+Index: src/compiler/ldc/typeinfo/ti_void.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_void.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_void.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_wchar.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_wchar.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_wchar.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_ptr.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_ptr.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_ptr.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_Afloat.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Afloat.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Afloat.d	(revision 0)
+@@ -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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_double.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_double.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_double.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_delegate.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_delegate.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_delegate.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_Adouble.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Adouble.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Adouble.d	(revision 0)
+@@ -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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_char.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_char.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_char.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_Acdouble.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Acdouble.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Acdouble.d	(revision 0)
+@@ -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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_uint.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_uint.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_uint.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_AC.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_AC.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_AC.d	(revision 0)
+@@ -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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_ulong.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_ulong.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_ulong.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_creal.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_creal.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_creal.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_ubyte.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_ubyte.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_ubyte.d	(revision 0)
+@@ -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"; }
++}
+Index: src/compiler/ldc/typeinfo/ti_Aint.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Aint.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Aint.d	(revision 0)
+@@ -0,0 +1,129 @@
++
++module rt.typeinfo.ti_Aint;
++
++private import core.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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_ireal.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_ireal.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_ireal.d	(revision 0)
+@@ -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"; }
++}
+Index: src/compiler/ldc/typeinfo/ti_long.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_long.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_long.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_short.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_short.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_short.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_Along.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Along.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Along.d	(revision 0)
+@@ -0,0 +1,109 @@
++
++module rt.typeinfo.ti_Along;
++
++private import core.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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_byte.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_byte.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_byte.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_float.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_float.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_float.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_cfloat.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_cfloat.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_cfloat.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_Acfloat.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Acfloat.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Acfloat.d	(revision 0)
+@@ -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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_cdouble.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_cdouble.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_cdouble.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_ifloat.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_ifloat.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_ifloat.d	(revision 0)
+@@ -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"; }
++}
+Index: src/compiler/ldc/typeinfo/ti_dchar.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_dchar.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_dchar.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_C.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_C.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_C.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_real.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_real.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_real.d	(revision 0)
+@@ -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];
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_idouble.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_idouble.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_idouble.d	(revision 0)
+@@ -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"; }
++}
+Index: src/compiler/ldc/typeinfo/ti_Areal.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Areal.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Areal.d	(revision 0)
+@@ -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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_ushort.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_ushort.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_ushort.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_Ag.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Ag.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Ag.d	(revision 0)
+@@ -0,0 +1,204 @@
++
++module rt.typeinfo.ti_Ag;
++
++private import util.string;
++private import core.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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_Acreal.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Acreal.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Acreal.d	(revision 0)
+@@ -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);
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_int.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_int.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_int.d	(revision 0)
+@@ -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;
++    }
++}
+Index: src/compiler/ldc/typeinfo/ti_Ashort.d
+===================================================================
+--- src/compiler/ldc/typeinfo/ti_Ashort.d	(revision 0)
++++ src/compiler/ldc/typeinfo/ti_Ashort.d	(revision 0)
+@@ -0,0 +1,132 @@
++
++module rt.typeinfo.ti_Ashort;
++
++private import core.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);
++    }
++}
+Index: src/compiler/ldc/ldc/vararg.d
+===================================================================
+--- src/compiler/ldc/ldc/vararg.d	(revision 0)
++++ src/compiler/ldc/ldc/vararg.d	(revision 0)
+@@ -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;
++}
+Index: src/compiler/ldc/ldc/bitmanip.d
+===================================================================
+--- src/compiler/ldc/ldc/bitmanip.d	(revision 0)
++++ src/compiler/ldc/ldc/bitmanip.d	(revision 0)
+@@ -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"); }
+Index: src/compiler/ldc/aaA.d
+===================================================================
+--- src/compiler/ldc/aaA.d	(revision 0)
++++ src/compiler/ldc/aaA.d	(revision 0)
+@@ -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 core.stdc.stdarg;
++    import core.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;
++}
++
+++/
+Index: src/compiler/ldc/aApply.d
+===================================================================
+--- src/compiler/ldc/aApply.d	(revision 0)
++++ src/compiler/ldc/aApply.d	(revision 0)
+@@ -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;
++}
+Index: src/compiler/ldc/monitor.c
+===================================================================
+--- src/compiler/ldc/monitor.c	(revision 0)
++++ src/compiler/ldc/monitor.c	(revision 0)
+@@ -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
+Index: src/compiler/ldc/ldc.mak
+===================================================================
+--- src/compiler/ldc/ldc.mak	(revision 0)
++++ src/compiler/ldc/ldc.mak	(revision 0)
+@@ -0,0 +1,166 @@
++# 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-ldc.a
++LIB_MASK=libdruntime-rt-ldc*.a
++
++CP=cp -f
++RM=rm -f
++MD=mkdir -p
++
++#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
++IMPORT_DEST=../../../import/
++
++.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     : ldc.lib
++doc     : ldc.doc
++
++######################################################
++
++OBJ_BASE= \
++    aaA.o \
++    aApply.o \
++    aApplyR.o \
++    adi.o \
++    arrayInit.o \
++    cast.o \
++    critical.o \
++    eh.o \
++    dmain2.o \
++    invariant.o \
++    lifetime.o \
++    memory.o \
++    monitor.o \
++    genobj.o \
++    qsort2.o \
++    switch.o
++
++OBJ_UTIL= \
++    util/console.o \
++    util/ctype.o \
++    util/string.o \
++    util/utf.o \
++    ldc/bitmanip.o \
++    ldc/vararg.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=
++
++######################################################
++
++ldc.lib : $(LIB_TARGET)
++
++$(LIB_TARGET) : $(ALL_OBJS)
++	$(RM) $@
++	$(LC) $@ $(ALL_OBJS)
++
++ldc.doc : $(ALL_DOCS)
++	echo No documentation available.
++
++################### LDC SPECIALS #####################
++
++ldc/bitmanip.o : ldc/bitmanip.d
++	$(DC) -c $(DFLAGS) -d -Hf$(IMPORT_DEST)/$*.di ldc/bitmanip.d -of$@
++
++ldc/vararg.o : ldc/vararg.d
++	$(DC) -c $(DFLAGS) -d -Hf$(IMPORT_DEST)/$*.di ldc/vararg.d -of$@
++
++######################################################
++
++clean :
++	find . -name "*.di" | xargs $(RM)
++	$(RM) $(ALL_OBJS)
++	$(RM) $(ALL_DOCS)
++	$(RM) $(LIB_MASK)
++
++install :
++	$(MD) $(LIB_DEST)
++	$(CP) $(LIB_MASK) $(LIB_DEST)/.
+Index: src/compiler/ldc/critical.c
+===================================================================
+--- src/compiler/ldc/critical.c	(revision 0)
++++ src/compiler/ldc/critical.c	(revision 0)
+@@ -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
++
+Index: src/compiler/ldc/qsort2.d
+===================================================================
+--- src/compiler/ldc/qsort2.d	(revision 0)
++++ src/compiler/ldc/qsort2.d	(revision 0)
+@@ -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 = core.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]);
++    }
++}
+Index: src/compiler/ldc/cast.d
+===================================================================
+--- src/compiler/ldc/cast.d	(revision 0)
++++ src/compiler/ldc/cast.d	(revision 0)
+@@ -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);
++}
+Index: src/compiler/ldc/util/utf.d
+===================================================================
+--- src/compiler/ldc/util/utf.d	(revision 0)
++++ src/compiler/ldc/util/utf.d	(revision 0)
+@@ -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",
++    ];
++