diff lphobos/gc/gc.d @ 473:373489eeaf90

Applied downs' lphobos update
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 04 Aug 2008 19:28:49 +0200
parents 5825d48b27d1
children 88e23f8c2354
line wrap: on
line diff
--- a/lphobos/gc/gc.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/gc/gc.d	Mon Aug 04 19:28:49 2008 +0200
@@ -1,151 +1,1028 @@
-/**
- * Part of the D programming language runtime library.
- */
-
-/*
- *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
- *  Written by Walter Bright
- *
- *  This software is provided 'as-is', without any express or implied
- *  warranty. In no event will the authors be held liable for any damages
- *  arising from the use of this software.
- *
- *  Permission is granted to anyone to use this software for any purpose,
- *  including commercial applications, and to alter it and redistribute it
- *  freely, 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.
- */
-
-
-// Storage allocation
-
-module std.gc;
-
-//debug = PRINTF;
-
-public import std.c.stdarg;
-public import std.c.stdlib;
-public import std.c.string;
-public import gcx;
-public import std.outofmemory;
-public import gcstats;
-public import std.thread;
-
-version=GCCLASS;
-
-version (GCCLASS)
-    alias GC gc_t;
-else
-    alias GC* gc_t;
-
-gc_t _gc;
-
-void addRoot(void *p)		      { _gc.addRoot(p); }
-void removeRoot(void *p)	      { _gc.removeRoot(p); }
-void addRange(void *pbot, void *ptop) { _gc.addRange(pbot, ptop); }
-void removeRange(void *pbot)	      { _gc.removeRange(pbot); }
-void fullCollect()		      { _gc.fullCollect(); }
-void fullCollectNoStack()	      { _gc.fullCollectNoStack(); }
-void genCollect()		      { _gc.genCollect(); }
-void minimize()			      { _gc.minimize(); }
-void disable()			      { _gc.disable(); }
-void enable()			      { _gc.enable(); }
-void getStats(out GCStats stats)      { _gc.getStats(stats); }
-void hasPointers(void* p)	      { _gc.hasPointers(p); }
-void hasNoPointers(void* p)	      { _gc.hasNoPointers(p); }
-void setV1_0()			      { _gc.setV1_0(); }
-
-void[] malloc(size_t nbytes)
-{
-    void* p = _gc.malloc(nbytes);
-    return p[0 .. nbytes];
-}
-
-void[] realloc(void* p, size_t nbytes)
-{
-    void* q = _gc.realloc(p, nbytes);
-    return q[0 .. nbytes];
-}
-
-size_t extend(void* p, size_t minbytes, size_t maxbytes)
-{
-    return _gc.extend(p, minbytes, maxbytes);
-}
-
-size_t capacity(void* p)
-{
-    return _gc.capacity(p);
-}
-
-void setTypeInfo(TypeInfo ti, void* p)
-{
-    if (ti.flags() & 1)
-	hasNoPointers(p);
-    else
-	hasPointers(p);
-}
-
-void* getGCHandle()
-{
-    return cast(void*)_gc;
-}
-
-void setGCHandle(void* p)
-{
-    void* oldp = getGCHandle();
-    gc_t g = cast(gc_t)p;
-    if (g.gcversion != gcx.GCVERSION)
-	throw new Error("incompatible gc versions");
-
-    // Add our static data to the new gc
-    GC.scanStaticData(g);
-
-    _gc = g;
-//    return oldp;
-}
-
-void endGCHandle()
-{
-    GC.unscanStaticData(_gc);
-}
-
-extern (C)
-{
-
-void _d_monitorrelease(Object h);
-
-
-void gc_init()
-{
-    version (GCCLASS)
-    {	void* p;
-	ClassInfo ci = GC.classinfo;
-
-	p = std.c.stdlib.malloc(ci.init.length);
-	(cast(byte*)p)[0 .. ci.init.length] = ci.init[];
-	_gc = cast(GC)p;
-    }
-    else
-    {
-	_gc = cast(GC *) std.c.stdlib.calloc(1, GC.sizeof);
-    }
-    _gc.initialize();
-    GC.scanStaticData(_gc);
-    std.thread.Thread.thread_init();
-}
-
-void gc_term()
-{
-    _gc.fullCollectNoStack();
-    _gc.Dtor();
-}
-
-}
+/**
+ * Part of the D programming language runtime library.
+ */
+
+/*
+ *  Copyright (C) 2004-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.
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, February 2007
+*/
+
+
+// Storage allocation
+
+module std.gc;
+
+//debug = PRINTF;
+
+public import std.c.stdarg;
+public import std.c.stdlib;
+public import std.c.string;
+public import gcx;
+public import std.outofmemory;
+public import gcstats;
+public import std.thread;
+
+version=GCCLASS;
+
+version (GCCLASS)
+    alias GC gc_t;
+else
+    alias GC* gc_t;
+
+gc_t _gc;
+
+void addRoot(void *p)		      { _gc.addRoot(p); }
+void removeRoot(void *p)	      { _gc.removeRoot(p); }
+void addRange(void *pbot, void *ptop) { _gc.addRange(pbot, ptop); }
+void removeRange(void *pbot)	      { _gc.removeRange(pbot); }
+void fullCollect()		      { _gc.fullCollect(); }
+void fullCollectNoStack()	      { _gc.fullCollectNoStack(); }
+void genCollect()		      { _gc.genCollect(); }
+void minimize()			      { _gc.minimize(); }
+void disable()			      { _gc.disable(); }
+void enable()			      { _gc.enable(); }
+void getStats(out GCStats stats)      { _gc.getStats(stats); }
+void hasPointers(void* p)	      { _gc.hasPointers(p); }
+void hasNoPointers(void* p)	      { _gc.hasNoPointers(p); }
+void setV1_0()			      { _gc.setV1_0(); }
+
+void[] malloc(size_t nbytes)
+{
+    void* p = _gc.malloc(nbytes);
+    return p[0 .. nbytes];
+}
+
+void[] realloc(void* p, size_t nbytes)
+{
+    void* q = _gc.realloc(p, nbytes);
+    return q[0 .. nbytes];
+}
+
+size_t extend(void* p, size_t minbytes, size_t maxbytes)
+{
+    return _gc.extend(p, minbytes, maxbytes);
+}
+
+size_t capacity(void* p)
+{
+    return _gc.capacity(p);
+}
+
+void setTypeInfo(TypeInfo ti, void* p)
+{
+    if (ti.flags() & 1)
+	hasNoPointers(p);
+    else
+	hasPointers(p);
+}
+
+void* getGCHandle()
+{
+    return cast(void*)_gc;
+}
+
+void setGCHandle(void* p)
+{
+    void* oldp = getGCHandle();
+    gc_t g = cast(gc_t)p;
+    if (g.gcversion != gcx.GCVERSION)
+	throw new Error("incompatible gc versions");
+
+    // Add our static data to the new gc
+    GC.scanStaticData(g);
+
+    _gc = g;
+//    return oldp;
+}
+
+void endGCHandle()
+{
+    GC.unscanStaticData(_gc);
+}
+
+extern (C)
+{
+
+void _d_monitorexit(Object h);
+
+
+void gc_init()
+{
+    version (GCCLASS)
+    {	void* p;
+	ClassInfo ci = GC.classinfo;
+
+	p = std.c.stdlib.malloc(ci.init.length);
+	(cast(byte*)p)[0 .. ci.init.length] = ci.init[];
+	_gc = cast(GC)p;
+    }
+    else
+    {
+	_gc = cast(GC *) std.c.stdlib.calloc(1, GC.sizeof);
+    }
+    _gc.initialize();
+    GC.scanStaticData(_gc);
+    std.thread.Thread.thread_init();
+}
+
+void gc_term()
+{
+    _gc.fullCollectNoStack();
+    _gc.Dtor();
+}
+
+Object _d_newclass(ClassInfo ci)
+{
+    void *p;
+
+    debug(PRINTF) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name);
+    if (ci.flags & 1)			// if COM object
+    {
+	p = std.c.stdlib.malloc(ci.init.length);
+	if (!p)
+	    _d_OutOfMemory();
+	debug(PRINTF) printf(" COM object p = %p\n", p);
+    }
+    else
+    {
+	p = _gc.malloc(ci.init.length);
+	debug(PRINTF) printf(" p = %p\n", p);
+	_gc.setFinalizer(p, &new_finalizer);
+	if (ci.flags & 2)
+	    _gc.hasNoPointers(p);
+    }
+
+    debug (PRINTF)
+    {
+	printf("p = %p\n", p);
+	printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length);
+	printf("vptr = %p\n", *cast(void **)ci.init);
+	printf("vtbl[0] = %p\n", (*cast(void ***)ci.init)[0]);
+	printf("vtbl[1] = %p\n", (*cast(void ***)ci.init)[1]);
+	printf("init[0] = %x\n", (cast(uint *)ci.init)[0]);
+	printf("init[1] = %x\n", (cast(uint *)ci.init)[1]);
+	printf("init[2] = %x\n", (cast(uint *)ci.init)[2]);
+	printf("init[3] = %x\n", (cast(uint *)ci.init)[3]);
+	printf("init[4] = %x\n", (cast(uint *)ci.init)[4]);
+    }
+
+
+    // Initialize it
+    (cast(byte*)p)[0 .. ci.init.length] = ci.init[];
+
+    //printf("initialization done\n");
+    return cast(Object)p;
+}
+
+extern (D) alias void (*fp_t)(Object);		// generic function pointer
+
+void _d_delinterface(void** p)
+{
+    if (*p)
+    {
+	Interface *pi = **cast(Interface ***)*p;
+	Object o;
+
+	o = cast(Object)(*p - pi.offset);
+	_d_delclass(&o);
+	*p = null;
+    }
+}
+
+void _d_delclass(Object *p)
+{
+    if (*p)
+    {
+	debug (PRINTF) printf("_d_delclass(%p)\n", *p);
+	version(0)
+	{
+	    ClassInfo **pc = cast(ClassInfo **)*p;
+	    if (*pc)
+	    {
+		ClassInfo c = **pc;
+
+		if (c.deallocator)
+		{
+		    _d_callfinalizer(cast(void *)(*p));
+		    fp_t fp = cast(fp_t)c.deallocator;
+		    (*fp)(*p);			// call deallocator
+		    *p = null;
+		    return;
+		}
+	    }
+	}
+	_gc.free(cast(void*)(*p));
+	*p = null;
+    }
+}
+
+/******************************************
+ * Allocate a new array of length elements.
+ * ti is the type of the resulting array, or pointer to element.
+ */
+
+/* For when the array is initialized to 0 */
+void* _d_newarrayT(TypeInfo ti, size_t length)
+{
+    void* result;
+    auto size = ti.next.tsize();		// array element size
+
+    debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size);
+    if (length && size)
+    {
+	/*version (D_InlineAsm_X86)
+	{
+	    asm
+	    {
+		mov	EAX,size	;
+		mul	EAX,length	;
+		mov	size,EAX	;
+		jc	Loverflow	;
+	    }
+	}
+	else*/
+	    size *= length;
+	result = cast(byte*) _gc.malloc(size + 1);
+	if (!(ti.next.flags() & 1))
+	    _gc.hasNoPointers(result);
+	memset(result, 0, size);
+    }
+    return result;
+
+Loverflow:
+    _d_OutOfMemory();
+}
+
+/* For when the array has a non-zero initializer.
+ */
+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)
+	{ }
+    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);
+	debug(PRINTF) printf(" p = %p\n", p);
+	if (!(ti.next.flags() & 1))
+	    _gc.hasNoPointers(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 = cast(byte*) p
;
+    }
+    return result;
+
+Loverflow:
+    _d_OutOfMemory();
+}
+
+void[] _d_newarraymTp(TypeInfo ti, int ndims, size_t* pdim)
+{
+    void[] result = void;
+
+    //debug(PRINTF)
+	//printf("_d_newarraymT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+	result = null;
+    else
+    {
+
+	void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+	{
+	    size_t dim = *pdim;
+	    void[] p;
+
+	    //printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
+	    if (ndims == 1)
+	    {
+		auto r = _d_newarrayT(ti, dim);
+		p = *cast(void[]*)(&r);
+	    }
+	    else
+	    {
+		p = _gc.malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+		for (int i = 0; i < dim; i++)
+		{
+		    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+		}
+	    }
+	    return p;
+	}
+
+	result = foo(ti, pdim, ndims);
+	//printf("result = %llx\n", result);
+
+	version (none)
+	{
+	    for (int i = 0; i < ndims; i++)
+	    {
+		printf("index %d: %d\n", i, pdim[i]);
+	    }
+	}
+    }
+    return result;
+}
+
+void[] _d_newarraymiTp(TypeInfo ti, int ndims, size_t* pdim)
+{
+    void[] result = void;
+
+    //debug(PRINTF)
+	//printf("_d_newarraymi(size = %d, ndims = %d)\n", size, ndims);
+    if (ndims == 0)
+	result = null;
+    else
+    {
+
+	void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+	{
+	    size_t dim = *pdim;
+	    void[] p;
+
+	    if (ndims == 1)
+	    {
+		auto r = _d_newarrayiT(ti, dim);
+		p = *cast(void[]*)(&r);
+	    }
+	    else
+	    {
+		p = _gc.malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+		for (int i = 0; i < dim; i++)
+		{
+		    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+		}
+	    }
+	    return p;
+	}
+
+	result = foo(ti, pdim, ndims);
+	//printf("result = %llx\n", result);
+
+	version (none)
+	{
+	    for (int i = 0; i < ndims; i++)
+	    {
+		printf("index %d: %d\n", i, pdim[i]);
+		printf("init = %d\n", *cast(int*)pinit);
+	    }
+	}
+    }
+    return result;
+}
+
+struct Array
+{
+    size_t length;
+    byte *data;
+};
+
+// Perhaps we should get a a size argument like _d_new(), so we
+// can zero out the array?
+
+void _d_delarray(size_t plength, void* pdata)
+{
+    assert(!plength || pdata);
+    if (pdata) _gc.free(pdata);
+}
+
+
+void _d_delmemory(void* *p)
+{
+    if (*p)
+    {
+	_gc.free(*p);
+	*p = null;
+    }
+}
+
+
+}
+
+void new_finalizer(void *p, bool dummy)
+{
+    //printf("new_finalizer(p = %p)\n", p);
+    _d_callfinalizer(p);
+}
+
+extern (C)
+void _d_callinterfacefinalizer(void *p)
+{
+    //printf("_d_callinterfacefinalizer(p = %p)\n", p);
+    if (p)
+    {
+	Interface *pi = **cast(Interface ***)p;
+	Object o = cast(Object)(p - pi.offset);
+	_d_callfinalizer(cast(void*)o);
+    }
+}
+
+extern (C)
+void _d_callfinalizer(void *p)
+{
+    //printf("_d_callfinalizer(p = %p)\n", p);
+    if (p)	// not necessary if called from gc
+    {
+	ClassInfo **pc = cast(ClassInfo **)p;
+	if (*pc)
+	{
+	    ClassInfo c = **pc;
+
+	    try
+	    {
+		do
+		{
+		    if (c.destructor)
+		    {
+			fp_t fp = cast(fp_t)c.destructor;
+			(*fp)(cast(Object)p);		// call destructor
+		    }
+		    c = c.base;
+		} while (c);
+		if ((cast(void**)p)[1])	// if monitor is not null
+		    _d_monitorexit(cast(Object)p);
+	    }
+	    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);
+}
+body
+{
+    byte* newdata;
+    size_t sizeelem = ti.next.tsize();
+
+    debug(PRINTF)
+    {
+	printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
+	if (p)
+	    printf("\tpdata = %p, plength = %d\n", pdata, plength);
+    }
+
+    if (newlength)
+    {
+	version (GNU)
+	{
+	    // required to output the label;
+	    static char x = 0;
+	    if (x)
+		goto Loverflow;
+	}
+
+	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;
+	}
+	//printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+	if (pdata)
+	{
+	    newdata = pdata;
+	    if (newlength > plength)
+	    {
+		size_t size = plength * sizeelem;
+		size_t cap = _gc.capacity(pdata);
+
+		if (cap <= newsize)
+		{
+		    if (cap >= 4096)
+		    {	// Try to extend in-place
+			auto u = _gc.extend(pdata, (newsize + 1) - cap, (newsize + 1) - cap);
+			if (u)
+			{
+			    goto L1;
+			}
+		    }
+		    newdata = cast(byte *)_gc.malloc(newsize + 1);
+		    newdata[0 .. size] = pdata[0 .. size];
+		    if (!(ti.next.flags() & 1))
+			_gc.hasNoPointers(newdata);
+		}
+	     L1:
+		newdata[size .. newsize] = 0;
+	    }
+	}
+	else
+	{
+	    newdata = cast(byte *)_gc.calloc(newsize + 1, 1);
+	    if (!(ti.next.flags() & 1))
+		_gc.hasNoPointers(newdata);
+	}
+    }
+    else
+    {
+	newdata = pdata;
+    }
+
+    pdata = newdata;
+    plength = newlength;
+    return newdata;
+
+Loverflow:
+    _d_OutOfMemory();
+}
+
+/**
+ * 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;
+    size_t sizeelem = ti.next.tsize();
+    void[] initializer = ti.next.init();
+    size_t initsize = initializer.length;
+
+    assert(sizeelem);
+    assert(initsize);
+    assert(initsize <= sizeelem);
+    assert((sizeelem / initsize) * initsize == sizeelem);
+
+    debug(PRINTF)
+    {
+	printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize);
+	if (p)
+	    printf("\tpdata = %p, plength = %d\n", pdata, plength);
+    }
+
+    if (newlength)
+    {
+	version (GNU)
+	{
+	    // required to output the label;
+	    static char x = 0;
+	    if (x)
+		goto Loverflow;
+	}
+
+	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;
+	}
+	//printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+	size_t size = plength * sizeelem;
+	if (pdata)
+	{
+	    newdata = pdata;
+	    if (newlength > plength)
+	    {
+		size_t cap = _gc.capacity(pdata);
+
+		if (cap <= newsize)
+		{
+		    if (cap >= 4096)
+		    {	// Try to extend in-place
+			auto u = _gc.extend(pdata, (newsize + 1) - cap, (newsize + 1) - cap);
+			if (u)
+			{
+			    goto L1;
+			}
+		    }
+		    newdata = cast(byte *)_gc.malloc(newsize + 1);
+		    newdata[0 .. size] = pdata[0 .. size];
+		L1: ;
+		}
+	    }
+	}
+	else
+	{
+	    newdata = cast(byte *)_gc.malloc(newsize + 1);
+	    if (!(ti.next.flags() & 1))
+		_gc.hasNoPointers(newdata);
+	}
+
+	auto q = initializer.ptr;	// pointer to initializer
+
+	if (newsize > size)
+	{
+	    if (initsize == 1)
+	    {
+		//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;
+    }
+
+    pdata = newdata;
+    plength = newlength;
+    return newdata;
+
+Loverflow:
+    _d_OutOfMemory();
+}
+
+/****************************************
+ * Append y[] to array x[].
+ * size is size of each array element.
+ */
+
+extern (C)
+Array _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
+{
+    auto sizeelem = ti.next.tsize();		// array element size
+    auto cap = _gc.capacity(px.data);
+    auto length = px.length;
+    auto newlength = length + y.length;
+    auto newsize = newlength * sizeelem;
+    if (newsize > cap)
+    {   byte* newdata;
+
+	if (cap >= 4096)
+	{   // Try to extend in-place
+	    auto u = _gc.extend(px.data, (newsize + 1) - cap, (newsize + 1) - cap);
+	    if (u)
+	    {
+		goto L1;
+	    }
+	}
+
+	newdata = cast(byte *)_gc.malloc(newCapacity(newlength, sizeelem) + 1);
+	if (!(ti.next.flags() & 1))
+	    _gc.hasNoPointers(newdata);
+	memcpy(newdata, px.data, length * sizeelem);
+	px.data = newdata;
+    }
+  L1:
+    px.length = newlength;
+    memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem);
+    return *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 4096 bytes are left as-is, so for the most
+	 * common cases, memory allocation is 1 to 1. The small overhead added
+	 * doesn't effect 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 > 4096)
+	{
+	    //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;
+	    //printf("mult: %2.2f, mult2: %2.2f, alloc: %2.2f\n",mult/100.0,mult2,newext / cast(double)size);
+	}
+	newcap = newext > newcap ? newext : newcap;
+	//printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
+    }
+    return newcap;
+}
+
+extern (C)
+byte[] _d_arrayappendcTp(TypeInfo ti, inout byte[] x, byte *argp)
+{
+    auto sizeelem = ti.next.tsize();		// array element size
+    auto cap = _gc.capacity(x.ptr);
+    auto length = x.length;
+    auto newlength = length + 1;
+    auto newsize = newlength * sizeelem;
+
+    assert(cap == 0 || length * sizeelem <= cap);
+
+    //printf("_d_arrayappendc(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, cap);
+
+    if (newsize >= cap)
+    {   byte* newdata;
+
+	if (cap >= 4096)
+	{   // Try to extend in-place
+	    auto u = _gc.extend(x.ptr, (newsize + 1) - cap, (newsize + 1) - cap);
+	    if (u)
+	    {
+		goto L1;
+	    }
+	}
+
+	//printf("_d_arrayappendc(sizeelem = %d, newlength = %d, cap = %d)\n", sizeelem, newlength, cap);
+	cap = newCapacity(newlength, sizeelem);
+	assert(cap >= newlength * sizeelem);
+	newdata = cast(byte *)_gc.malloc(cap + 1);
+	if (!(ti.next.flags() & 1))
+	    _gc.hasNoPointers(newdata);
+	memcpy(newdata, x.ptr, length * sizeelem);
+	(cast(void **)(&x))[1] = newdata;
+    }
+  L1:
+
+    *cast(size_t *)&x = newlength;
+    x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
+    assert((cast(size_t)x.ptr & 15) == 0);
+    assert(_gc.capacity(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
+    //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.capacity(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;
+    }
+
+    //printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr);
+    auto sizeelem = ti.next.tsize();		// array element size
+    //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);
+    if (!(ti.next.flags() & 1))
+	_gc.hasNoPointers(p);
+    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;
+    va_list va;
+    auto sizeelem = ti.next.tsize();		// array element size
+
+    va_start!(typeof(n))(va, n);
+
+    for (i = 0; i < n; i++)
+    {
+	b = va_arg!(typeof(b))(va);
+	length += b.length;
+    }
+    if (!length)
+	return null;
+
+    a = _gc.malloc(length * sizeelem);
+    if (!(ti.next.flags() & 1))
+	_gc.hasNoPointers(a);
+    va_start!(typeof(n))(va, n);
+
+    uint j = 0;
+    for (i = 0; i < n; i++)
+    {
+	b = va_arg!(typeof(b))(va);
+	if (b.length)
+	{
+	    memcpy(a + j, b.ptr, b.length * sizeelem);
+	    j += b.length * sizeelem;
+	}
+    }
+
+    return (cast(byte*)a)[0..length];
+}
+
+version (GNU) { } else
+extern (C)
+void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
+{
+    auto sizeelem = ti.next.tsize();		// array element size
+    void* result;
+
+    //printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length);
+    if (length == 0 || sizeelem == 0)
+	result = null;
+    else
+    {
+	result = _gc.malloc(length * sizeelem);
+	if (!(ti.next.flags() & 1))
+	{
+	    _gc.hasNoPointers(result);
+	}
+
+	va_list q;
+	va_start!(size_t)(q, length);
+
+	size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1);
+
+	if (stacksize == sizeelem)
+	{
+	    memcpy(result, q, length * sizeelem);
+	}
+	else
+	{
+	    for (size_t i = 0; i < length; i++)
+	    {
+		memcpy(result + i * sizeelem, q, sizeelem);
+		q += stacksize;
+	    }
+	}
+
+	va_end(q);
+    }
+    return result;
+}
+
+/**********************************
+ * Support for array.dup property.
+ */
+
+/*struct Array2
+{
+    size_t length;
+    void* ptr;
+}*/
+
+extern(C) void* _d_allocmemoryT(size_t foo) { return malloc(foo).ptr; }