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",
++    ];
++
++    for (int j = 0; j < s4.length; j++)
++    {
++	try
++	{
++	    i = 0;
++	    c = decode(s4[j], i);
++	    assert(0);
++	}
++	catch (Object o)
++	{
++	    i = 23;
++	}
++	assert(i == 23);
++    }
++}
++
++/** ditto */
++
++dchar decode(in wchar[] s, inout size_t idx)
++    in
++    {
++	assert(idx >= 0 && idx < s.length);
++    }
++    out (result)
++    {
++	assert(isValidDchar(result));
++    }
++    body
++    {
++	string msg;
++	dchar V;
++	size_t i = idx;
++	uint u = s[i];
++
++	if (u & ~0x7F)
++	{   if (u >= 0xD800 && u <= 0xDBFF)
++	    {   uint u2;
++
++		if (i + 1 == s.length)
++		{   msg = "surrogate UTF-16 high value past end of string";
++		    goto Lerr;
++		}
++		u2 = s[i + 1];
++		if (u2 < 0xDC00 || u2 > 0xDFFF)
++		{   msg = "surrogate UTF-16 low value out of range";
++		    goto Lerr;
++		}
++		u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
++		i += 2;
++	    }
++	    else if (u >= 0xDC00 && u <= 0xDFFF)
++	    {   msg = "unpaired surrogate UTF-16 value";
++		goto Lerr;
++	    }
++	    else if (u == 0xFFFE || u == 0xFFFF)
++	    {   msg = "illegal UTF-16 value";
++		goto Lerr;
++	    }
++	    else
++		i++;
++	}
++	else
++	{
++	    i++;
++	}
++
++	idx = i;
++	return cast(dchar)u;
++
++      Lerr:
++	  onUnicodeError(msg, i);
++	return cast(dchar)u; // dummy return
++    }
++
++/** ditto */
++
++dchar decode(in dchar[] s, inout size_t idx)
++    in
++    {
++	assert(idx >= 0 && idx < s.length);
++    }
++    body
++    {
++	size_t i = idx;
++	dchar c = s[i];
++
++	if (!isValidDchar(c))
++	    goto Lerr;
++	idx = i + 1;
++	return c;
++
++      Lerr:
++	  onUnicodeError("invalid UTF-32 value", i);
++	return c; // dummy return
++    }
++
++
++/* =================== Encode ======================= */
++
++/*******************************
++ * Encodes character c and appends it to array s[].
++ */
++void encode(inout char[] s, dchar c)
++    in
++    {
++	assert(isValidDchar(c));
++    }
++    body
++    {
++	char[] r = s;
++
++	if (c <= 0x7F)
++	{
++	    r ~= cast(char) c;
++	}
++	else
++	{
++	    char[4] buf;
++	    uint L;
++
++	    if (c <= 0x7FF)
++	    {
++		buf[0] = cast(char)(0xC0 | (c >> 6));
++		buf[1] = cast(char)(0x80 | (c & 0x3F));
++		L = 2;
++	    }
++	    else if (c <= 0xFFFF)
++	    {
++		buf[0] = cast(char)(0xE0 | (c >> 12));
++		buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
++		buf[2] = cast(char)(0x80 | (c & 0x3F));
++		L = 3;
++	    }
++	    else if (c <= 0x10FFFF)
++	    {
++		buf[0] = cast(char)(0xF0 | (c >> 18));
++		buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
++		buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
++		buf[3] = cast(char)(0x80 | (c & 0x3F));
++		L = 4;
++	    }
++	    else
++	    {
++		assert(0);
++	    }
++	    r ~= buf[0 .. L];
++	}
++	s = r;
++    }
++
++unittest
++{
++    debug(utf) printf("utf.encode.unittest\n");
++
++    char[] s = "abcd".dup;
++    encode(s, cast(dchar)'a');
++    assert(s.length == 5);
++    assert(s == "abcda");
++
++    encode(s, cast(dchar)'\u00A9');
++    assert(s.length == 7);
++    assert(s == "abcda\xC2\xA9");
++    //assert(s == "abcda\u00A9");	// BUG: fix compiler
++
++    encode(s, cast(dchar)'\u2260');
++    assert(s.length == 10);
++    assert(s == "abcda\xC2\xA9\xE2\x89\xA0");
++}
++
++/** ditto */
++
++void encode(inout wchar[] s, dchar c)
++    in
++    {
++	assert(isValidDchar(c));
++    }
++    body
++    {
++	wchar[] r = s;
++
++	if (c <= 0xFFFF)
++	{
++	    r ~= cast(wchar) c;
++	}
++	else
++	{
++	    wchar[2] buf;
++
++	    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
++	    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
++	    r ~= buf;
++	}
++	s = r;
++    }
++
++/** ditto */
++void encode(inout dchar[] s, dchar c)
++    in
++    {
++	assert(isValidDchar(c));
++    }
++    body
++    {
++	s ~= c;
++    }
++
++/**
++Returns the code length of $(D c) in the encoding using $(D C) as a
++code point. The code is returned in character count, not in bytes.
++ */
++
++ubyte codeLength(C)(dchar c)
++{
++
++    static if (C.sizeof == 1)
++    {
++        return
++            c <= 0x7F ? 1
++            : c <= 0x7FF ? 2
++            : c <= 0xFFFF ? 3
++            : c <= 0x10FFFF ? 4
++            : (assert(false), 6);
++}
++
++    else static if (C.sizeof == 2)
++{
++	return c <= 0xFFFF ? 1 : 2;
++    }
++    else
++    {
++        static assert(C.sizeof == 4);
++        return 1;
++    }
++}
++
++/* =================== Validation ======================= */
++
++/***********************************
++Checks to see if string is well formed or not. $(D S) can be an array
++ of $(D char), $(D wchar), or $(D dchar). Throws a $(D UtfException)
++ if it is not. Use to check all untrusted input for correctness.
++ */
++void validate(S)(in S s)
++{
++    auto len = s.length;
++    for (size_t i = 0; i < len; )
++    {
++	decode(s, i);
++    }
++}
++
++/* =================== Conversion to UTF8 ======================= */
++
++char[] toUTF8(char[4] buf, dchar c)
++    in
++    {
++	assert(isValidDchar(c));
++    }
++    body
++    {
++	if (c <= 0x7F)
++	{
++	    buf[0] = cast(char) c;
++	    return buf[0 .. 1];
++	}
++	else if (c <= 0x7FF)
++	{
++	    buf[0] = cast(char)(0xC0 | (c >> 6));
++	    buf[1] = cast(char)(0x80 | (c & 0x3F));
++	    return buf[0 .. 2];
++	}
++	else if (c <= 0xFFFF)
++	{
++	    buf[0] = cast(char)(0xE0 | (c >> 12));
++	    buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
++	    buf[2] = cast(char)(0x80 | (c & 0x3F));
++	    return buf[0 .. 3];
++	}
++	else if (c <= 0x10FFFF)
++	{
++	    buf[0] = cast(char)(0xF0 | (c >> 18));
++	    buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
++	    buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
++	    buf[3] = cast(char)(0x80 | (c & 0x3F));
++	    return buf[0 .. 4];
++	}
++	assert(0);
++    }
++
++/*******************
++ * Encodes string s into UTF-8 and returns the encoded string.
++ */
++string toUTF8(string s)
++    in
++    {
++	validate(s);
++    }
++    body
++    {
++	return s;
++    }
++
++/** ditto */
++string toUTF8(in wchar[] s)
++{
++    char[] r;
++    size_t i;
++    size_t slen = s.length;
++
++    r.length = slen;
++
++    for (i = 0; i < slen; i++)
++    {	wchar c = s[i];
++
++	if (c <= 0x7F)
++	    r[i] = cast(char)c;		// fast path for ascii
++	else
++	{
++	    r.length = i;
++	    foreach (dchar c; s[i .. slen])
++	    {
++		encode(r, c);
++	    }
++	    break;
++	}
++    }
++    return cast(string)r;
++}
++
++/** ditto */
++string toUTF8(in dchar[] s)
++{
++    char[] r;
++    size_t i;
++    size_t slen = s.length;
++
++    r.length = slen;
++
++    for (i = 0; i < slen; i++)
++    {	dchar c = s[i];
++
++	if (c <= 0x7F)
++	    r[i] = cast(char)c;		// fast path for ascii
++	else
++	{
++	    r.length = i;
++	    foreach (dchar d; s[i .. slen])
++	    {
++		encode(r, d);
++	    }
++	    break;
++	}
++    }
++    return cast(string)r;
++}
++
++/* =================== Conversion to UTF16 ======================= */
++
++wchar[] toUTF16(wchar[2] buf, dchar c)
++    in
++    {
++	assert(isValidDchar(c));
++    }
++    body
++    {
++	if (c <= 0xFFFF)
++	{
++	    buf[0] = cast(wchar) c;
++	    return buf[0 .. 1];
++	}
++	else
++	{
++	    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
++	    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
++	    return buf[0 .. 2];
++	}
++    }
++
++/****************
++ * Encodes string s into UTF-16 and returns the encoded string.
++ * toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take
++ * an LPWSTR or LPCWSTR argument.
++ */
++wstring toUTF16(in char[] s)
++{
++    wchar[] r;
++    size_t slen = s.length;
++
++    r.length = slen;
++    r.length = 0;
++    for (size_t i = 0; i < slen; )
++    {
++	dchar c = s[i];
++	if (c <= 0x7F)
++	{
++	    i++;
++	    r ~= cast(wchar)c;
++	}
++	else
++	{
++	    c = decode(s, i);
++	    encode(r, c);
++	}
++    }
++    return cast(wstring)r;
++}
++
++alias const(wchar)* wptr;
++/** ditto */
++wptr toUTF16z(in char[] s)
++{
++    wchar[] r;
++    size_t slen = s.length;
++
++    r.length = slen + 1;
++    r.length = 0;
++    for (size_t i = 0; i < slen; )
++    {
++	dchar c = s[i];
++	if (c <= 0x7F)
++	{
++	    i++;
++	    r ~= cast(wchar)c;
++	}
++	else
++	{
++	    c = decode(s, i);
++	    encode(r, c);
++	}
++    }
++    r ~= "\000";
++    return r.ptr;
++}
++
++/** ditto */
++wstring toUTF16(wstring s)
++    in
++    {
++	validate(s);
++    }
++    body
++    {
++	return s;
++    }
++
++/** ditto */
++wstring toUTF16(in dchar[] s)
++{
++    wchar[] r;
++    size_t slen = s.length;
++
++    r.length = slen;
++    r.length = 0;
++    for (size_t i = 0; i < slen; i++)
++    {
++	encode(r, s[i]);
++    }
++    return cast(wstring)r;
++}
++
++/* =================== Conversion to UTF32 ======================= */
++
++/*****
++ * Encodes string s into UTF-32 and returns the encoded string.
++ */
++dstring toUTF32(in char[] s)
++{
++    dchar[] r;
++    size_t slen = s.length;
++    size_t j = 0;
++
++    r.length = slen;		// r[] will never be longer than s[]
++    for (size_t i = 0; i < slen; )
++    {
++	dchar c = s[i];
++	if (c >= 0x80)
++	    c = decode(s, i);
++	else
++	    i++;		// c is ascii, no need for decode
++	r[j++] = c;
++    }
++    return cast(dstring)r[0 .. j];
++}
++
++/** ditto */
++dstring toUTF32(in wchar[] s)
++{
++    dchar[] r;
++    size_t slen = s.length;
++    size_t j = 0;
++
++    r.length = slen;		// r[] will never be longer than s[]
++    for (size_t i = 0; i < slen; )
++    {
++	dchar c = s[i];
++	if (c >= 0x80)
++	    c = decode(s, i);
++	else
++	    i++;		// c is ascii, no need for decode
++	r[j++] = c;
++    }
++    return cast(dstring)r[0 .. j];
++}
++
++/** ditto */
++dstring toUTF32(dstring s)
++    in
++    {
++	validate(s);
++    }
++    body
++    {
++	return s;
++    }
++
++/* ================================ tests ================================== */
++
++unittest
++{
++    debug(utf) printf("utf.toUTF.unittest\n");
++
++    auto c = "hello"c;
++    auto w = toUTF16(c);
++    assert(w == "hello");
++    auto d = toUTF32(c);
++    assert(d == "hello");
++
++    c = toUTF8(w);
++    assert(c == "hello");
++    d = toUTF32(w);
++    assert(d == "hello");
++
++    c = toUTF8(d);
++    assert(c == "hello");
++    w = toUTF16(d);
++    assert(w == "hello");
++
++
++    c = "hel\u1234o";
++    w = toUTF16(c);
++    assert(w == "hel\u1234o");
++    d = toUTF32(c);
++    assert(d == "hel\u1234o");
++
++    c = toUTF8(w);
++    assert(c == "hel\u1234o");
++    d = toUTF32(w);
++    assert(d == "hel\u1234o");
++
++    c = toUTF8(d);
++    assert(c == "hel\u1234o");
++    w = toUTF16(d);
++    assert(w == "hel\u1234o");
++
++
++    c = "he\U0010AAAAllo";
++    w = toUTF16(c);
++    //foreach (wchar c; w) printf("c = x%x\n", c);
++    //foreach (wchar c; cast(wstring)"he\U0010AAAAllo") printf("c = x%x\n", c);
++    assert(w == "he\U0010AAAAllo");
++    d = toUTF32(c);
++    assert(d == "he\U0010AAAAllo");
++
++    c = toUTF8(w);
++    assert(c == "he\U0010AAAAllo");
++    d = toUTF32(w);
++    assert(d == "he\U0010AAAAllo");
++
++    c = toUTF8(d);
++    assert(c == "he\U0010AAAAllo");
++    w = toUTF16(d);
++    assert(w == "he\U0010AAAAllo");
++}
+Index: src/compiler/ldc/util/console.d
+===================================================================
+--- src/compiler/ldc/util/console.d	(revision 0)
++++ src/compiler/ldc/util/console.d	(revision 0)
+@@ -0,0 +1,49 @@
++/**
++ * The console module contains some simple routines for console output.
++ *
++ * Copyright: Public Domain
++ * License:   Public Domain
++ * Authors:   Sean Kelly
++ */
++module rt.util.console;
++
++
++private
++{
++    version (Windows)
++    {
++        import core.sys.windows.windows;
++    }
++    else version( Posix )
++    {
++        import core.sys.posix.unistd;
++    }
++    import util.string;
++}
++
++
++struct Console
++{
++    Console opCall( in char[] val )
++    {
++        version( Windows )
++        {
++            uint count = void;
++            WriteFile( GetStdHandle( 0xfffffff5 ), val.ptr, val.length, &count, null );
++        }
++        else version( Posix )
++        {
++            write( 2, val.ptr, val.length );
++        }
++        return *this;
++    }
++
++
++    Console opCall( uint val )
++    {
++            char[10] tmp = void;
++            return opCall( tmp.intToString( val ) );
++    }
++}
++
++Console console;
+Index: src/compiler/ldc/util/ctype.d
+===================================================================
+--- src/compiler/ldc/util/ctype.d	(revision 0)
++++ src/compiler/ldc/util/ctype.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.
++ */
++
++// Simple ASCII char classification functions
++
++module rt.util.ctype;
++
++int isalnum(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG) : 0; }
++int isalpha(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP)      : 0; }
++int iscntrl(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_CTL)      : 0; }
++int isdigit(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_DIG)      : 0; }
++int islower(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_LC)       : 0; }
++int ispunct(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_PNC)      : 0; }
++int isspace(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_SPC)      : 0; }
++int isupper(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_UC)       : 0; }
++int isxdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_HEX)      : 0; }
++int isgraph(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC) : 0; }
++int isprint(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC|_BLK) : 0; }
++int isascii(dchar c)  { return c <= 0x7F; }
++
++dchar tolower(dchar c)
++    out (result)
++    {
++	assert(!isupper(result));
++    }
++    body
++    {
++	return isupper(c) ? c + (cast(dchar)'a' - 'A') : c;
++    }
++
++dchar toupper(dchar c)
++    out (result)
++    {
++	assert(!islower(result));
++    }
++    body
++    {
++	return islower(c) ? c - (cast(dchar)'a' - 'A') : c;
++    }
++
++private:
++
++enum
++{
++    _SPC =	8,
++    _CTL =	0x20,
++    _BLK =	0x40,
++    _HEX =	0x80,
++    _UC  =	1,
++    _LC  =	2,
++    _PNC =	0x10,
++    _DIG =	4,
++    _ALP =	_UC|_LC,
++}
++
++ubyte _ctype[128] =
++[
++	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
++	_CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL,
++	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
++	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
++	_SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
++	_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
++	_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
++	_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
++	_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
++	_PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC,
++	_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
++	_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
++	_UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC,
++	_PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC,
++	_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
++	_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
++	_LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL
++];
++
++
++unittest
++{
++    assert(isspace(' '));
++    assert(!isspace('z'));
++    assert(toupper('a') == 'A');
++    assert(tolower('Q') == 'q');
++    assert(!isxdigit('G'));
++}
+Index: src/compiler/ldc/util/string.d
+===================================================================
+--- src/compiler/ldc/util/string.d	(revision 0)
++++ src/compiler/ldc/util/string.d	(revision 0)
+@@ -0,0 +1,35 @@
++/**
++ * The exception module defines all system-level exceptions and provides a
++ * mechanism to alter system-level error handling.
++ *
++ * Copyright: Copyright (c) 2005-2008, The D Runtime Project
++ * License:   BSD Style, see LICENSE
++ * Authors:   Sean Kelly
++ */
++module rt.util.string;
++
++private import core.stdc.string;
++
++char[] intToString( char[] buf, uint val )
++{
++    assert( buf.length > 9 );
++    auto p = buf.ptr + buf.length;
++
++    do
++    {
++        *--p = cast(char)(val % 10 + '0');
++    } while( val /= 10 );
++
++    return buf[p - buf.ptr .. $];
++}
++
++
++int dstrcmp( in char[] s1, in char[] s2 )
++{
++    auto len = s1.length;
++    if( s2.length < len )
++        len = s2.length;
++    if( memcmp( s1.ptr, s2.ptr, len ) == 0 )
++        return 0;
++    return s1.length > s2.length ? 1 : -1;
++}
+Index: src/compiler/ldc/invariant.d
+===================================================================
+--- src/compiler/ldc/invariant.d	(revision 0)
++++ src/compiler/ldc/invariant.d	(revision 0)
+@@ -0,0 +1,25 @@
++
++/*
++ * Placed into the Public Domain
++ * written by Walter Bright
++ * www.digitalmars.com
++ */
++
++extern(C) void _d_invariant(Object o)
++{   ClassInfo c;
++
++    //printf("__d_invariant(%p)\n", o);
++
++    // BUG: needs to be filename/line of caller, not library routine
++    assert(o !is null);	// just do null check, not invariant check
++
++    c = o.classinfo;
++    do
++    {
++	if (c.classInvariant)
++	{
++	    (*c.classInvariant)(o);
++	}
++	c = c.base;
++    } while (c);
++}
+Index: src/compiler/ldc/eh.d
+===================================================================
+--- src/compiler/ldc/eh.d	(revision 0)
++++ src/compiler/ldc/eh.d	(revision 0)
+@@ -0,0 +1,388 @@
++/**
++ * This module contains functions and structures required for
++ * exception handling.
++ */
++module eh;
++
++import util.console;
++import ldc.cstdarg;
++
++// debug = EH_personality;
++
++// current EH implementation works on x86
++// if it has a working unwind runtime
++version(X86) {
++    version(linux) version=X86_UNWIND;
++    version(darwin) version=X86_UNWIND;
++}
++version(X86_64) {
++    version(linux) version=X86_UNWIND;
++}
++
++private extern(C) void abort();
++private extern(C) int printf(in char*, ...);
++private extern(C) int vprintf(in char*, va_list va);
++
++// D runtime functions
++extern(C) {
++    int _d_isbaseof(ClassInfo oc, ClassInfo c);
++}
++
++// libunwind headers
++extern(C)
++{
++    enum _Unwind_Reason_Code
++    {
++        NO_REASON = 0,
++        FOREIGN_EXCEPTION_CAUGHT = 1,
++        FATAL_PHASE2_ERROR = 2,
++        FATAL_PHASE1_ERROR = 3,
++        NORMAL_STOP = 4,
++        END_OF_STACK = 5,
++        HANDLER_FOUND = 6,
++        INSTALL_CONTEXT = 7,
++        CONTINUE_UNWIND = 8
++    }
++
++    enum _Unwind_Action
++    {
++        SEARCH_PHASE = 1,
++        CLEANUP_PHASE = 2,
++        HANDLER_PHASE = 3,
++        FORCE_UNWIND = 4
++    }
++
++    alias void* _Unwind_Context_Ptr;
++
++    alias void function(_Unwind_Reason_Code, _Unwind_Exception*) _Unwind_Exception_Cleanup_Fn;
++
++    struct _Unwind_Exception
++    {
++        char[8] exception_class;
++        _Unwind_Exception_Cleanup_Fn exception_cleanup;
++        int private_1;
++        int private_2;
++    }
++
++version(X86_UNWIND) 
++{
++    void _Unwind_Resume(_Unwind_Exception*);
++    _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*);
++    ulong _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context);
++    ulong _Unwind_GetIP(_Unwind_Context_Ptr context);
++    ulong _Unwind_SetIP(_Unwind_Context_Ptr context, ulong new_value);
++    ulong _Unwind_SetGR(_Unwind_Context_Ptr context, int index, ulong new_value);
++    ulong _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
++}
++else
++{
++    // runtime calls these directly
++    void _Unwind_Resume(_Unwind_Exception*)
++    {
++        console("_Unwind_Resume is not implemented on this platform.\n");
++    }
++    _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*)
++    {
++        console("_Unwind_RaiseException is not implemented on this platform.\n");
++        return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
++    }
++}
++
++}
++
++// error and exit
++extern(C) private void fatalerror(in char* format, ...)
++{
++  va_list args;
++  va_start(args, format);
++  printf("Fatal error in EH code: ");
++  vprintf(format, args);
++  printf("\n");
++  abort();
++}
++
++
++// helpers for reading certain DWARF data
++private ubyte* get_uleb128(ubyte* addr, ref size_t res)
++{
++  res = 0;
++  size_t bitsize = 0;
++
++  // read as long as high bit is set
++  while(*addr & 0x80) {
++    res |= (*addr & 0x7f) << bitsize;
++    bitsize += 7;
++    addr += 1;
++    if(bitsize >= size_t.sizeof*8)
++       fatalerror("tried to read uleb128 that exceeded size of size_t");
++  }
++  // read last
++  if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
++    fatalerror("Fatal error in EH code: tried to read uleb128 that exceeded size of size_t");
++  res |= (*addr) << bitsize;
++
++  return addr + 1;
++}
++
++private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res)
++{
++  res = 0;
++  size_t bitsize = 0;
++
++  // read as long as high bit is set
++  while(*addr & 0x80) {
++    res |= (*addr & 0x7f) << bitsize;
++    bitsize += 7;
++    addr += 1;
++    if(bitsize >= size_t.sizeof*8)
++       fatalerror("tried to read sleb128 that exceeded size of size_t");
++  }
++  // read last
++  if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
++    fatalerror("tried to read sleb128 that exceeded size of size_t");
++  res |= (*addr) << bitsize;
++
++  // take care of sign
++  if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40))
++    res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1);
++
++  return addr + 1;
++}
++
++
++// exception struct used by the runtime.
++// _d_throw allocates a new instance and passes the address of its
++// _Unwind_Exception member to the unwind call. The personality
++// routine is then able to get the whole struct by looking at the data
++// surrounding the unwind info.
++struct _d_exception
++{
++  Object exception_object;
++  _Unwind_Exception unwind_info;
++}
++
++// the 8-byte string identifying the type of exception
++// the first 4 are for vendor, the second 4 for language
++//TODO: This may be the wrong way around
++char[8] _d_exception_class = "LLDCD1\0\0";
++
++
++//
++// x86 unwind specific implementation of personality function
++// and helpers
++//
++version(X86_UNWIND)
++{
++
++// the personality routine gets called by the unwind handler and is responsible for
++// reading the EH tables and deciding what to do
++extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context)
++{
++  // check ver: the C++ Itanium ABI only allows ver == 1
++  if(ver != 1)
++    return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
++
++  // check exceptionClass
++  //TODO: Treat foreign exceptions with more respect
++  if((cast(char*)&exception_class)[0..8] != _d_exception_class)
++    return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
++
++  // find call site table, action table and classinfo table
++  // Note: callsite and action tables do not contain static-length
++  // data and will be parsed as needed
++  // Note: classinfo_table points past the end of the table
++  ubyte* callsite_table;
++  ubyte* action_table;
++  ClassInfo* classinfo_table;
++  _d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table);
++
++
++  /*
++    find landing pad and action table index belonging to ip by walking
++    the callsite_table
++  */
++  ubyte* callsite_walker = callsite_table;
++
++  // get the instruction pointer
++  // will be used to find the right entry in the callsite_table
++  // -1 because it will point past the last instruction
++  ulong ip = _Unwind_GetIP(context) - 1;
++
++  // address block_start is relative to
++  ulong region_start = _Unwind_GetRegionStart(context);
++
++  // table entries
++  uint block_start_offset, block_size;
++  ulong landing_pad;
++  size_t action_offset;
++
++  while(true) {
++    // if we've gone through the list and found nothing...
++    if(callsite_walker >= action_table)
++      return _Unwind_Reason_Code.CONTINUE_UNWIND;
++
++    block_start_offset = *cast(uint*)callsite_walker;
++    block_size = *(cast(uint*)callsite_walker + 1);
++    landing_pad = *(cast(uint*)callsite_walker + 2);
++    if(landing_pad)
++      landing_pad += region_start;
++    callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset);
++
++    debug(EH_personality_verbose) printf("%d %d %d\n", block_start_offset, block_size, landing_pad);
++
++    // since the list is sorted, as soon as we're past the ip
++    // there's no handler to be found
++    if(ip < region_start + block_start_offset)
++      return _Unwind_Reason_Code.CONTINUE_UNWIND;
++
++    // if we've found our block, exit
++    if(ip < region_start + block_start_offset + block_size)
++      break;
++  }
++
++  debug(EH_personality) printf("Found correct landing pad and actionOffset %d\n", action_offset);
++
++  // now we need the exception's classinfo to find a handler
++  // the exception_info is actually a member of a larger _d_exception struct
++  // the runtime allocated. get that now
++  _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof);
++
++  // if there's no action offset and no landing pad, continue unwinding
++  if(!action_offset && !landing_pad)
++    return _Unwind_Reason_Code.CONTINUE_UNWIND;
++
++  // if there's no action offset but a landing pad, this is a cleanup handler
++  else if(!action_offset && landing_pad)
++    return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
++
++  /*
++   walk action table chain, comparing classinfos using _d_isbaseof
++  */
++  ubyte* action_walker = action_table + action_offset - 1;
++
++  ptrdiff_t ti_offset, next_action_offset;
++  while(true) {
++    action_walker = get_sleb128(action_walker, ti_offset);
++    // it is intentional that we not modify action_walker here
++    // next_action_offset is from current action_walker position
++    get_sleb128(action_walker, next_action_offset);
++
++    // negative are 'filters' which we don't use
++    if(!(ti_offset >= 0))
++      fatalerror("Filter actions are unsupported");
++
++    // zero means cleanup, which we require to be the last action
++    if(ti_offset == 0) {
++      if(!(next_action_offset == 0))
++        fatalerror("Cleanup action must be last in chain");
++      return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
++    }
++
++    // get classinfo for action and check if the one in the
++    // exception structure is a base
++    ClassInfo catch_ci = classinfo_table[-ti_offset];
++    debug(EH_personality) printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr);
++    if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci))
++      return _d_eh_install_catch_context(actions, ti_offset, landing_pad, exception_struct, context);
++
++    // we've walked through all actions and found nothing...
++    if(next_action_offset == 0)
++      return _Unwind_Reason_Code.CONTINUE_UNWIND;
++    else
++      action_walker += next_action_offset;
++  }
++
++  fatalerror("reached unreachable");
++  return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
++}
++
++// These are the register numbers for SetGR that
++// llvm's eh.exception and eh.selector intrinsics
++// will pick up.
++// Found by trial-and-error :/
++version (X86_64)
++{
++  private int eh_exception_regno = 3;
++  private int eh_selector_regno = 1;
++} else {
++  private int eh_exception_regno = 0;
++  private int eh_selector_regno = 2;
++}
++
++private _Unwind_Reason_Code _d_eh_install_catch_context(_Unwind_Action actions, ptrdiff_t switchval, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
++{
++  debug(EH_personality) printf("Found catch clause!\n");
++
++  if(actions & _Unwind_Action.SEARCH_PHASE)
++    return _Unwind_Reason_Code.HANDLER_FOUND;
++
++  else if(actions & _Unwind_Action.HANDLER_PHASE)
++  {
++    debug(EH_personality) printf("Setting switch value to: %d!\n", switchval);
++    _Unwind_SetGR(context, eh_exception_regno, cast(ulong)cast(void*)(exception_struct.exception_object));
++    _Unwind_SetGR(context, eh_selector_regno, switchval);
++    _Unwind_SetIP(context, landing_pad);
++    return _Unwind_Reason_Code.INSTALL_CONTEXT;
++  }
++
++  fatalerror("reached unreachable");
++  return _Unwind_Reason_Code.FATAL_PHASE2_ERROR;
++}
++
++private _Unwind_Reason_Code _d_eh_install_finally_context(_Unwind_Action actions, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
++{
++  // if we're merely in search phase, continue
++  if(actions & _Unwind_Action.SEARCH_PHASE)
++    return _Unwind_Reason_Code.CONTINUE_UNWIND;
++
++  debug(EH_personality) printf("Calling cleanup routine...\n");
++
++  _Unwind_SetGR(context, eh_exception_regno, cast(ulong)exception_struct);
++  _Unwind_SetGR(context, eh_selector_regno, 0);
++  _Unwind_SetIP(context, landing_pad);
++  return _Unwind_Reason_Code.INSTALL_CONTEXT;
++}
++
++private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci)
++{
++  ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
++
++  //TODO: Do proper DWARF reading here
++  if(*data++ != 0xff)
++    fatalerror("DWARF header has unexpected format 1");
++
++  if(*data++ != 0x00)
++    fatalerror("DWARF header has unexpected format 2");
++  size_t cioffset;
++  data = get_uleb128(data, cioffset);
++  ci = cast(ClassInfo*)(data + cioffset);
++
++  if(*data++ != 0x03)
++    fatalerror("DWARF header has unexpected format 3");
++  size_t callsitelength;
++  data = get_uleb128(data, callsitelength);
++  action = data + callsitelength;
++
++  callsite = data;
++}
++
++} // end of x86 Linux specific implementation
++
++
++extern(C) void _d_throw_exception(Object e)
++{
++    if (e !is null)
++    {
++        _d_exception* exc_struct = new _d_exception;
++        exc_struct.unwind_info.exception_class[] = _d_exception_class;
++        exc_struct.exception_object = e;
++        _Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info);
++        console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
++    }
++    abort();
++}
++
++extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct)
++{
++  _Unwind_Resume(&exception_struct.unwind_info);
++}
 Index: import/object.di
 ===================================================================
 --- import/object.di	(revision 46)
@@ -248,6 +12675,388 @@
      static int opApply(int delegate(inout ModuleInfo));
  }
  
+Index: import/ldc/intrinsics.di
+===================================================================
+--- import/ldc/intrinsics.di	(revision 0)
++++ import/ldc/intrinsics.di	(revision 0)
+@@ -0,0 +1,343 @@
++/*
++ * This module holds declarations to LLVM intrinsics.
++ *
++ * See the LLVM language reference for more information:
++ *
++ * - http://llvm.org/docs/LangRef.html#intrinsics
++ *
++ */
++
++module ldc.intrinsics;
++
++// Check for the right compiler
++version(LDC)
++{
++    // OK
++}
++else
++{
++    static assert(false, "This module is only valid for LDC");
++}
++
++//
++// CODE GENERATOR INTRINSICS
++//
++
++
++// The 'llvm.returnaddress' intrinsic attempts to compute a target-specific value indicating the return address of the current function or one of its callers. 
++
++pragma(intrinsic, "llvm.returnaddress")
++    void* llvm_returnaddress(uint level);
++
++
++// The 'llvm.frameaddress' intrinsic attempts to return the target-specific frame pointer value for the specified stack frame. 
++
++pragma(intrinsic, "llvm.frameaddress")
++    void* llvm_frameaddress(uint level);
++
++
++// The 'llvm.stacksave' intrinsic is used to remember the current state of the function stack, for use with llvm.stackrestore. This is useful for implementing language features like scoped automatic variable sized arrays in C99. 
++
++pragma(intrinsic, "llvm.stacksave")
++    void* llvm_stacksave();
++
++
++// The 'llvm.stackrestore' intrinsic is used to restore the state of the function stack to the state it was in when the corresponding llvm.stacksave intrinsic executed. This is useful for implementing language features like scoped automatic variable sized arrays in C99. 
++
++pragma(intrinsic, "llvm.stackrestore")
++    void llvm_stackrestore(void* ptr);
++
++
++// The 'llvm.prefetch' intrinsic is a hint to the code generator to insert a prefetch instruction if supported; otherwise, it is a noop. Prefetches have no effect on the behavior of the program but can change its performance characteristics.
++
++pragma(intrinsic, "llvm.prefetch")
++    void llvm_prefetch(void* ptr, uint rw, uint locality);
++
++
++// The 'llvm.pcmarker' intrinsic is a method to export a Program Counter (PC) in a region of code to simulators and other tools. The method is target specific, but it is expected that the marker will use exported symbols to transmit the PC of the marker. The marker makes no guarantees that it will remain with any specific instruction after optimizations. It is possible that the presence of a marker will inhibit optimizations. The intended use is to be inserted after optimizations to allow correlations of simulation runs. 
++
++pragma(intrinsic, "llvm.pcmarker")
++    void llvm_pcmarker(uint id);
++
++
++// The 'llvm.readcyclecounter' intrinsic provides access to the cycle counter register (or similar low latency, high accuracy clocks) on those targets that support it. On X86, it should map to RDTSC. On Alpha, it should map to RPCC. As the backing counters overflow quickly (on the order of 9 seconds on alpha), this should only be used for small timings. 
++
++pragma(intrinsic, "llvm.readcyclecounter")
++    ulong readcyclecounter();
++
++
++
++
++//
++// STANDARD C LIBRARY INTRINSICS
++//
++
++
++// The 'llvm.memcpy.*' intrinsics copy a block of memory from the source location to the destination location.
++// Note that, unlike the standard libc function, the llvm.memcpy.* intrinsics do not return a value, and takes an extra alignment argument.
++
++pragma(intrinsic, "llvm.memcpy.i32")
++    void llvm_memcpy_i32(void* dst, void* src, uint len, uint alignment);
++pragma(intrinsic, "llvm.memcpy.i64")
++    void llvm_memcpy_i64(void* dst, void* src, ulong len, uint alignment);
++
++
++// The 'llvm.memmove.*' intrinsics move a block of memory from the source location to the destination location. It is similar to the 'llvm.memcpy' intrinsic but allows the two memory locations to overlap.
++// Note that, unlike the standard libc function, the llvm.memmove.* intrinsics do not return a value, and takes an extra alignment argument.
++
++pragma(intrinsic, "llvm.memmove.i32")
++    void llvm_memmove_i32(void* dst, void* src, uint len, uint alignment);
++pragma(intrinsic, "llvm.memmove.i64")
++    void llvm_memmove_i64(void* dst, void* src, ulong len, int alignment);
++
++
++// The 'llvm.memset.*' intrinsics fill a block of memory with a particular byte value.
++// Note that, unlike the standard libc function, the llvm.memset intrinsic does not return a value, and takes an extra alignment argument.
++
++pragma(intrinsic, "llvm.memset.i32")
++    void llvm_memset_i32(void* dst, ubyte val, uint len, uint alignment);
++pragma(intrinsic, "llvm.memset.i64")
++    void llvm_memset_i64(void* dst, ubyte val, ulong len, uint alignment);
++
++
++// The 'llvm.sqrt' intrinsics return the sqrt of the specified operand, returning the same value as the libm 'sqrt' functions would. Unlike sqrt in libm, however, llvm.sqrt has undefined behavior for negative numbers other than -0.0 (which allows for better optimization, because there is no need to worry about errno being set). llvm.sqrt(-0.0) is defined to return -0.0 like IEEE sqrt. 
++
++pragma(intrinsic, "llvm.sqrt.f32")
++    float llvm_sqrt_f32(float val);
++pragma(intrinsic, "llvm.sqrt.f64")
++    double llvm_sqrt_f64(double val);
++version(X86)
++{
++pragma(intrinsic, "llvm.sqrt.f80")
++    real llvm_sqrt_f80(real val);
++}
++
++version(X86_64)
++{
++pragma(intrinsic, "llvm.sqrt.f80")
++    real llvm_sqrt_f80(real val);
++}
++
++
++// The 'llvm.sin.*' intrinsics return the sine of the operand. 
++
++pragma(intrinsic, "llvm.sin.f32")
++    float llvm_sin_f32(float val);
++pragma(intrinsic, "llvm.sin.f64")
++    double llvm_sin_f64(double val);
++version(X86)
++{
++pragma(intrinsic, "llvm.sin.f80")
++    real llvm_sin_f80(real val);
++}
++
++version(X86_64)
++{
++pragma(intrinsic, "llvm.sin.f80")
++    real llvm_sin_f80(real val);
++}
++
++
++// The 'llvm.cos.*' intrinsics return the cosine of the operand. 
++
++pragma(intrinsic, "llvm.cos.f32")
++    float llvm_cos_f32(float val);
++pragma(intrinsic, "llvm.cos.f64")
++    double llvm_cos_f64(double val);
++version(X86)
++{
++pragma(intrinsic, "llvm.cos.f80")
++    real llvm_cos_f80(real val);
++}
++
++version(X86_64)
++{
++pragma(intrinsic, "llvm.cos.f80")
++    real llvm_cos_f80(real val);
++}
++
++
++// The 'llvm.powi.*' intrinsics return the first operand raised to the specified (positive or negative) power. The order of evaluation of multiplications is not defined. When a vector of floating point type is used, the second argument remains a scalar integer value. 
++
++pragma(intrinsic, "llvm.powi.f32")
++    float llvm_powi_f32(float val, int power);
++
++pragma(intrinsic, "llvm.powi.f64")
++    double llvm_powi_f64(double val, int power);
++version(X86)
++{
++pragma(intrinsic, "llvm.powi.f80")
++    real llvm_powi_f80(real val, int power);
++}
++
++version(X86_64)
++{
++pragma(intrinsic, "llvm.powi.f80")
++    real llvm_powi_f80(real val, int power);
++}
++
++// The 'llvm.pow.*' intrinsics return the first operand raised to the specified (positive or negative) power. 
++
++pragma(intrinsic, "llvm.pow.f32")
++    float llvm_pow_f32(float val, float power);
++
++pragma(intrinsic, "llvm.pow.f64")
++    double llvm_pow_f64(double val, double power);
++version(X86)
++{
++pragma(intrinsic, "llvm.pow.f80")
++    real llvm_pow_f80(real val, real power);
++}
++
++version(X86_64)
++{
++pragma(intrinsic, "llvm.pow.f80")
++    real llvm_pow_f80(real val, real power);
++}
++
++
++//
++// BIT MANIPULATION INTRINSICS
++//
++
++// The 'llvm.bswap' family of intrinsics is used to byte swap integer values with an even number of bytes (positive multiple of 16 bits). These are useful for performing operations on data that is not in the target's native byte order. 
++
++pragma(intrinsic, "llvm.bswap.i16.i16")
++    ushort llvm_bswap_i16(ushort val);
++
++pragma(intrinsic, "llvm.bswap.i32.i32")
++    uint llvm_bswap_i32(uint val);
++
++pragma(intrinsic, "llvm.bswap.i64.i64")
++    ulong llvm_bswap_i64(ulong val);
++
++
++// The 'llvm.ctpop' family of intrinsics counts the number of bits set in a value. 
++
++pragma(intrinsic, "llvm.ctpop.i8")
++    ubyte llvm_ctpop_i8(ubyte src);
++
++pragma(intrinsic, "llvm.ctpop.i16")
++    ushort llvm_ctpop_i16(ushort src);
++
++pragma(intrinsic, "llvm.ctpop.i32")
++    uint llvm_ctpop_i32(uint src);
++
++pragma(intrinsic, "llvm.ctpop.i64")
++    ulong llvm_ctpop_i64(ulong src);
++
++
++// The 'llvm.ctlz' family of intrinsic functions counts the number of leading zeros in a variable. 
++
++pragma(intrinsic, "llvm.ctlz.i8")
++    ubyte llvm_ctlz_i8(ubyte src);
++
++pragma(intrinsic, "llvm.ctlz.i16")
++    ushort llvm_ctlz_i16(ushort src);
++
++pragma(intrinsic, "llvm.ctlz.i32")
++    uint llvm_ctlz_i32(uint src);
++
++pragma(intrinsic, "llvm.ctlz.i64")
++    ulong llvm_ctlz_i64(ulong src);
++
++
++// The 'llvm.cttz' family of intrinsic functions counts the number of trailing zeros. 
++
++pragma(intrinsic, "llvm.cttz.i8")
++    ubyte llvm_cttz_i8(ubyte src);
++
++pragma(intrinsic, "llvm.cttz.i16")
++    ushort llvm_cttz_i16(ushort src);
++
++pragma(intrinsic, "llvm.cttz.i32")
++    uint llvm_cttz_i32(uint src);
++
++pragma(intrinsic, "llvm.cttz.i64")
++    ulong llvm_cttz_i64(ulong src);
++
++
++// The 'llvm.part.select' family of intrinsic functions selects a range of bits from an integer value and returns them in the same bit width as the original value.
++
++pragma(intrinsic, "llvm.part.select.i8")
++    ubyte llvm_part_select_i(ubyte val, uint loBit, uint hiBit);
++
++pragma(intrinsic, "llvm.part.select.i16")
++    ushort llvm_part_select_i(ushort val, uint loBit, uint hiBit);
++
++pragma(intrinsic, "llvm.part.select.i32")
++    uint llvm_part_select_i(uint val, uint loBit, uint hiBit);
++
++pragma(intrinsic, "llvm.part.select.i64")
++    ulong llvm_part_select_i(ulong val, uint loBit, uint hiBit);
++
++
++// The 'llvm.part.set' family of intrinsic functions replaces a range of bits in an integer value with another integer value. It returns the integer with the replaced bits.
++
++// TODO
++// declare i17 @llvm.part.set.i17.i9 (i17 %val, i9 %repl, i32 %lo, i32 %hi)
++// declare i29 @llvm.part.set.i29.i9 (i29 %val, i9 %repl, i32 %lo, i32 %hi)
++
++
++
++
++//
++// ATOMIC OPERATIONS AND SYNCHRONIZATION INTRINSICS
++//
++
++// The llvm.memory.barrier intrinsic guarantees ordering between specific pairs of memory access types.
++
++pragma(intrinsic, "llvm.memory.barrier")
++    void llvm_memory_barrier(bool ll, bool ls, bool sl, bool ss, bool device);
++
++// This loads a value in memory and compares it to a given value. If they are equal, it stores a new value into the memory.
++
++pragma(intrinsic, "llvm.atomic.cmp.swap.i#.p0i#")
++    T llvm_atomic_cmp_swap(T)(T* ptr, T cmp, T val);
++
++// This intrinsic loads the value stored in memory at ptr and yields the value from memory. It then stores the value in val in the memory at ptr.
++
++pragma(intrinsic, "llvm.atomic.swap.i#.p0i#")
++    T llvm_atomic_swap(T)(T* ptr, T val);
++
++// This intrinsic adds delta to the value stored in memory at ptr. It yields the original value at ptr.
++
++pragma(intrinsic, "llvm.atomic.load.add.i#.p0i#")
++    T llvm_atomic_load_add(T)(T* ptr, T val);
++
++// This intrinsic subtracts delta to the value stored in memory at ptr. It yields the original value at ptr.
++
++pragma(intrinsic, "llvm.atomic.load.sub.i#.p0i#")
++    T llvm_atomic_load_sub(T)(T* ptr, T val);
++
++// These intrinsics bitwise the operation (and, nand, or, xor) delta to the value stored in memory at ptr. It yields the original value at ptr.
++
++pragma(intrinsic, "llvm.atomic.load.and.i#.p0i#")
++    T llvm_atomic_load_and(T)(T* ptr, T val);
++pragma(intrinsic, "llvm.atomic.load.nand.i#.p0i#")
++    T llvm_atomic_load_nand(T)(T* ptr, T val);
++pragma(intrinsic, "llvm.atomic.load.or.i#.p0i#")
++    T llvm_atomic_load_or(T)(T* ptr, T val);
++pragma(intrinsic, "llvm.atomic.load.xor.i#.p0i#")
++    T llvm_atomic_load_xor(T)(T* ptr, T val);
++
++// These intrinsics takes the signed or unsigned minimum or maximum of delta and the value stored in memory at ptr. It yields the original value at ptr. 
++
++pragma(intrinsic, "llvm.atomic.load.max.i#.p0i#")
++    T llvm_atomic_load_max(T)(T* ptr, T val);
++pragma(intrinsic, "llvm.atomic.load.min.i#.p0i#")
++    T llvm_atomic_load_min(T)(T* ptr, T val);
++pragma(intrinsic, "llvm.atomic.load.umax.i#.p0i#")
++    T llvm_atomic_load_umax(T)(T* ptr, T val);
++pragma(intrinsic, "llvm.atomic.load.umin.i#.p0i#")
++    T llvm_atomic_load_umin(T)(T* ptr, T val);
++
++//
++// GENERAL INTRINSICS
++//
++
++
++// This intrinsics is lowered to the target dependent trap instruction. If the target does not have a trap instruction, this intrinsic will be lowered to the call of the abort() function. 
++
++pragma(intrinsic, "llvm.trap")
++    void llvm_trap();
+Index: import/ldc/cstdarg.di
+===================================================================
+--- import/ldc/cstdarg.di	(revision 0)
++++ import/ldc/cstdarg.di	(revision 0)
+@@ -0,0 +1,29 @@
++/*
++ * vararg support for extern(C) functions
++ */
++
++module ldc.cstdarg;
++
++// Check for the right compiler
++version(LDC)
++{
++    // OK
++}
++else
++{
++    static assert(false, "This module is only valid for LDC");
++}
++
++alias void* va_list;
++
++pragma(va_start)
++    void va_start(T)(va_list ap, ref T);
++
++pragma(va_arg)
++    T va_arg(T)(va_list ap);
++
++pragma(va_end)
++    void va_end(va_list args);
++
++pragma(va_copy)
++    void va_copy(va_list dst, va_list src);
 Index: import/core/stdc/stdarg.d
 ===================================================================
 --- import/core/stdc/stdarg.d	(revision 46)