Added druntime (this should be removed once it works).

This commit is contained in:
Robert Clipsham
2009-06-02 17:43:06 +01:00
parent 435d3069f6
commit c9ca799f88
269 changed files with 83741 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
@echo off
set OLDHOME=%HOME%
set HOME=%CD%
make clean all -fdmd-win32.mak
set HOME=%OLDHOME%

19
druntime/src/build-dmd.sh Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
OLDHOME=$HOME
export HOME=`pwd`
goerror(){
export HOME=$OLDHOME
echo "="
echo "= *** Error ***"
echo "="
exit 1
}
make clean -fdmd-posix.mak || goerror
make -fdmd-posix.mak || goerror
chmod 644 ../import/core/*.di || goerror
chmod 644 ../import/core/sync/*.di || goerror
export HOME=$OLDHOME

19
druntime/src/build-ldc.sh Executable file
View File

@@ -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-posix.mak || goerror
make -fldc-posix.mak || goerror
chmod 644 ../import/core/*.di || goerror
chmod 644 ../import/core/sync/*.di || goerror
export HOME=$OLDHOME

View File

@@ -0,0 +1,286 @@
/**
* This module contains a collection of bit-level operations.
*
* Copyright: Copyright (c) 2005-2008, The D Runtime Project
* License: BSD Style, see LICENSE
* Authors: Walter Bright, Don Clugston, Sean Kelly
*/
module core.bitmanip;
version( DDoc )
{
/**
* Scans the bits in v starting with bit 0, looking
* for the first set bit.
* Returns:
* The bit number of the first bit set.
* The return value is undefined if v is zero.
*/
int bsf( uint v );
/**
* Scans the bits in v from the most significant bit
* to the least significant bit, looking
* for the first set bit.
* Returns:
* The bit number of the first bit set.
* The return value is undefined if v is zero.
* Example:
* ---
* import core.bitmanip;
*
* int main()
* {
* uint v;
* int x;
*
* v = 0x21;
* x = bsf(v);
* printf("bsf(x%x) = %d\n", v, x);
* x = bsr(v);
* printf("bsr(x%x) = %d\n", v, x);
* return 0;
* }
* ---
* Output:
* bsf(x21) = 0<br>
* bsr(x21) = 5
*/
int bsr( uint v );
/**
* Tests the bit.
*/
int bt( uint* p, uint bitnum );
/**
* Tests and complements the bit.
*/
int btc( uint* p, uint bitnum );
/**
* Tests and resets (sets to 0) the bit.
*/
int btr( uint* p, uint bitnum );
/**
* Tests and sets the bit.
* Params:
* p = a non-NULL pointer to an array of uints.
* index = a bit number, starting with bit 0 of p[0],
* and progressing. It addresses bits like the expression:
---
p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)))
---
* Returns:
* A non-zero value if the bit was set, and a zero
* if it was clear.
*
* Example:
* ---
import core.bitmanip;
int main()
{
uint array[2];
array[0] = 2;
array[1] = 0x100;
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
printf("bts(array, 35) = %d\n", <b>bts</b>(array, 35));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
printf("btr(array, 35) = %d\n", <b>btr</b>(array, 35));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
printf("bt(array, 1) = %d\n", <b>bt</b>(array, 1));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
return 0;
}
* ---
* Output:
<pre>
btc(array, 35) = 0
array = [0]:x2, [1]:x108
btc(array, 35) = -1
array = [0]:x2, [1]:x100
bts(array, 35) = 0
array = [0]:x2, [1]:x108
btr(array, 35) = -1
array = [0]:x2, [1]:x100
bt(array, 1) = -1
array = [0]:x2, [1]:x100
</pre>
*/
int bts( uint* p, uint bitnum );
/**
* Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
* byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
* becomes byte 0.
*/
uint bswap( uint v );
/**
* Reads I/O port at port_address.
*/
ubyte inp( uint port_address );
/**
* ditto
*/
ushort inpw( uint port_address );
/**
* ditto
*/
uint inpl( uint port_address );
/**
* Writes and returns value to I/O port at port_address.
*/
ubyte outp( uint port_address, ubyte value );
/**
* ditto
*/
ushort outpw( uint port_address, ushort value );
/**
* ditto
*/
uint outpl( uint port_address, uint value );
}
else
{
public import std.intrinsic;
}
/**
* Calculates the number of set bits in a 32-bit integer.
*/
int popcnt( uint x )
{
// Avoid branches, and the potential for cache misses which
// could be incurred with a table lookup.
// We need to mask alternate bits to prevent the
// sum from overflowing.
// add neighbouring bits. Each bit is 0 or 1.
x = x - ((x>>1) & 0x5555_5555);
// now each two bits of x is a number 00,01 or 10.
// now add neighbouring pairs
x = ((x&0xCCCC_CCCC)>>2) + (x&0x3333_3333);
// now each nibble holds 0000-0100. Adding them won't
// overflow any more, so we don't need to mask any more
// Now add the nibbles, then the bytes, then the words
// We still need to mask to prevent double-counting.
// Note that if we used a rotate instead of a shift, we
// wouldn't need the masks, and could just divide the sum
// by 8 to account for the double-counting.
// On some CPUs, it may be faster to perform a multiply.
x += (x>>4);
x &= 0x0F0F_0F0F;
x += (x>>8);
x &= 0x00FF_00FF;
x += (x>>16);
x &= 0xFFFF;
return x;
}
debug( UnitTest )
{
unittest
{
assert( popcnt( 0 ) == 0 );
assert( popcnt( 7 ) == 3 );
assert( popcnt( 0xAA )== 4 );
assert( popcnt( 0x8421_1248 ) == 8 );
assert( popcnt( 0xFFFF_FFFF ) == 32 );
assert( popcnt( 0xCCCC_CCCC ) == 16 );
assert( popcnt( 0x7777_7777 ) == 24 );
}
}
/**
* Reverses the order of bits in a 32-bit integer.
*/
uint bitswap( uint x )
{
version( D_InlineAsm_X86 )
{
asm
{
// Author: Tiago Gasiba.
mov EDX, EAX;
shr EAX, 1;
and EDX, 0x5555_5555;
and EAX, 0x5555_5555;
shl EDX, 1;
or EAX, EDX;
mov EDX, EAX;
shr EAX, 2;
and EDX, 0x3333_3333;
and EAX, 0x3333_3333;
shl EDX, 2;
or EAX, EDX;
mov EDX, EAX;
shr EAX, 4;
and EDX, 0x0f0f_0f0f;
and EAX, 0x0f0f_0f0f;
shl EDX, 4;
or EAX, EDX;
bswap EAX;
}
}
else
{
// swap odd and even bits
x = ((x >> 1) & 0x5555_5555) | ((x & 0x5555_5555) << 1);
// swap consecutive pairs
x = ((x >> 2) & 0x3333_3333) | ((x & 0x3333_3333) << 2);
// swap nibbles
x = ((x >> 4) & 0x0F0F_0F0F) | ((x & 0x0F0F_0F0F) << 4);
// swap bytes
x = ((x >> 8) & 0x00FF_00FF) | ((x & 0x00FF_00FF) << 8);
// swap 2-byte long pairs
x = ( x >> 16 ) | ( x << 16);
return x;
}
}
debug( UnitTest )
{
unittest
{
assert( bitswap( 0x8000_0100 ) == 0x0080_0001 );
}
}

View File

@@ -0,0 +1,290 @@
/**
* This module contains a collection of bit-level operations.
*
* Copyright: Copyright Don Clugston 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Don Clugston, Sean Kelly, Walter Bright
*
* Copyright Don Clugston 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.bitop;
version( D_Ddoc )
{
/**
* Scans the bits in v starting with bit 0, looking
* for the first set bit.
* Returns:
* The bit number of the first bit set.
* The return value is undefined if v is zero.
*/
int bsf( uint v );
/**
* Scans the bits in v from the most significant bit
* to the least significant bit, looking
* for the first set bit.
* Returns:
* The bit number of the first bit set.
* The return value is undefined if v is zero.
* Example:
* ---
* import core.bitop;
*
* int main()
* {
* uint v;
* int x;
*
* v = 0x21;
* x = bsf(v);
* printf("bsf(x%x) = %d\n", v, x);
* x = bsr(v);
* printf("bsr(x%x) = %d\n", v, x);
* return 0;
* }
* ---
* Output:
* bsf(x21) = 0<br>
* bsr(x21) = 5
*/
int bsr( uint v );
/**
* Tests the bit.
*/
int bt( uint* p, uint bitnum );
/**
* Tests and complements the bit.
*/
int btc( uint* p, uint bitnum );
/**
* Tests and resets (sets to 0) the bit.
*/
int btr( uint* p, uint bitnum );
/**
* Tests and sets the bit.
* Params:
* p = a non-NULL pointer to an array of uints.
* index = a bit number, starting with bit 0 of p[0],
* and progressing. It addresses bits like the expression:
---
p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)))
---
* Returns:
* A non-zero value if the bit was set, and a zero
* if it was clear.
*
* Example:
* ---
import core.bitop;
int main()
{
uint array[2];
array[0] = 2;
array[1] = 0x100;
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
printf("bts(array, 35) = %d\n", <b>bts</b>(array, 35));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
printf("btr(array, 35) = %d\n", <b>btr</b>(array, 35));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
printf("bt(array, 1) = %d\n", <b>bt</b>(array, 1));
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
return 0;
}
* ---
* Output:
<pre>
btc(array, 35) = 0
array = [0]:x2, [1]:x108
btc(array, 35) = -1
array = [0]:x2, [1]:x100
bts(array, 35) = 0
array = [0]:x2, [1]:x108
btr(array, 35) = -1
array = [0]:x2, [1]:x100
bt(array, 1) = -1
array = [0]:x2, [1]:x100
</pre>
*/
int bts( uint* p, uint bitnum );
/**
* Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
* byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
* becomes byte 0.
*/
uint bswap( uint v );
/**
* Reads I/O port at port_address.
*/
ubyte inp( uint port_address );
/**
* ditto
*/
ushort inpw( uint port_address );
/**
* ditto
*/
uint inpl( uint port_address );
/**
* Writes and returns value to I/O port at port_address.
*/
ubyte outp( uint port_address, ubyte value );
/**
* ditto
*/
ushort outpw( uint port_address, ushort value );
/**
* ditto
*/
uint outpl( uint port_address, uint value );
}
else
{
public import std.intrinsic;
}
/**
* Calculates the number of set bits in a 32-bit integer.
*/
int popcnt( uint x )
{
// Avoid branches, and the potential for cache misses which
// could be incurred with a table lookup.
// We need to mask alternate bits to prevent the
// sum from overflowing.
// add neighbouring bits. Each bit is 0 or 1.
x = x - ((x>>1) & 0x5555_5555);
// now each two bits of x is a number 00,01 or 10.
// now add neighbouring pairs
x = ((x&0xCCCC_CCCC)>>2) + (x&0x3333_3333);
// now each nibble holds 0000-0100. Adding them won't
// overflow any more, so we don't need to mask any more
// Now add the nibbles, then the bytes, then the words
// We still need to mask to prevent double-counting.
// Note that if we used a rotate instead of a shift, we
// wouldn't need the masks, and could just divide the sum
// by 8 to account for the double-counting.
// On some CPUs, it may be faster to perform a multiply.
x += (x>>4);
x &= 0x0F0F_0F0F;
x += (x>>8);
x &= 0x00FF_00FF;
x += (x>>16);
x &= 0xFFFF;
return x;
}
debug( UnitTest )
{
unittest
{
assert( popcnt( 0 ) == 0 );
assert( popcnt( 7 ) == 3 );
assert( popcnt( 0xAA )== 4 );
assert( popcnt( 0x8421_1248 ) == 8 );
assert( popcnt( 0xFFFF_FFFF ) == 32 );
assert( popcnt( 0xCCCC_CCCC ) == 16 );
assert( popcnt( 0x7777_7777 ) == 24 );
}
}
/**
* Reverses the order of bits in a 32-bit integer.
*/
uint bitswap( uint x )
{
version( D_InlineAsm_X86 )
{
asm
{
// Author: Tiago Gasiba.
mov EDX, EAX;
shr EAX, 1;
and EDX, 0x5555_5555;
and EAX, 0x5555_5555;
shl EDX, 1;
or EAX, EDX;
mov EDX, EAX;
shr EAX, 2;
and EDX, 0x3333_3333;
and EAX, 0x3333_3333;
shl EDX, 2;
or EAX, EDX;
mov EDX, EAX;
shr EAX, 4;
and EDX, 0x0f0f_0f0f;
and EAX, 0x0f0f_0f0f;
shl EDX, 4;
or EAX, EDX;
bswap EAX;
}
}
else
{
// swap odd and even bits
x = ((x >> 1) & 0x5555_5555) | ((x & 0x5555_5555) << 1);
// swap consecutive pairs
x = ((x >> 2) & 0x3333_3333) | ((x & 0x3333_3333) << 2);
// swap nibbles
x = ((x >> 4) & 0x0F0F_0F0F) | ((x & 0x0F0F_0F0F) << 4);
// swap bytes
x = ((x >> 8) & 0x00FF_00FF) | ((x & 0x00FF_00FF) << 8);
// swap 2-byte long pairs
x = ( x >> 16 ) | ( x << 16);
return x;
}
}
debug( UnitTest )
{
unittest
{
assert( bitswap( 0x8000_0100 ) == 0x0080_0001 );
}
}

View File

@@ -0,0 +1,279 @@
/**
* The exception module defines all system-level exceptions and provides a
* mechanism to alter system-level error handling.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.exception;
private
{
alias void function( string file, size_t line, string msg = null ) assertHandlerType;
// Note that this is set on a per-thread basis (should it be global?)
assertHandlerType assertHandler = null;
}
/**
* Thrown on a range error.
*/
class RangeError : Error
{
this( string file, size_t line )
{
super( "Range violation", file, line );
}
}
/**
* Thrown on an assert error.
*/
class AssertError : Error
{
this( string file, size_t line )
{
super( "Assertion failure", file, line );
}
this( string msg, string file, size_t line )
{
super( msg, file, line );
}
}
/**
* Thrown on finalize error.
*/
class FinalizeError : Error
{
ClassInfo info;
this( ClassInfo c, Exception e = null )
{
super( "Finalization error", e );
info = c;
}
override string toString()
{
return "An exception was thrown while finalizing an instance of class " ~ info.name;
}
}
/**
* Thrown on hidden function error.
*/
class HiddenFuncError : Error
{
this( ClassInfo ci )
{
super( "Hidden method called for " ~ ci.name );
}
}
/**
* Thrown on an out of memory error.
*/
class OutOfMemoryError : Error
{
this( string file, size_t line )
{
super( "Memory allocation failed", file, line );
}
override string toString()
{
return msg ? super.toString() : "Memory allocation failed";
}
}
/**
* Thrown on a switch error.
*/
class SwitchError : Error
{
this( string file, size_t line )
{
super( "No appropriate switch clause found", file, line );
}
}
/**
* Thrown on a unicode conversion error.
*/
class UnicodeException : Exception
{
size_t idx;
this( string msg, size_t idx )
{
super( msg );
this.idx = idx;
}
}
///////////////////////////////////////////////////////////////////////////////
// Overrides
///////////////////////////////////////////////////////////////////////////////
/**
* Overrides the default assert hander with a user-supplied version.
*
* Params:
* h = The new assert handler. Set to null to use the default handler.
*/
void setAssertHandler( assertHandlerType h )
{
assertHandler = h;
}
///////////////////////////////////////////////////////////////////////////////
// Overridable Callbacks
///////////////////////////////////////////////////////////////////////////////
/**
* A callback for assert errors in D. The user-supplied assert handler will
* be called if one has been supplied, otherwise an AssertError will be thrown.
*
* Params:
* file = The name of the file that signaled this error.
* line = The line number on which this error occurred.
*/
extern (C) void onAssertError( string file, size_t line )
{
if( assertHandler is null )
throw new AssertError( file, line );
assertHandler( file, line );
}
/**
* A callback for assert errors in D. The user-supplied assert handler will
* be called if one has been supplied, otherwise an AssertError will be thrown.
*
* Params:
* file = The name of the file that signaled this error.
* line = The line number on which this error occurred.
* msg = An error message supplied by the user.
*/
extern (C) void onAssertErrorMsg( string file, size_t line, string msg )
{
if( assertHandler is null )
throw new AssertError( msg, file, line );
assertHandler( file, line, msg );
}
///////////////////////////////////////////////////////////////////////////////
// Internal Error Callbacks
///////////////////////////////////////////////////////////////////////////////
/**
* A callback for array bounds errors in D. A RangeError will be thrown.
*
* Params:
* file = The name of the file that signaled this error.
* line = The line number on which this error occurred.
*
* Throws:
* RangeError.
*/
extern (C) void onRangeError( string file, size_t line )
{
throw new RangeError( file, line );
}
/**
* A callback for finalize errors in D. A FinalizeError will be thrown.
*
* Params:
* e = The exception thrown during finalization.
*
* Throws:
* FinalizeError.
*/
extern (C) void onFinalizeError( ClassInfo info, Exception ex )
{
throw new FinalizeError( info, ex );
}
/**
* A callback for hidden function errors in D. A HiddenFuncError will be
* thrown.
*
* Throws:
* HiddenFuncError.
*/
extern (C) void onHiddenFuncError( Object o )
{
throw new HiddenFuncError( o.classinfo );
}
/**
* A callback for out of memory errors in D. An OutOfMemoryError will be
* thrown.
*
* Throws:
* OutOfMemoryError.
*/
extern (C) void onOutOfMemoryError()
{
// NOTE: Since an out of memory condition exists, no allocation must occur
// while generating this object.
throw cast(OutOfMemoryError) cast(void*) OutOfMemoryError.classinfo.init;
}
/**
* A callback for switch errors in D. A SwitchError will be thrown.
*
* Params:
* file = The name of the file that signaled this error.
* line = The line number on which this error occurred.
*
* Throws:
* SwitchError.
*/
extern (C) void onSwitchError( string file, size_t line )
{
throw new SwitchError( file, line );
}
/**
* A callback for unicode errors in D. A UnicodeException will be thrown.
*
* Params:
* msg = Information about the error.
* idx = String index where this error was detected.
*
* Throws:
* UnicodeException.
*/
extern (C) void onUnicodeError( string msg, size_t idx )
{
throw new UnicodeException( msg, idx );
}

View File

@@ -0,0 +1,452 @@
/**
* The memory module provides an interface to the garbage collector and to
* any other OS or API-level memory management facilities.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.memory;
private
{
extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void gc_enable();
extern (C) void gc_disable();
extern (C) void gc_collect();
extern (C) void gc_minimize();
extern (C) uint gc_getAttr( void* p );
extern (C) uint gc_setAttr( void* p, uint a );
extern (C) uint gc_clrAttr( void* p, uint a );
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 );
extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
extern (C) size_t gc_reserve( size_t sz );
extern (C) void gc_free( void* p );
extern (C) void* gc_addrOf( void* p );
extern (C) size_t gc_sizeOf( void* p );
struct BlkInfo_
{
void* base;
size_t size;
uint attr;
}
extern (C) BlkInfo_ gc_query( void* p );
extern (C) void gc_addRoot( void* p );
extern (C) void gc_addRange( void* p, size_t sz );
extern (C) void gc_removeRoot( void* p );
extern (C) void gc_removeRange( void* p );
}
/**
* This struct encapsulates all garbage collection functionality for the D
* programming language.
*/
struct GC
{
/**
* Enables automatic garbage collection behavior if collections have
* previously been suspended by a call to disable. This function is
* reentrant, and must be called once for every call to disable before
* automatic collections are enabled.
*/
static void enable()
{
gc_enable();
}
/**
* Disables automatic garbage collections performed to minimize the
* process footprint. Collections may continue to occur in instances
* where the implementation deems necessary for correct program behavior,
* such as during an out of memory condition. This function is reentrant,
* but enable must be called once for each call to disable.
*/
static void disable()
{
gc_disable();
}
/**
* Begins a full collection. While the meaning of this may change based
* on the garbage collector implementation, typical behavior is to scan
* all stack segments for roots, mark accessible memory blocks as alive,
* and then to reclaim free space. This action may need to suspend all
* running threads for at least part of the collection process.
*/
static void collect()
{
gc_collect();
}
/**
* Indicates that the managed memory space be minimized by returning free
* physical memory to the operating system. The amount of free memory
* returned depends on the allocator design and on program behavior.
*/
static void minimize()
{
gc_minimize();
}
/**
* Elements for a bit field representing memory block attributes. These
* are manipulated via the getAttr, setAttr, clrAttr functions.
*/
enum BlkAttr : uint
{
FINALIZE = 0b0000_0001, /// Finalize the data in this block on collect.
NO_SCAN = 0b0000_0010, /// Do not scan through this block on collect.
NO_MOVE = 0b0000_0100 /// Do not move this memory block on collect.
}
/**
* Contains aggregate information about a block of managed memory. The
* purpose of this struct is to support a more efficient query style in
* instances where detailed information is needed.
*
* base = A pointer to the base of the block in question.
* size = The size of the block, calculated from base.
* attr = Attribute bits set on the memory block.
*/
alias BlkInfo_ BlkInfo;
/**
* Returns a bit field representing all block attributes set for the memory
* referenced by p. If p references memory not originally allocated by
* this garbage collector, points to the interior of a memory block, or if
* p is null, zero will be returned.
*
* Params:
* p = A pointer to the root of a valid memory block or to null.
*
* Returns:
* A bit field containing any bits set for the memory block referenced by
* p or zero on error.
*/
static uint getAttr( void* p )
{
return gc_getAttr( p );
}
/**
* Sets the specified bits for the memory references by p. If p references
* memory not originally allocated by this garbage collector, points to the
* interior of a memory block, or if p is null, no action will be
* performed.
*
* Params:
* p = A pointer to the root of a valid memory block or to null.
* a = A bit field containing any bits to set for this memory block.
*
* The result of a call to getAttr after the specified bits have been
* set.
*/
static uint setAttr( void* p, uint a )
{
return gc_setAttr( p, a );
}
/**
* Clears the specified bits for the memory references by p. If p
* references memory not originally allocated by this garbage collector,
* points to the interior of a memory block, or if p is null, no action
* will be performed.
*
* Params:
* p = A pointer to the root of a valid memory block or to null.
* a = A bit field containing any bits to clear for this memory block.
*
* Returns:
* The result of a call to getAttr after the specified bits have been
* cleared.
*/
static uint clrAttr( void* p, uint a )
{
return gc_clrAttr( p, a );
}
/**
* Requests an aligned block of managed memory from the garbage collector.
* This memory may be deleted at will with a call to free, or it may be
* discarded and cleaned up automatically during a collection run. If
* allocation fails, this function will call onOutOfMemory which is
* expected to throw an OutOfMemoryException.
*
* Params:
* sz = The desired allocation size in bytes.
* ba = A bitmask of the attributes to set on this block.
*
* Returns:
* A reference to the allocated memory or null if insufficient memory
* is available.
*
* Throws:
* OutOfMemoryException on allocation failure.
*/
static void* malloc( size_t sz, uint ba = 0 )
{
return gc_malloc( sz, ba );
}
/**
* Requests an aligned block of managed memory from the garbage collector,
* which is initialized with all bits set to zero. This memory may be
* deleted at will with a call to free, or it may be discarded and cleaned
* up automatically during a collection run. If allocation fails, this
* function will call onOutOfMemory which is expected to throw an
* OutOfMemoryException.
*
* Params:
* sz = The desired allocation size in bytes.
* ba = A bitmask of the attributes to set on this block.
*
* Returns:
* A reference to the allocated memory or null if insufficient memory
* is available.
*
* Throws:
* OutOfMemoryException on allocation failure.
*/
static void* calloc( size_t sz, uint ba = 0 )
{
return gc_calloc( sz, ba );
}
/**
* If sz is zero, the memory referenced by p will be deallocated as if
* by a call to free. A new memory block of size sz will then be
* allocated as if by a call to malloc, or the implementation may instead
* resize the memory block in place. The contents of the new memory block
* will be the same as the contents of the old memory block, up to the
* lesser of the new and old sizes. Note that existing memory will only
* be freed by realloc if sz is equal to zero. The garbage collector is
* otherwise expected to later reclaim the memory block if it is unused.
* If allocation fails, this function will call onOutOfMemory which is
* expected to throw an OutOfMemoryException. If p references memory not
* originally allocated by this garbage collector, or if it points to the
* interior of a memory block, no action will be taken. If ba is zero
* (the default) and p references the head of a valid, known memory block
* then any bits set on the current block will be set on the new block if a
* reallocation is required. If ba is not zero and p references the head
* of a valid, known memory block then the bits in ba will replace those on
* the current memory block and will also be set on the new block if a
* reallocation is required.
*
* Params:
* p = A pointer to the root of a valid memory block or to null.
* sz = The desired allocation size in bytes.
* ba = A bitmask of the attributes to set on this block.
*
* Returns:
* A reference to the allocated memory on success or null if sz is
* zero. On failure, the original value of p is returned.
*
* Throws:
* OutOfMemoryException on allocation failure.
*/
static void* realloc( void* p, size_t sz, uint ba = 0 )
{
return gc_realloc( p, sz, ba );
}
/**
* Requests that the managed memory block referenced by p be extended in
* place by at least mx bytes, with a desired extension of sz bytes. If an
* extension of the required size is not possible, if p references memory
* not originally allocated by this garbage collector, or if p points to
* the interior of a memory block, no action will be taken.
*
* Params:
* mx = The minimum extension size in bytes.
* sz = The desired extension size in bytes.
*
* Returns:
* The size in bytes of the extended memory block referenced by p or zero
* if no extension occurred.
*/
static size_t extend( void* p, size_t mx, size_t sz )
{
return gc_extend( p, mx, sz );
}
/**
* Requests that at least sz bytes of memory be obtained from the operating
* system and marked as free.
*
* Params:
* sz = The desired size in bytes.
*
* Returns:
* The actual number of bytes reserved or zero on error.
*/
static size_t reserve( size_t sz )
{
return gc_reserve( sz );
}
/**
* Deallocates the memory referenced by p. If p is null, no action
* occurs. If p references memory not originally allocated by this
* garbage collector, or if it points to the interior of a memory block,
* no action will be taken. The block will not be finalized regardless
* of whether the FINALIZE attribute is set. If finalization is desired,
* use delete instead.
*
* Params:
* p = A pointer to the root of a valid memory block or to null.
*/
static void free( void* p )
{
gc_free( p );
}
/**
* Returns the base address of the memory block containing p. This value
* is useful to determine whether p is an interior pointer, and the result
* may be passed to routines such as sizeOf which may otherwise fail. If p
* references memory not originally allocated by this garbage collector, if
* p is null, or if the garbage collector does not support this operation,
* null will be returned.
*
* Params:
* p = A pointer to the root or the interior of a valid memory block or to
* null.
*
* Returns:
* The base address of the memory block referenced by p or null on error.
*/
static void* addrOf( void* p )
{
return gc_addrOf( p );
}
/**
* Returns the true size of the memory block referenced by p. This value
* represents the maximum number of bytes for which a call to realloc may
* resize the existing block in place. If p references memory not
* originally allocated by this garbage collector, points to the interior
* of a memory block, or if p is null, zero will be returned.
*
* Params:
* p = A pointer to the root of a valid memory block or to null.
*
* Returns:
* The size in bytes of the memory block referenced by p or zero on error.
*/
static size_t sizeOf( void* p )
{
return gc_sizeOf( p );
}
/**
* Returns aggregate information about the memory block containing p. If p
* references memory not originally allocated by this garbage collector, if
* p is null, or if the garbage collector does not support this operation,
* BlkInfo.init will be returned. Typically, support for this operation
* is dependent on support for addrOf.
*
* Params:
* p = A pointer to the root or the interior of a valid memory block or to
* null.
*
* Returns:
* Information regarding the memory block referenced by p or BlkInfo.init
* on error.
*/
static BlkInfo query( void* p )
{
return gc_query( p );
}
/**
* Adds the memory address referenced by p to an internal list of roots to
* be scanned during a collection. If p is null, no operation is
* performed.
*
* Params:
* p = A pointer to a valid memory address or to null.
*/
static void addRoot( void* p )
{
gc_addRoot( p );
}
/**
* Adds the memory block referenced by p and of size sz to an internal list
* of ranges to be scanned during a collection. If p is null, no operation
* is performed.
*
* Params:
* p = A pointer to a valid memory address or to null.
* sz = The size in bytes of the block to add. If sz is zero then the
* no operation will occur. If p is null then sz must be zero.
*/
static void addRange( void* p, size_t sz )
{
gc_addRange( p, sz );
}
/**
* Removes the memory block referenced by p from an internal list of roots
* to be scanned during a collection. If p is null or does not represent
* a value previously passed to add(void*) then no operation is performed.
*
* p = A pointer to a valid memory address or to null.
*/
static void removeRoot( void* p )
{
gc_removeRoot( p );
}
/**
* Removes the memory block referenced by p from an internal list of ranges
* to be scanned during a collection. If p is null or does not represent
* a value previously passed to add(void*, size_t) then no operation is
* performed.
*
* Params:
* p = A pointer to a valid memory address or to null.
*/
static void removeRange( void* p )
{
gc_removeRange( p );
}
}

View File

@@ -0,0 +1,211 @@
/**
* The runtime module exposes information specific to the D runtime code.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.runtime;
private
{
extern (C) bool rt_isHalting();
alias bool function() ModuleUnitTester;
alias bool function(Object) CollectHandler;
alias Exception.TraceInfo function( void* ptr = null ) TraceHandler;
extern (C) void rt_setCollectHandler( CollectHandler h );
extern (C) void rt_setTraceHandler( TraceHandler h );
alias void delegate( Throwable ) ExceptionHandler;
extern (C) bool rt_init( ExceptionHandler dg = null );
extern (C) bool rt_term( ExceptionHandler dg = null );
extern (C) void* rt_loadLibrary( in char[] name );
extern (C) bool rt_unloadLibrary( void* ptr );
}
///////////////////////////////////////////////////////////////////////////////
// Runtime
///////////////////////////////////////////////////////////////////////////////
/**
* This struct encapsulates all functionality related to the underlying runtime
* module for the calling context.
*/
struct Runtime
{
/**
* Initializes the runtime. This call is to be used in instances where the
* standard program initialization process is not executed. This is most
* often in shared libraries or in libraries linked to a C program.
*
* Params:
* dg = A delegate which will receive any exception thrown during the
* initialization process or null if such exceptions should be
* discarded.
*
* Returns:
* true if initialization succeeds and false if initialization fails.
*/
static bool initialize( ExceptionHandler dg = null )
{
return rt_init( dg );
}
/**
* Terminates the runtime. This call is to be used in instances where the
* standard program termination process will not be not executed. This is
* most often in shared libraries or in libraries linked to a C program.
*
* Params:
* dg = A delegate which will receive any exception thrown during the
* termination process or null if such exceptions should be
* discarded.
*
* Returns:
* true if termination succeeds and false if termination fails.
*/
static bool terminate( ExceptionHandler dg = null )
{
return rt_term( dg );
}
/**
* Returns true if the runtime is halting. Under normal circumstances,
* this will be set between the time that normal application code has
* exited and before module dtors are called.
*
* Returns:
* true if the runtime is halting.
*/
static bool isHalting()
{
return rt_isHalting();
}
/**
* Locates a dynamic library with the supplied library name and dynamically
* loads it into the caller's address space. If the library contains a D
* runtime it will be integrated with the current runtime.
*
* Params:
* name = The name of the dynamic library to load.
*
* Returns:
* A reference to the library or null on error.
*/
static void* loadLibrary( in char[] name )
{
return rt_loadLibrary( name );
}
/**
* Unloads the dynamic library referenced by p. If this library contains a
* D runtime then any necessary finalization or cleanup of that runtime
* will be performed.
*
* Params:
* p = A reference to the library to unload.
*/
static bool unloadLibrary( void* p )
{
return rt_unloadLibrary( p );
}
/**
* Overrides the default trace mechanism with s user-supplied version. A
* trace represents the context from which an exception was thrown, and the
* trace handler will be called when this occurs. The pointer supplied to
* this routine indicates the base address from which tracing should occur.
* If the supplied pointer is null then the trace routine should determine
* an appropriate calling context from which to begin the trace.
*
* Params:
* h = The new trace handler. Set to null to use the default handler.
*/
static void traceHandler( TraceHandler h )
{
rt_setTraceHandler( h );
}
/**
* Overrides the default collect hander with a user-supplied version. This
* routine will be called for each resource object that is finalized in a
* non-deterministic manner--typically during a garbage collection cycle.
* If the supplied routine returns true then the object's dtor will called
* as normal, but if the routine returns false than the dtor will not be
* called. The default behavior is for all object dtors to be called.
*
* Params:
* h = The new collect handler. Set to null to use the default handler.
*/
static void collectHandler( CollectHandler h )
{
rt_setCollectHandler( h );
}
/**
* Overrides the default module unit tester with a user-supplied version.
* This routine will be called once on program initialization. The return
* value of this routine indicates to the runtime whether the body of the
* program will be executed.
*
* Params:
* h = The new unit tester. Set to null to use the default unit tester.
*/
static void moduleUnitTester( ModuleUnitTester h )
{
sm_moduleUnitTester = h;
}
private:
// Unit tests should only be run in single-threaded
__gshared ModuleUnitTester sm_moduleUnitTester = null;
}
///////////////////////////////////////////////////////////////////////////////
// Overridable Callbacks
///////////////////////////////////////////////////////////////////////////////
/**
* This routine is called by the runtime to run module unit tests on startup.
* The user-supplied unit tester will be called if one has been supplied,
* otherwise all unit tests will be run in sequence.
*
* Returns:
* true if execution should continue after testing is complete and false if
* not. Default behavior is to return true.
*/
extern (C) bool runModuleUnitTests()
{
if( Runtime.sm_moduleUnitTester is null )
{
foreach( m; ModuleInfo )
{
if( m.unitTest )
m.unitTest();
}
return true;
}
return Runtime.sm_moduleUnitTester();
}

View File

@@ -0,0 +1,26 @@
/**
* This file contains wrapper functions for macro-defined C rouines.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <errno.h>
int getErrno()
{
return errno;
}
int setErrno( int val )
{
errno = val;
return val;
}

View File

@@ -0,0 +1,153 @@
/**
* The barrier module provides a primitive for synchronizing the progress of
* a group of threads.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.sync.barrier;
public import core.sync.exception;
private import core.sync.condition;
private import core.sync.mutex;
version( Win32 )
{
private import core.sys.windows.windows;
}
else version( Posix )
{
private import core.stdc.errno;
private import core.sys.posix.pthread;
}
////////////////////////////////////////////////////////////////////////////////
// Barrier
//
// void wait();
////////////////////////////////////////////////////////////////////////////////
/**
* This class represents a barrier across which threads may only travel in
* groups of a specific size.
*/
class Barrier
{
////////////////////////////////////////////////////////////////////////////
// Initialization
////////////////////////////////////////////////////////////////////////////
/**
* Initializes a barrier object which releases threads in groups of limit
* in size.
*
* Params:
* limit = The number of waiting threads to release in unison.
*
* Throws:
* SyncException on error.
*/
this( uint limit )
in
{
assert( limit > 0 );
}
body
{
m_lock = new Mutex;
m_cond = new Condition( m_lock );
m_group = 0;
m_limit = limit;
m_count = limit;
}
////////////////////////////////////////////////////////////////////////////
// General Actions
////////////////////////////////////////////////////////////////////////////
/**
* Wait for the pre-determined number of threads and then proceed.
*
* Throws:
* SyncException on error.
*/
void wait()
{
synchronized( m_lock )
{
uint group = m_group;
if( --m_count == 0 )
{
m_group++;
m_count = m_limit;
m_cond.notifyAll();
}
while( group == m_group )
m_cond.wait();
}
}
private:
Mutex m_lock;
Condition m_cond;
uint m_group;
uint m_limit;
uint m_count;
}
////////////////////////////////////////////////////////////////////////////////
// Unit Tests
////////////////////////////////////////////////////////////////////////////////
version( unittest )
{
private import core.thread;
unittest
{
int numThreads = 10;
auto barrier = new Barrier( numThreads );
auto synInfo = new Object;
int numReady = 0;
int numPassed = 0;
void threadFn()
{
synchronized( synInfo )
{
++numReady;
}
barrier.wait();
synchronized( synInfo )
{
++numPassed;
}
}
auto group = new ThreadGroup;
for( int i = 0; i < numThreads; ++i )
{
group.create( &threadFn );
}
group.joinAll();
assert( numReady == numThreads && numPassed == numThreads );
}
}

View File

@@ -0,0 +1,573 @@
/**
* The condition module provides a primitive for synchronized condition
* checking.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.sync.condition;
public import core.sync.exception;
public import core.sync.mutex;
version( Win32 )
{
private import core.sync.semaphore;
private import core.sys.windows.windows;
}
else version( Posix )
{
private import core.sync.config;
private import core.stdc.errno;
private import core.sys.posix.pthread;
private import core.sys.posix.time;
}
////////////////////////////////////////////////////////////////////////////////
// Condition
//
// void wait();
// void notify();
// void notifyAll();
////////////////////////////////////////////////////////////////////////////////
/**
* This class represents a condition variable as concieved by C.A.R. Hoare. As
* per Mesa type monitors however, "signal" has been replaced with "notify" to
* indicate that control is not transferred to the waiter when a notification
* is sent.
*/
class Condition
{
////////////////////////////////////////////////////////////////////////////
// Initialization
////////////////////////////////////////////////////////////////////////////
/**
* Initializes a condition object which is associated with the supplied
* mutex object.
*
* Params:
* m = The mutex with which this condition will be associated.
*
* Throws:
* SyncException on error.
*/
this( Mutex m )
{
version( Win32 )
{
m_blockLock = CreateSemaphoreA( null, 1, 1, null );
if( m_blockLock == m_blockLock.init )
throw new SyncException( "Unable to initialize condition" );
scope(failure) CloseHandle( m_blockLock );
m_blockQueue = CreateSemaphoreA( null, 0, int.max, null );
if( m_blockQueue == m_blockQueue.init )
throw new SyncException( "Unable to initialize condition" );
scope(failure) CloseHandle( m_blockQueue );
InitializeCriticalSection( &m_unblockLock );
m_assocMutex = m;
}
else version( Posix )
{
m_mutexAddr = m.handleAddr();
int rc = pthread_cond_init( &m_hndl, null );
if( rc )
throw new SyncException( "Unable to initialize condition" );
}
}
~this()
{
version( Win32 )
{
BOOL rc = CloseHandle( m_blockLock );
assert( rc, "Unable to destroy condition" );
rc = CloseHandle( m_blockQueue );
assert( rc, "Unable to destroy condition" );
DeleteCriticalSection( &m_unblockLock );
}
else version( Posix )
{
int rc = pthread_cond_destroy( &m_hndl );
assert( !rc, "Unable to destroy condition" );
}
}
////////////////////////////////////////////////////////////////////////////
// General Actions
////////////////////////////////////////////////////////////////////////////
/**
* Wait until notified.
*
* Throws:
* SyncException on error.
*/
void wait()
{
version( Win32 )
{
timedWait( INFINITE );
}
else version( Posix )
{
int rc = pthread_cond_wait( &m_hndl, m_mutexAddr );
if( rc )
throw new SyncException( "Unable to wait for condition" );
}
}
/**
* Suspends the calling thread until a notification occurs or until the
* supplied time period has elapsed.
*
* Params:
* period = The time to wait, in 100 nanosecond intervals. This value may
* be adjusted to equal to the maximum wait period supported by
* the target platform if it is too large.
*
* In:
* period must be non-negative.
*
* Throws:
* SyncException on error.
*
* Returns:
* true if notified before the timeout and false if not.
*/
bool wait( long period )
in
{
assert( period >= 0 );
}
body
{
version( Win32 )
{
enum : uint
{
TICKS_PER_MILLI = 10_000,
MAX_WAIT_MILLIS = uint.max - 1
}
period /= TICKS_PER_MILLI;
if( period > MAX_WAIT_MILLIS )
period = MAX_WAIT_MILLIS;
return timedWait( cast(uint) period );
}
else version( Posix )
{
timespec t = void;
mktspec( t, period );
int rc = pthread_cond_timedwait( &m_hndl, m_mutexAddr, &t );
if( !rc )
return true;
if( rc == ETIMEDOUT )
return false;
throw new SyncException( "Unable to wait for condition" );
}
}
/**
* Notifies one waiter.
*
* Throws:
* SyncException on error.
*/
void notify()
{
version( Win32 )
{
notify( false );
}
else version( Posix )
{
int rc = pthread_cond_signal( &m_hndl );
if( rc )
throw new SyncException( "Unable to notify condition" );
}
}
/**
* Notifies all waiters.
*
* Throws:
* SyncException on error.
*/
void notifyAll()
{
version( Win32 )
{
notify( true );
}
else version( Posix )
{
int rc = pthread_cond_broadcast( &m_hndl );
if( rc )
throw new SyncException( "Unable to notify condition" );
}
}
private:
version( Win32 )
{
bool timedWait( DWORD timeout )
{
int numSignalsLeft;
int numWaitersGone;
DWORD rc;
rc = WaitForSingleObject( m_blockLock, INFINITE );
assert( rc == WAIT_OBJECT_0 );
m_numWaitersBlocked++;
rc = ReleaseSemaphore( m_blockLock, 1, null );
assert( rc );
m_assocMutex.unlock();
scope(failure) m_assocMutex.lock();
rc = WaitForSingleObject( m_blockQueue, timeout );
assert( rc == WAIT_OBJECT_0 || rc == WAIT_TIMEOUT );
bool timedOut = (rc == WAIT_TIMEOUT);
EnterCriticalSection( &m_unblockLock );
scope(failure) LeaveCriticalSection( &m_unblockLock );
if( (numSignalsLeft = m_numWaitersToUnblock) != 0 )
{
if ( timedOut )
{
// timeout (or canceled)
if( m_numWaitersBlocked != 0 )
{
m_numWaitersBlocked--;
// do not unblock next waiter below (already unblocked)
numSignalsLeft = 0;
}
else
{
// spurious wakeup pending!!
m_numWaitersGone = 1;
}
}
if( --m_numWaitersToUnblock == 0 )
{
if( m_numWaitersBlocked != 0 )
{
// open the gate
rc = ReleaseSemaphore( m_blockLock, 1, null );
assert( rc );
// do not open the gate below again
numSignalsLeft = 0;
}
else if( (numWaitersGone = m_numWaitersGone) != 0 )
{
m_numWaitersGone = 0;
}
}
}
else if( ++m_numWaitersGone == int.max / 2 )
{
// timeout/canceled or spurious event :-)
rc = WaitForSingleObject( m_blockLock, INFINITE );
assert( rc == WAIT_OBJECT_0 );
// something is going on here - test of timeouts?
m_numWaitersBlocked -= m_numWaitersGone;
rc = ReleaseSemaphore( m_blockLock, 1, null );
assert( rc == WAIT_OBJECT_0 );
m_numWaitersGone = 0;
}
LeaveCriticalSection( &m_unblockLock );
if( numSignalsLeft == 1 )
{
// better now than spurious later (same as ResetEvent)
for( ; numWaitersGone > 0; --numWaitersGone )
{
rc = WaitForSingleObject( m_blockQueue, INFINITE );
assert( rc == WAIT_OBJECT_0 );
}
// open the gate
rc = ReleaseSemaphore( m_blockLock, 1, null );
assert( rc );
}
else if( numSignalsLeft != 0 )
{
// unblock next waiter
rc = ReleaseSemaphore( m_blockQueue, 1, null );
assert( rc );
}
m_assocMutex.lock();
return !timedOut;
}
void notify( bool all )
{
DWORD rc;
EnterCriticalSection( &m_unblockLock );
scope(failure) LeaveCriticalSection( &m_unblockLock );
if( m_numWaitersToUnblock != 0 )
{
if( m_numWaitersBlocked == 0 )
{
LeaveCriticalSection( &m_unblockLock );
return;
}
if( all )
{
m_numWaitersToUnblock += m_numWaitersBlocked;
m_numWaitersBlocked = 0;
}
else
{
m_numWaitersToUnblock++;
m_numWaitersBlocked--;
}
LeaveCriticalSection( &m_unblockLock );
}
else if( m_numWaitersBlocked > m_numWaitersGone )
{
rc = WaitForSingleObject( m_blockLock, INFINITE );
assert( rc == WAIT_OBJECT_0 );
if( 0 != m_numWaitersGone )
{
m_numWaitersBlocked -= m_numWaitersGone;
m_numWaitersGone = 0;
}
if( all )
{
m_numWaitersToUnblock = m_numWaitersBlocked;
m_numWaitersBlocked = 0;
}
else
{
m_numWaitersToUnblock = 1;
m_numWaitersBlocked--;
}
LeaveCriticalSection( &m_unblockLock );
rc = ReleaseSemaphore( m_blockQueue, 1, null );
assert( rc );
}
else
{
LeaveCriticalSection( &m_unblockLock );
}
}
// NOTE: This implementation uses Algorithm 8c as described here:
// http://groups.google.com/group/comp.programming.threads/
// browse_frm/thread/1692bdec8040ba40/e7a5f9d40e86503a
HANDLE m_blockLock; // auto-reset event (now semaphore)
HANDLE m_blockQueue; // auto-reset event (now semaphore)
Mutex m_assocMutex; // external mutex/CS
CRITICAL_SECTION m_unblockLock; // internal mutex/CS
int m_numWaitersGone = 0;
int m_numWaitersBlocked = 0;
int m_numWaitersToUnblock = 0;
}
else version( Posix )
{
pthread_cond_t m_hndl;
pthread_mutex_t* m_mutexAddr;
}
}
////////////////////////////////////////////////////////////////////////////////
// Unit Tests
////////////////////////////////////////////////////////////////////////////////
version( unittest )
{
private import core.thread;
private import core.sync.mutex;
private import core.sync.semaphore;
void testNotify()
{
auto mutex = new Mutex;
auto condReady = new Condition( mutex );
auto semDone = new Semaphore;
auto synLoop = new Object;
int numWaiters = 10;
int numTries = 10;
int numReady = 0;
int numTotal = 0;
int numDone = 0;
int numPost = 0;
void waiter()
{
for( int i = 0; i < numTries; ++i )
{
synchronized( mutex )
{
while( numReady < 1 )
{
condReady.wait();
}
--numReady;
++numTotal;
}
synchronized( synLoop )
{
++numDone;
}
semDone.wait();
}
}
auto group = new ThreadGroup;
for( int i = 0; i < numWaiters; ++i )
group.create( &waiter );
for( int i = 0; i < numTries; ++i )
{
for( int j = 0; j < numWaiters; ++j )
{
synchronized( mutex )
{
++numReady;
condReady.notify();
}
}
while( true )
{
synchronized( synLoop )
{
if( numDone >= numWaiters )
break;
}
Thread.yield();
}
for( int j = 0; j < numWaiters; ++j )
{
semDone.notify();
}
}
group.joinAll();
assert( numTotal == numWaiters * numTries );
}
void testNotifyAll()
{
auto mutex = new Mutex;
auto condReady = new Condition( mutex );
int numWaiters = 10;
int numReady = 0;
int numDone = 0;
bool alert = false;
void waiter()
{
synchronized( mutex )
{
++numReady;
while( !alert )
condReady.wait();
++numDone;
}
}
auto group = new ThreadGroup;
for( int i = 0; i < numWaiters; ++i )
group.create( &waiter );
while( true )
{
synchronized( mutex )
{
if( numReady >= numWaiters )
{
alert = true;
condReady.notifyAll();
break;
}
}
Thread.yield();
}
group.joinAll();
assert( numReady == numWaiters && numDone == numWaiters );
}
void testWaitTimeout()
{
auto mutex = new Mutex;
auto condReady = new Condition( mutex );
bool waiting = false;
bool alertedOne = true;
bool alertedTwo = true;
void waiter()
{
synchronized( mutex )
{
waiting = true;
alertedOne = condReady.wait( 10_000_000 ); // 1s
alertedTwo = condReady.wait( 10_000_000 ); // 1s
}
}
auto thread = new Thread( &waiter );
thread.start();
while( true )
{
synchronized( mutex )
{
if( waiting )
{
condReady.notify();
break;
}
}
Thread.yield();
}
thread.join();
assert( waiting && alertedOne && !alertedTwo );
}
unittest
{
testNotify();
testNotifyAll();
testWaitTimeout();
}
}

View File

@@ -0,0 +1,72 @@
/**
* The config module contains utility routines and configuration information
* specific to this package.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.sync.config;
version( Posix )
{
private import core.sys.posix.time;
private import core.sys.posix.sys.time;
void mktspec( inout timespec t, long delta = 0 )
{
static if( is( typeof( clock_gettime ) ) )
{
clock_gettime( CLOCK_REALTIME, &t );
}
else
{
timeval tv;
gettimeofday( &tv, null );
(cast(byte*) &t)[0 .. t.sizeof] = 0;
t.tv_sec = cast(typeof(t.tv_sec)) tv.tv_sec;
t.tv_nsec = cast(typeof(t.tv_nsec)) tv.tv_usec * 1_000;
}
mvtspec( t, delta );
}
void mvtspec( inout timespec t, long delta )
{
if( delta == 0 )
return;
enum : uint
{
NANOS_PER_TICK = 100,
TICKS_PER_SECOND = 10_000_000,
NANOS_PER_SECOND = NANOS_PER_TICK * TICKS_PER_SECOND,
}
if( t.tv_sec.max - t.tv_sec < delta / TICKS_PER_SECOND )
{
t.tv_sec = t.tv_sec.max;
t.tv_nsec = 0;
}
else
{
t.tv_sec += cast(typeof(t.tv_sec)) (delta / TICKS_PER_SECOND);
long ns = (delta % TICKS_PER_SECOND) * NANOS_PER_TICK;
if( NANOS_PER_SECOND - t.tv_nsec > ns )
{
t.tv_nsec = cast(typeof(t.tv_nsec)) ns;
return;
}
t.tv_sec += 1;
t.tv_nsec += cast(typeof(t.tv_nsec)) (ns - NANOS_PER_SECOND);
}
}
}

View File

@@ -0,0 +1,26 @@
/**
* The barrier module provides a primitive for synchronizing the progress of
* a group of threads.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.sync.exception;
/**
* Base class for synchronization exceptions.
*/
class SyncException : Exception
{
this( string msg )
{
super( msg );
}
}

View File

@@ -0,0 +1,268 @@
/**
* The mutex module provides a primitive for maintaining mutually exclusive
* access.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.sync.mutex;
public import core.sync.exception;
version( Win32 )
{
private import core.sys.windows.windows;
}
else version( Posix )
{
private import core.sys.posix.pthread;
}
////////////////////////////////////////////////////////////////////////////////
// Mutex
//
// void lock();
// void unlock();
// bool tryLock();
////////////////////////////////////////////////////////////////////////////////
/**
* This class represents a general purpose, recursive mutex.
*/
class Mutex :
Object.Monitor
{
////////////////////////////////////////////////////////////////////////////
// Initialization
////////////////////////////////////////////////////////////////////////////
/**
* Initializes a mutex object.
*
* Throws:
* SyncException on error.
*/
this()
{
version( Win32 )
{
InitializeCriticalSection( &m_hndl );
}
else version( Posix )
{
int rc = pthread_mutex_init( &m_hndl, &sm_attr );
if( rc )
throw new SyncException( "Unable to initialize mutex" );
}
m_proxy.link = this;
// NOTE: With DMD this can be "this.__monitor = &m_proxy".
(cast(void**) this)[1] = &m_proxy;
}
/**
* Initializes a mutex object and sets it as the monitor for o.
*
* In:
* o must not already have a monitor.
*/
this( Object o )
in
{
// NOTE: With DMD this can be "o.__monitor is null".
assert( (cast(void**) o)[1] is null );
}
body
{
this();
// NOTE: With DMD this can be "o.__monitor = &m_proxy".
(cast(void**) o)[1] = &m_proxy;
}
~this()
{
version( Win32 )
{
DeleteCriticalSection( &m_hndl );
}
else version( Posix )
{
int rc = pthread_mutex_destroy( &m_hndl );
assert( !rc, "Unable to destroy mutex" );
}
(cast(void**) this)[1] = null;
}
////////////////////////////////////////////////////////////////////////////
// General Actions
////////////////////////////////////////////////////////////////////////////
/**
* If this lock is not already held by the caller, the lock is acquired,
* then the internal counter is incremented by one.
*
* Throws:
* SyncException on error.
*/
void lock()
{
version( Win32 )
{
EnterCriticalSection( &m_hndl );
}
else version( Posix )
{
int rc = pthread_mutex_lock( &m_hndl );
if( rc )
throw new SyncException( "Unable to lock mutex" );
}
}
/**
* Decrements the internal lock count by one. If this brings the count to
* zero, the lock is released.
*
* Throws:
* SyncException on error.
*/
void unlock()
{
version( Win32 )
{
LeaveCriticalSection( &m_hndl );
}
else version( Posix )
{
int rc = pthread_mutex_unlock( &m_hndl );
if( rc )
throw new SyncException( "Unable to unlock mutex" );
}
}
/**
* If the lock is held by another caller, the method returns. Otherwise,
* the lock is acquired if it is not already held, and then the internal
* counter is incremented by one.
*
* Throws:
* SyncException on error.
*
* Returns:
* true if the lock was acquired and false if not.
*/
bool tryLock()
{
version( Win32 )
{
return TryEnterCriticalSection( &m_hndl ) != 0;
}
else version( Posix )
{
return pthread_mutex_trylock( &m_hndl ) == 0;
}
}
version( Posix )
{
static this()
{
int rc = pthread_mutexattr_init( &sm_attr );
assert( !rc );
rc = pthread_mutexattr_settype( &sm_attr, PTHREAD_MUTEX_RECURSIVE );
assert( !rc );
}
static ~this()
{
int rc = pthread_mutexattr_destroy( &sm_attr );
assert( !rc );
}
}
private:
version( Win32 )
{
CRITICAL_SECTION m_hndl;
}
else version( Posix )
{
__gshared pthread_mutexattr_t sm_attr;
pthread_mutex_t m_hndl;
}
struct MonitorProxy
{
Object.Monitor link;
}
MonitorProxy m_proxy;
package:
version( Posix )
{
pthread_mutex_t* handleAddr()
{
return &m_hndl;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Unit Tests
////////////////////////////////////////////////////////////////////////////////
version( unittest )
{
private import core.thread;
unittest
{
auto mutex = new Mutex;
int numThreads = 10;
int numTries = 1000;
int lockCount = 0;
void testFn()
{
for( int i = 0; i < numTries; ++i )
{
synchronized( mutex )
{
++lockCount;
}
}
}
auto group = new ThreadGroup;
for( int i = 0; i < numThreads; ++i )
group.create( &testFn );
group.joinAll();
assert( lockCount == numThreads * numTries );
}
}

View File

@@ -0,0 +1,512 @@
/**
* The read/write mutex module provides a primitive for maintaining shared read
* access and mutually exclusive write access.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.sync.rwmutex;
public import core.sync.exception;
private import core.sync.condition;
private import core.sync.mutex;
version( Win32 )
{
private import core.sys.windows.windows;
}
else version( Posix )
{
private import core.sys.posix.pthread;
}
////////////////////////////////////////////////////////////////////////////////
// ReadWriteMutex
//
// Reader reader();
// Writer writer();
////////////////////////////////////////////////////////////////////////////////
/**
* This class represents a mutex that allows any number of readers to enter,
* but when a writer enters, all other readers and writers are blocked.
*
* Please note that this mutex is not recursive and is intended to guard access
* to data only. Also, no deadlock checking is in place because doing so would
* require dynamic memory allocation, which would reduce performance by an
* unacceptable amount. As a result, any attempt to recursively acquire this
* mutex may well deadlock the caller, particularly if a write lock is acquired
* while holding a read lock, or vice-versa. In practice, this should not be
* an issue however, because it is uncommon to call deeply into unknown code
* while holding a lock that simply protects data.
*/
class ReadWriteMutex
{
/**
* Defines the policy used by this mutex. Currently, two policies are
* defined.
*
* The first will queue writers until no readers hold the mutex, then
* pass the writers through one at a time. If a reader acquires the mutex
* while there are still writers queued, the reader will take precedence.
*
* The second will queue readers if there are any writers queued. Writers
* are passed through one at a time, and once there are no writers present,
* all queued readers will be alerted.
*
* Future policies may offer a more even balance between reader and writer
* precedence.
*/
enum Policy
{
PREFER_READERS, /// Readers get preference. This may starve writers.
PREFER_WRITERS /// Writers get preference. This may starve readers.
}
////////////////////////////////////////////////////////////////////////////
// Initialization
////////////////////////////////////////////////////////////////////////////
/**
* Initializes a read/write mutex object with the supplied policy.
*
* Params:
* policy = The policy to use.
*
* Throws:
* SyncException on error.
*/
this( Policy policy = Policy.PREFER_WRITERS )
{
m_commonMutex = new Mutex;
if( !m_commonMutex )
throw new SyncException( "Unable to initialize mutex" );
scope(failure) delete m_commonMutex;
m_readerQueue = new Condition( m_commonMutex );
if( !m_readerQueue )
throw new SyncException( "Unable to initialize mutex" );
scope(failure) delete m_readerQueue;
m_writerQueue = new Condition( m_commonMutex );
if( !m_writerQueue )
throw new SyncException( "Unable to initialize mutex" );
scope(failure) delete m_writerQueue;
m_policy = policy;
m_reader = new Reader;
m_writer = new Writer;
}
////////////////////////////////////////////////////////////////////////////
// General Properties
////////////////////////////////////////////////////////////////////////////
/**
* Gets the policy for the associated mutex.
*
* Returns:
* The policy used by this mutex.
*/
Policy policy()
{
return m_policy;
}
////////////////////////////////////////////////////////////////////////////
// Reader/Writer Handles
////////////////////////////////////////////////////////////////////////////
/**
* Gets an object representing the reader lock for the associated mutex.
*
* Returns:
* A reader sub-mutex.
*/
Reader reader()
{
return m_reader;
}
/**
* Gets an object representing the writer lock for the associated mutex.
*
* Returns:
* A writer sub-mutex.
*/
Writer writer()
{
return m_writer;
}
////////////////////////////////////////////////////////////////////////////
// Reader
////////////////////////////////////////////////////////////////////////////
/**
* This class can be considered a mutex in its own right, and is used to
* negotiate a read lock for the enclosing mutex.
*/
class Reader :
Object.Monitor
{
/**
* Initializes a read/write mutex reader proxy object.
*/
this()
{
m_proxy.link = this;
(cast(void**) this)[1] = &m_proxy;
}
/**
* Acquires a read lock on the enclosing mutex.
*/
void lock()
{
synchronized( m_commonMutex )
{
++m_numQueuedReaders;
scope(exit) --m_numQueuedReaders;
while( shouldQueueReader() )
m_readerQueue.wait();
++m_numActiveReaders;
}
}
/**
* Releases a read lock on the enclosing mutex.
*/
void unlock()
{
synchronized( m_commonMutex )
{
if( --m_numActiveReaders < 1 )
{
if( m_numQueuedWriters > 0 )
m_writerQueue.notify();
}
}
}
/**
* Attempts to acquire a read lock on the enclosing mutex. If one can
* be obtained without blocking, the lock is acquired and true is
* returned. If not, the lock is not acquired and false is returned.
*
* Returns:
* true if the lock was acquired and false if not.
*/
bool tryLock()
{
synchronized( m_commonMutex )
{
if( shouldQueueReader() )
return false;
++m_numActiveReaders;
return true;
}
}
private:
bool shouldQueueReader()
{
if( m_numActiveWriters > 0 )
return true;
switch( m_policy )
{
case Policy.PREFER_WRITERS:
return m_numQueuedWriters > 0;
case Policy.PREFER_READERS:
default:
break;
}
return false;
}
struct MonitorProxy
{
Object.Monitor link;
}
MonitorProxy m_proxy;
}
////////////////////////////////////////////////////////////////////////////
// Writer
////////////////////////////////////////////////////////////////////////////
/**
* This class can be considered a mutex in its own right, and is used to
* negotiate a write lock for the enclosing mutex.
*/
class Writer :
Object.Monitor
{
/**
* Initializes a read/write mutex writer proxy object.
*/
this()
{
m_proxy.link = this;
(cast(void**) this)[1] = &m_proxy;
}
/**
* Acquires a write lock on the enclosing mutex.
*/
void lock()
{
synchronized( m_commonMutex )
{
++m_numQueuedWriters;
scope(exit) --m_numQueuedWriters;
while( shouldQueueWriter() )
m_writerQueue.wait();
++m_numActiveWriters;
}
}
/**
* Releases a write lock on the enclosing mutex.
*/
void unlock()
{
synchronized( m_commonMutex )
{
if( --m_numActiveWriters < 1 )
{
switch( m_policy )
{
default:
case Policy.PREFER_READERS:
if( m_numQueuedReaders > 0 )
m_readerQueue.notifyAll();
else if( m_numQueuedWriters > 0 )
m_writerQueue.notify();
break;
case Policy.PREFER_WRITERS:
if( m_numQueuedWriters > 0 )
m_writerQueue.notify();
else if( m_numQueuedReaders > 0 )
m_readerQueue.notifyAll();
}
}
}
}
/**
* Attempts to acquire a write lock on the enclosing mutex. If one can
* be obtained without blocking, the lock is acquired and true is
* returned. If not, the lock is not acquired and false is returned.
*
* Returns:
* true if the lock was acquired and false if not.
*/
bool tryLock()
{
synchronized( m_commonMutex )
{
if( shouldQueueWriter() )
return false;
++m_numActiveWriters;
return true;
}
}
private:
bool shouldQueueWriter()
{
if( m_numActiveWriters > 0 ||
m_numActiveReaders > 0 )
return true;
switch( m_policy )
{
case Policy.PREFER_READERS:
return m_numQueuedReaders > 0;
case Policy.PREFER_WRITERS:
default:
break;
}
return false;
}
struct MonitorProxy
{
Object.Monitor link;
}
MonitorProxy m_proxy;
}
private:
Policy m_policy;
Reader m_reader;
Writer m_writer;
Mutex m_commonMutex;
Condition m_readerQueue;
Condition m_writerQueue;
int m_numQueuedReaders;
int m_numActiveReaders;
int m_numQueuedWriters;
int m_numActiveWriters;
}
////////////////////////////////////////////////////////////////////////////////
// Unit Tests
////////////////////////////////////////////////////////////////////////////////
version( unittest )
{
static if( !is( typeof( Thread ) ) )
private import core.thread;
void testRead( ReadWriteMutex.Policy policy )
{
auto mutex = new ReadWriteMutex( policy );
auto synInfo = new Object;
int numThreads = 10;
int numReaders = 0;
int maxReaders = 0;
void readerFn()
{
synchronized( mutex.reader() )
{
synchronized( synInfo )
{
if( ++numReaders > maxReaders )
maxReaders = numReaders;
}
Thread.sleep( 100_000 ); // 1ms
synchronized( synInfo )
{
--numReaders;
}
}
}
auto group = new ThreadGroup;
for( int i = 0; i < numThreads; ++i )
{
group.create( &readerFn );
}
group.joinAll();
assert( numReaders < 1 && maxReaders > 1 );
}
void testReadWrite( ReadWriteMutex.Policy policy )
{
auto mutex = new ReadWriteMutex( policy );
auto synInfo = new Object;
int numThreads = 10;
int numReaders = 0;
int numWriters = 0;
int maxReaders = 0;
int maxWriters = 0;
int numTries = 20;
void readerFn()
{
for( int i = 0; i < numTries; ++i )
{
synchronized( mutex.reader() )
{
synchronized( synInfo )
{
if( ++numReaders > maxReaders )
maxReaders = numReaders;
}
Thread.sleep( 100_000 ); // 1ms
synchronized( synInfo )
{
--numReaders;
}
}
}
}
void writerFn()
{
for( int i = 0; i < numTries; ++i )
{
synchronized( mutex.writer() )
{
synchronized( synInfo )
{
if( ++numWriters > maxWriters )
maxWriters = numWriters;
}
Thread.sleep( 100_000 ); // 1ms
synchronized( synInfo )
{
--numWriters;
}
}
}
}
auto group = new ThreadGroup;
for( int i = 0; i < numThreads; ++i )
{
group.create( &readerFn );
group.create( &writerFn );
}
group.joinAll();
assert( numReaders < 1 && maxReaders > 1 &&
numWriters < 1 && maxWriters < 2 );
}
unittest
{
testRead( ReadWriteMutex.Policy.PREFER_READERS );
testRead( ReadWriteMutex.Policy.PREFER_WRITERS );
testReadWrite( ReadWriteMutex.Policy.PREFER_READERS );
testReadWrite( ReadWriteMutex.Policy.PREFER_WRITERS );
}
}

View File

@@ -0,0 +1,506 @@
/**
* The semaphore module provides a general use semaphore for synchronization.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.sync.semaphore;
public import core.sync.exception;
version( Win32 )
{
private import core.sys.windows.windows;
}
else version( OSX )
{
private import core.sync.config;
private import core.stdc.errno;
private import core.sys.posix.time;
private import core.sys.osx.mach.semaphore;
}
else version( Posix )
{
private import core.sync.config;
private import core.stdc.errno;
private import core.sys.posix.pthread;
private import core.sys.posix.semaphore;
}
////////////////////////////////////////////////////////////////////////////////
// Semaphore
//
// void wait();
// void notify();
// bool tryWait();
////////////////////////////////////////////////////////////////////////////////
/**
* This class represents a general counting semaphore as concieved by Edsger
* Dijkstra. As per Mesa type monitors however, "signal" has been replaced
* with "notify" to indicate that control is not transferred to the waiter when
* a notification is sent.
*/
class Semaphore
{
////////////////////////////////////////////////////////////////////////////
// Initialization
////////////////////////////////////////////////////////////////////////////
/**
* Initializes a semaphore object with the specified initial count.
*
* Params:
* count = The initial count for the semaphore.
*
* Throws:
* SyncException on error.
*/
this( uint count = 0 )
{
version( Win32 )
{
m_hndl = CreateSemaphoreA( null, count, int.max, null );
if( m_hndl == m_hndl.init )
throw new SyncException( "Unable to create semaphore" );
}
else version( OSX )
{
auto rc = semaphore_create( mach_task_self(), &m_hndl, SYNC_POLICY_FIFO, count );
if( rc )
throw new SyncException( "Unable to create semaphore" );
}
else version( Posix )
{
int rc = sem_init( &m_hndl, 0, count );
if( rc )
throw new SyncException( "Unable to create semaphore" );
}
}
~this()
{
version( Win32 )
{
BOOL rc = CloseHandle( m_hndl );
assert( rc, "Unable to destroy semaphore" );
}
else version( OSX )
{
auto rc = semaphore_destroy( mach_task_self(), m_hndl );
assert( !rc, "Unable to destroy semaphore" );
}
else version( Posix )
{
int rc = sem_destroy( &m_hndl );
assert( !rc, "Unable to destroy semaphore" );
}
}
////////////////////////////////////////////////////////////////////////////
// General Actions
////////////////////////////////////////////////////////////////////////////
/**
* Wait until the current count is above zero, then atomically decrement
* the count by one and return.
*
* Throws:
* SyncException on error.
*/
void wait()
{
version( Win32 )
{
DWORD rc = WaitForSingleObject( m_hndl, INFINITE );
if( rc != WAIT_OBJECT_0 )
throw new SyncException( "Unable to wait for semaphore" );
}
else version( OSX )
{
while( true )
{
auto rc = semaphore_wait( m_hndl );
if( !rc )
return;
if( rc == KERN_ABORTED && errno == EINTR )
continue;
throw new SyncException( "Unable to wait for semaphore" );
}
}
else version( Posix )
{
while( true )
{
if( !sem_wait( &m_hndl ) )
return;
if( errno != EINTR )
throw new SyncException( "Unable to wait for semaphore" );
}
}
}
/**
* Suspends the calling thread until the current count moves above zero or
* until the supplied time period has elapsed. If the count moves above
* zero in this interval, then atomically decrement the count by one and
* return true. Otherwise, return false.
*
*
* Params:
* period = The time to wait, in 100 nanosecond intervals. This value may
* be adjusted to equal to the maximum wait period supported by
* the target platform if it is too large.
*
* In:
* period must be non-negative.
*
* Throws:
* SyncException on error.
*
* Returns:
* true if notified before the timeout and false if not.
*/
bool wait( long period )
in
{
assert( period >= 0 );
}
body
{
version( Win32 )
{
enum : uint
{
TICKS_PER_MILLI = 10_000,
MAX_WAIT_MILLIS = uint.max - 1
}
period /= TICKS_PER_MILLI;
if( period > MAX_WAIT_MILLIS )
period = MAX_WAIT_MILLIS;
switch( WaitForSingleObject( m_hndl, cast(uint) period ) )
{
case WAIT_OBJECT_0:
return true;
case WAIT_TIMEOUT:
return false;
default:
throw new SyncException( "Unable to wait for semaphore" );
}
}
else version( OSX )
{
mach_timespec_t t = void;
(cast(byte*) &t)[0 .. t.sizeof] = 0;
if( period != 0 )
{
enum : uint
{
NANOS_PER_TICK = 100,
TICKS_PER_SECOND = 10_000_000,
NANOS_PER_SECOND = NANOS_PER_TICK * TICKS_PER_SECOND,
}
if( t.tv_sec.max - t.tv_sec < period / TICKS_PER_SECOND )
{
t.tv_sec = t.tv_sec.max;
t.tv_nsec = 0;
}
else
{
t.tv_sec += cast(typeof(t.tv_sec)) (period / TICKS_PER_SECOND);
long ns = (period % TICKS_PER_SECOND) * NANOS_PER_TICK;
if( NANOS_PER_SECOND - t.tv_nsec > ns )
t.tv_nsec = cast(typeof(t.tv_nsec)) ns;
else
{
t.tv_sec += 1;
t.tv_nsec += ns - NANOS_PER_SECOND;
}
}
}
while( true )
{
auto rc = semaphore_timedwait( m_hndl, t );
if( !rc )
return true;
if( rc == KERN_OPERATION_TIMED_OUT )
return false;
if( rc != KERN_ABORTED || errno != EINTR )
throw new SyncException( "Unable to wait for semaphore" );
}
// -w trip
return false;
}
else version( Posix )
{
timespec t = void;
mktspec( t, period );
while( true )
{
if( !sem_timedwait( &m_hndl, &t ) )
return true;
if( errno == ETIMEDOUT )
return false;
if( errno != EINTR )
throw new SyncException( "Unable to wait for semaphore" );
}
// -w trip
return false;
}
}
/**
* Atomically increment the current count by one. This will notify one
* waiter, if there are any in the queue.
*
* Throws:
* SyncException on error.
*/
void notify()
{
version( Win32 )
{
if( !ReleaseSemaphore( m_hndl, 1, null ) )
throw new SyncException( "Unable to notify semaphore" );
}
else version( OSX )
{
auto rc = semaphore_signal( m_hndl );
if( rc )
throw new SyncException( "Unable to notify semaphore" );
}
else version( Posix )
{
int rc = sem_post( &m_hndl );
if( rc )
throw new SyncException( "Unable to notify semaphore" );
}
}
/**
* If the current count is equal to zero, return. Otherwise, atomically
* decrement the count by one and return true.
*
* Throws:
* SyncException on error.
*
* Returns:
* true if the count was above zero and false if not.
*/
bool tryWait()
{
version( Win32 )
{
switch( WaitForSingleObject( m_hndl, 0 ) )
{
case WAIT_OBJECT_0:
return true;
case WAIT_TIMEOUT:
return false;
default:
throw new SyncException( "Unable to wait for semaphore" );
}
}
else version( OSX )
{
return wait( 0 );
}
else version( Posix )
{
while( true )
{
if( !sem_trywait( &m_hndl ) )
return true;
if( errno == EAGAIN )
return false;
if( errno != EINTR )
throw new SyncException( "Unable to wait for semaphore" );
}
// -w trip
return false;
}
}
private:
version( Win32 )
{
HANDLE m_hndl;
}
else version( OSX )
{
semaphore_t m_hndl;
}
else version( Posix )
{
sem_t m_hndl;
}
}
////////////////////////////////////////////////////////////////////////////////
// Unit Tests
////////////////////////////////////////////////////////////////////////////////
version( unittest )
{
private import core.thread;
void testWait()
{
auto semaphore = new Semaphore;
int numToProduce = 10;
bool allProduced = false;
auto synProduced = new Object;
int numConsumed = 0;
auto synConsumed = new Object;
int numConsumers = 10;
int numComplete = 0;
auto synComplete = new Object;
void consumer()
{
while( true )
{
semaphore.wait();
synchronized( synProduced )
{
if( allProduced )
break;
}
synchronized( synConsumed )
{
++numConsumed;
}
}
synchronized( synComplete )
{
++numComplete;
}
}
void producer()
{
assert( !semaphore.tryWait() );
for( int i = 0; i < numToProduce; ++i )
{
semaphore.notify();
Thread.yield();
}
Thread.sleep( 10_000_000 ); // 1s
synchronized( synProduced )
{
allProduced = true;
}
for( int i = 0; i < numConsumers; ++i )
{
semaphore.notify();
Thread.yield();
}
for( int i = numConsumers * 10000; i > 0; --i )
{
synchronized( synComplete )
{
if( numComplete == numConsumers )
break;
}
Thread.yield();
}
synchronized( synComplete )
{
assert( numComplete == numConsumers );
}
synchronized( synConsumed )
{
assert( numConsumed == numToProduce );
}
assert( !semaphore.tryWait() );
semaphore.notify();
assert( semaphore.tryWait() );
assert( !semaphore.tryWait() );
}
auto group = new ThreadGroup;
for( int i = 0; i < numConsumers; ++i )
group.create( &consumer );
group.create( &producer );
group.joinAll();
}
void testWaitTimeout()
{
auto synReady = new Object;
auto semReady = new Semaphore;
bool waiting = false;
bool alertedOne = true;
bool alertedTwo = true;
void waiter()
{
synchronized( synReady )
{
waiting = true;
}
alertedOne = semReady.wait( 10_000_000 ); // 100ms
alertedTwo = semReady.wait( 10_000_000 ); // 100ms
}
auto thread = new Thread( &waiter );
thread.start();
while( true )
{
synchronized( synReady )
{
if( waiting )
{
semReady.notify();
break;
}
}
Thread.yield();
}
thread.join();
assert( waiting && alertedOne && !alertedTwo );
}
unittest
{
testWait();
testWaitTimeout();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
/**
* Support code for mutithreading.
*
* Copyright: Copyright Mikola Lysenko 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Mikola Lysenko
*
* Copyright Mikola Lysenko 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
/************************************************************************************
* POWER PC ASM BITS
************************************************************************************/
#if defined( __ppc__ ) || defined( __PPC__ ) || defined( __powerpc__ )
/**
* Performs a context switch.
*
* r3 - old context pointer
* r4 - new context pointer
*
*/
.text
.align 2
.globl _fiber_switchContext
_fiber_switchContext:
/* Save linkage area */
mflr r0
mfcr r5
stw r0, 8(r1)
stw r5, 4(r1)
/* Save GPRs */
stw r11, (-1 * 4)(r1)
stw r13, (-2 * 4)(r1)
stw r14, (-3 * 4)(r1)
stw r15, (-4 * 4)(r1)
stw r16, (-5 * 4)(r1)
stw r17, (-6 * 4)(r1)
stw r18, (-7 * 4)(r1)
stw r19, (-8 * 4)(r1)
stw r20, (-9 * 4)(r1)
stw r21, (-10 * 4)(r1)
stw r22, (-11 * 4)(r1)
stw r23, (-12 * 4)(r1)
stw r24, (-13 * 4)(r1)
stw r25, (-14 * 4)(r1)
stw r26, (-15 * 4)(r1)
stw r27, (-16 * 4)(r1)
stw r28, (-17 * 4)(r1)
stw r29, (-18 * 4)(r1)
stw r30, (-19 * 4)(r1)
stwu r31, (-20 * 4)(r1)
/* We update the stack pointer here, since we do not want the GC to
scan the floating point registers. */
/* Save FPRs */
stfd f14, (-1 * 8)(r1)
stfd f15, (-2 * 8)(r1)
stfd f16, (-3 * 8)(r1)
stfd f17, (-4 * 8)(r1)
stfd f18, (-5 * 8)(r1)
stfd f19, (-6 * 8)(r1)
stfd f20, (-7 * 8)(r1)
stfd f21, (-8 * 8)(r1)
stfd f22, (-9 * 8)(r1)
stfd f23, (-10 * 8)(r1)
stfd f24, (-11 * 8)(r1)
stfd f25, (-12 * 8)(r1)
stfd f26, (-13 * 8)(r1)
stfd f27, (-14 * 8)(r1)
stfd f28, (-15 * 8)(r1)
stfd f29, (-16 * 8)(r1)
stfd f30, (-17 * 8)(r1)
stfd f31, (-18 * 8)(r1)
/* Update the old stack pointer */
stw r1, 0(r3)
/* Set new stack pointer */
addi r1, r4, 20 * 4
/* Restore linkage area */
lwz r0, 8(r1)
lwz r5, 4(r1)
/* Restore GPRs */
lwz r11, (-1 * 4)(r1)
lwz r13, (-2 * 4)(r1)
lwz r14, (-3 * 4)(r1)
lwz r15, (-4 * 4)(r1)
lwz r16, (-5 * 4)(r1)
lwz r17, (-6 * 4)(r1)
lwz r18, (-7 * 4)(r1)
lwz r19, (-8 * 4)(r1)
lwz r20, (-9 * 4)(r1)
lwz r21, (-10 * 4)(r1)
lwz r22, (-11 * 4)(r1)
lwz r23, (-12 * 4)(r1)
lwz r24, (-13 * 4)(r1)
lwz r25, (-14 * 4)(r1)
lwz r26, (-15 * 4)(r1)
lwz r27, (-16 * 4)(r1)
lwz r28, (-17 * 4)(r1)
lwz r29, (-18 * 4)(r1)
lwz r30, (-19 * 4)(r1)
lwz r31, (-20 * 4)(r1)
/* Restore FPRs */
lfd f14, (-1 * 8)(r4)
lfd f15, (-2 * 8)(r4)
lfd f16, (-3 * 8)(r4)
lfd f17, (-4 * 8)(r4)
lfd f18, (-5 * 8)(r4)
lfd f19, (-6 * 8)(r4)
lfd f20, (-7 * 8)(r4)
lfd f21, (-8 * 8)(r4)
lfd f22, (-9 * 8)(r4)
lfd f23, (-10 * 8)(r4)
lfd f24, (-11 * 8)(r4)
lfd f25, (-12 * 8)(r4)
lfd f26, (-13 * 8)(r4)
lfd f27, (-14 * 8)(r4)
lfd f28, (-15 * 8)(r4)
lfd f29, (-16 * 8)(r4)
lfd f30, (-17 * 8)(r4)
lfd f31, (-18 * 8)(r4)
/* Set condition and link register */
mtcr r5
mtlr r0
/* Return and switch context */
blr
#endif

View File

@@ -0,0 +1,81 @@
/**
* The vararg module is intended to facilitate vararg manipulation in D.
* It should be interface compatible with the C module "stdarg," and the
* two modules may share a common implementation if possible (as is done
* here).
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Hauke Duden
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.vararg;
/**
* The base vararg list type.
*/
alias void* va_list;
/**
* This function initializes the supplied argument pointer for subsequent
* use by va_arg and va_end.
*
* Params:
* ap = The argument pointer to initialize.
* paramn = The identifier of the rightmost parameter in the function
* parameter list.
*/
void va_start(T) ( out va_list ap, inout T parmn )
{
ap = cast(va_list) ( cast(void*) &parmn + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) );
}
/**
* This function returns the next argument in the sequence referenced by
* the supplied argument pointer. The argument pointer will be adjusted
* to point to the next arggument in the sequence.
*
* Params:
* ap = The argument pointer.
*
* Returns:
* The next argument in the sequence. The result is undefined if ap
* does not point to a valid argument.
*/
T va_arg(T) ( inout va_list ap )
{
T arg = *cast(T*) ap;
ap = cast(va_list) ( cast(void*) ap + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) );
return arg;
}
/**
* This function cleans up any resources allocated by va_start. It is
* currently a no-op and exists mostly for syntax compatibility with
* the variadric argument functions for C.
*
* Params:
* ap = The argument pointer.
*/
void va_end( va_list ap )
{
}
/**
* This function copied the argument pointer src to dst.
*
* Params:
* src = The source pointer.
* dst = The destination pointer.
*/
void va_copy( out va_list dst, va_list src )
{
dst = src;
}

View File

@@ -0,0 +1,81 @@
# Makefile to build the D runtime library core components for Posix
# Designed to work with GNU make
# Targets:
# make
# Same as make all
# make debug
# Build the debug version of the library
# make release
# Build the release version of the library
# make doc
# Generate documentation
# make clean
# Delete all files created by build process
# Essentials
LIBDIR=../../lib
DOCDIR=../../doc
IMPDIR=../../import
LIBBASENAME=libdruntime-core.a
MODULES=bitop exception memory runtime thread vararg \
$(addprefix sync/,barrier condition config exception mutex rwmutex semaphore)
BUILDS=debug release unittest
# Symbols
DMD=dmd
CLC=ar rsv
DOCFLAGS=-version=DDoc
DFLAGS_release=-d -release -O -inline -w
DFLAGS_debug=-d -g -w
DFLAGS_unittest=$(DFLAGS_release) -unittest
CFLAGS_release= -O
CFLAGS_debug= -g
CFLAGS_unittest=$(CFLAGS_release)
# Derived symbols
C_SRCS=core/stdc/errno.c #core/threadasm.S
C_OBJS=errno.o threadasm.o
AS_OBJS=$(addsuffix .o,$(basename $(AS_SRCS)))
D_SRCS=$(addsuffix .d,$(addprefix core/,$(MODULES))) \
$(addsuffix .d,$(addprefix $(IMPDIR)/core/stdc/,math stdarg stdio wchar_)) \
$(addsuffix .d,$(addprefix $(IMPDIR)/core/sys/posix/,netinet/in_ sys/select sys/socket sys/stat sys/wait))
ALL_OBJS_O=$(addsuffix .o,$(addprefix core/,$(MODULES))) \
$(addsuffix .o,$(addprefix $(IMPDIR)/core/stdc/,math stdarg stdio wchar_)) \
$(addsuffix .o,$(addprefix $(IMPDIR)/core/sys/posix/,netinet/in_ sys/select sys/socket sys/stat sys/wait)) \
$(AS_OBJS) $(C_OBJS)
DOCS=$(addsuffix .html,$(addprefix $(DOCDIR)/core/,$(MODULES)))
IMPORTS=$(addsuffix .di,$(addprefix $(IMPDIR)/core/,$(MODULES)))
ALLLIBS=$(addsuffix /$(LIBBASENAME),$(addprefix $(LIBDIR)/,$(BUILDS)))
# Patterns
$(LIBDIR)/%/$(LIBBASENAME) : $(D_SRCS) $(C_SRCS)
$(CC) -c $(CFLAGS_$*) $(C_SRCS)
ifeq ($(DMD),ldc2 -vv)
$(DMD) $(DFLAGS_$*) -of$@ $(D_SRCS)
$(CLC) $@ $(ALL_OBJS_O)
else
$(DMD) $(DFLAGS_$*) -lib -of$@ $(D_SRCS) $(C_OBJS)
endif
rm $(C_OBJS)
$(DOCDIR)/%.html : %.d
$(DMD) -c -d -o- -Df$@ $<
$(IMPDIR)/%.di : %.d
$(DMD) -c -d -o- -Hf$@ $<
# Rulez
all : $(BUILDS) doc
debug : $(LIBDIR)/debug/$(LIBBASENAME) $(IMPORTS)
release : $(LIBDIR)/release/$(LIBBASENAME) $(IMPORTS)
unittest : $(LIBDIR)/unittest/$(LIBBASENAME) $(IMPORTS)
doc : $(DOCS)
clean :
rm -f $(IMPORTS) $(DOCS) $(ALLLIBS)

View File

@@ -0,0 +1,226 @@
# Makefile to build the D runtime library core components for Posix
# Designed to work with GNU make
# Targets:
# make
# Same as make all
# make debug
# Build the debug version of the library
# make release
# Build the release version of the library
# make doc
# Generate documentation
# make clean
# Delete all files created by build process
# Essentials
LIBDIR=..\..\lib
DOCDIR=..\..\doc
IMPDIR=..\..\import
LIBBASENAME=druntime_core.lib
#MODULES=bitop exception memory runtime thread vararg \
# $(addprefix sync/,barrier condition config exception mutex rwmutex semaphore)
BUILDS=debug release unittest
# Symbols
CC=dmc
DMD=dmd
DOCFLAGS=-version=DDoc
DFLAGS_release=-d -release -O -inline -w -nofloat
DFLAGS_debug=-d -g -w -nofloat
DFLAGS_unittest=$(DFLAGS_release) -unittest
CFLAGS_release=-mn -6 -r
CFLAGS_debug=-g -mn -6 -r
CFLAGS_unittest=$(CFLAGS_release)
# Derived symbols
C_SRCS=core\stdc\errno.c
C_OBJS=errno.obj
D_SRCS=\
core\bitop.d \
core\exception.d \
core\memory.d \
core\runtime.d \
core\thread.d \
core\vararg.d \
\
core\sync\barrier.d \
core\sync\condition.d \
core\sync\config.d \
core\sync\exception.d \
core\sync\mutex.d \
core\sync\rwmutex.d \
core\sync\semaphore.d \
\
$(IMPDIR)\core\stdc\math.d \
$(IMPDIR)\core\stdc\stdarg.d \
$(IMPDIR)\core\stdc\stdio.d \
$(IMPDIR)\core\stdc\wchar_.d \
\
$(IMPDIR)\core\sys\windows\windows.d
DOCS=\
$(DOCDIR)\core\bitop.html \
$(DOCDIR)\core\exception.html \
$(DOCDIR)\core\memory.html \
$(DOCDIR)\core\runtime.html \
$(DOCDIR)\core\thread.html \
$(DOCDIR)\core\vararg.html \
\
$(DOCDIR)\core\sync\barrier.html \
$(DOCDIR)\core\sync\condition.html \
$(DOCDIR)\core\sync\config.html \
$(DOCDIR)\core\sync\exception.html \
$(DOCDIR)\core\sync\mutex.html \
$(DOCDIR)\core\sync\rwmutex.html \
$(DOCDIR)\core\sync\semaphore.html
IMPORTS=\
$(IMPDIR)\core\exception.di \
$(IMPDIR)\core\memory.di \
$(IMPDIR)\core\runtime.di \
$(IMPDIR)\core\thread.di \
$(IMPDIR)\core\vararg.di \
\
$(IMPDIR)\core\sync\barrier.di \
$(IMPDIR)\core\sync\condition.di \
$(IMPDIR)\core\sync\config.di \
$(IMPDIR)\core\sync\exception.di \
$(IMPDIR)\core\sync\mutex.di \
$(IMPDIR)\core\sync\rwmutex.di \
$(IMPDIR)\core\sync\semaphore.di
# bitop.di is already published
ALLLIBS=\
$(LIBDIR)\debug\$(LIBBASENAME) \
$(LIBDIR)\release\$(LIBBASENAME) \
$(LIBDIR)\unittest\$(LIBBASENAME)
# Patterns
#$(LIBDIR)\%\$(LIBBASENAME) : $(D_SRCS) $(C_SRCS)
# $(CC) -c $(CFLAGS_$*) $(C_SRCS)
# $(DMD) $(DFLAGS_$*) -lib -of$@ $(D_SRCS) $(C_OBJS)
# del $(C_OBJS)
#$(DOCDIR)\%.html : %.d
# $(DMD) -c -d -o- -Df$@ $<
#$(IMPDIR)\%.di : %.d
# $(DMD) -c -d -o- -Hf$@ $<
# Patterns - debug
$(LIBDIR)\debug\$(LIBBASENAME) : $(D_SRCS) $(C_SRCS)
$(CC) -c $(CFLAGS_debug) $(C_SRCS)
$(DMD) $(DFLAGS_debug) -lib -of$@ $(D_SRCS) $(C_OBJS)
del $(C_OBJS)
# Patterns - release
$(LIBDIR)\release\$(LIBBASENAME) : $(D_SRCS) $(C_SRCS)
$(CC) -c $(CFLAGS_release) $(C_SRCS)
$(DMD) $(DFLAGS_release) -lib -of$@ $(D_SRCS) $(C_OBJS)
del $(C_OBJS)
# Patterns - unittest
$(LIBDIR)\unittest\$(LIBBASENAME) : $(D_SRCS) $(C_SRCS)
$(CC) -c $(CFLAGS_unittest) $(C_SRCS)
$(DMD) $(DFLAGS_unittest) -lib -of$@ $(D_SRCS) $(C_OBJS)
del $(C_OBJS)
# Patterns - docs
$(DOCDIR)\core\bitop.html : core\bitop.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\exception.html : core\exception.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\memory.html : core\memory.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\runtime.html : core\runtime.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\thread.html : core\thread.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\vararg.html : core\vararg.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\sync\barrier.html : core\sync\barrier.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\sync\condition.html : core\sync\condition.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\sync\config.html : core\sync\config.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\sync\exception.html : core\sync\exception.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\sync\mutex.html : core\sync\mutex.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\sync\rwmutex.html : core\sync\rwmutex.d
$(DMD) -c -d -o- -Df$@ $**
$(DOCDIR)\core\sync\semaphore.html : core\sync\semaphore.d
$(DMD) -c -d -o- -Df$@ $**
# Patterns - imports
$(IMPDIR)\core\exception.di : core\exception.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\memory.di : core\memory.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\runtime.di : core\runtime.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\thread.di : core\thread.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\vararg.di : core\vararg.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\sync\barrier.di : core\sync\barrier.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\sync\condition.di : core\sync\condition.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\sync\config.di : core\sync\config.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\sync\exception.di : core\sync\exception.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\sync\mutex.di : core\sync\mutex.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\sync\rwmutex.di : core\sync\rwmutex.d
$(DMD) -c -d -o- -Hf$@ $**
$(IMPDIR)\core\sync\semaphore.di : core\sync\semaphore.d
$(DMD) -c -d -o- -Hf$@ $**
# Rulez
all : $(BUILDS) doc
debug : $(LIBDIR)\debug\$(LIBBASENAME) $(IMPORTS)
release : $(LIBDIR)\release\$(LIBBASENAME) $(IMPORTS)
unittest : $(LIBDIR)\unittest\$(LIBBASENAME) $(IMPORTS)
doc : $(DOCS)
clean :
del $(IMPORTS) $(DOCS) $(ALLLIBS)

View File

@@ -0,0 +1,386 @@
/**
* 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.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.aApply;
private import rt.util.utf;
/**********************************************
*/
// dg is D, but _aApplycd() is C
extern (D) typedef int delegate(void *) dg_t;
extern (C) int _aApplycd1(char[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplycd1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
d = aa[i];
if (d & 0x80)
d = decode(aa, i);
else
i++;
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplywd1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
d = aa[i];
if (d & ~0x7F)
d = decode(aa, i);
else
i++;
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplycw1(char[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplycw1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
wchar w;
w = aa[i];
if (w & 0x80)
{ d = decode(aa, i);
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
else
i++;
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplywc1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
wchar w;
char c;
w = aa[i];
if (w & ~0x7F)
{
char[4] buf;
d = decode(aa, i);
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)w;
i++;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
foreach (dchar d; aa)
{
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{
c = cast(char)d;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
foreach (dchar d; aa)
{
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
/****************************************************************************/
// dg is D, but _aApplycd2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
extern (C) int _aApplycd2(char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplycd2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
d = aa[i];
if (d & 0x80)
{
n = i;
d = decode(aa, n);
n -= i;
}
else
n = 1;
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplywd2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
d = aa[i];
if (d & ~0x7F)
{
n = i;
d = decode(aa, n);
n -= i;
}
else
n = 1;
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplycw2(char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplycw2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
wchar w;
w = aa[i];
if (w & 0x80)
{ n = i;
d = decode(aa, n);
n -= i;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
else
n = 1;
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplywc2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
wchar w;
char c;
w = aa[i];
if (w & ~0x7F)
{
char[4] buf;
n = i;
d = decode(aa, n);
n -= i;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)w;
n = 1;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplydc2(), len = %d\n", len);
for (i = 0; i < len; i++)
{ dchar d;
char c;
d = aa[i];
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)d;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
foreach (size_t i, dchar d; aa)
{
wchar w;
auto j = i;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&j, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(&j, cast(void *)&w);
if (result)
break;
}
return result;
}

View File

@@ -0,0 +1,957 @@
/**
* 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.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.aApplyR;
/* This code handles decoding UTF strings for foreach_reverse loops.
* There are 6 combinations of conversions between char, wchar,
* and dchar, and 2 of each of those.
*/
private import rt.util.utf;
/**********************************************/
/* 1 argument versions */
// dg is D, but _aApplyRcd() is C
extern (D) typedef int delegate(void *) dg_t;
extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d & 0x80)
{ char c = cast(char)d;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
}
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcd1.unittest\n");
auto s = "hello"c[];
int i;
foreach_reverse(dchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(dchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == '\U00100456'); break;
case 2: assert(d == '\u1234'); break;
case 3: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwd1.unittest\n");
auto s = "hello"w[];
int i;
foreach_reverse(dchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(dchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == '\U00100456'); break;
case 2: assert(d == '\u1234'); break;
case 3: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
wchar w;
i--;
w = aa[i];
if (w & 0x80)
{ char c = cast(char)w;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcw1.unittest\n");
auto s = "hello"c[];
int i;
foreach_reverse(wchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(wchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xDBC1); break;
case 2: assert(d == 0xDC56); break;
case 3: assert(d == 0x1234); break;
case 4: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/*****************************/
extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
char c;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
c = cast(char)d;
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwc1.unittest\n");
auto s = "hello"w[];
int i;
foreach_reverse(char d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(char d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xF4); break;
case 2: assert(d == 0x80); break;
case 3: assert(d == 0x91); break;
case 4: assert(d == 0x96); break;
case 5: assert(d == 0xE1); break;
case 6: assert(d == 0x88); break;
case 7: assert(d == 0xB4); break;
case 8: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0;)
{ dchar d = aa[--i];
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{
c = cast(char)d;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdc1.unittest\n");
auto s = "hello"d[];
int i;
foreach_reverse(char d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(char d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xF4); break;
case 2: assert(d == 0x80); break;
case 3: assert(d == 0x91); break;
case 4: assert(d == 0x96); break;
case 5: assert(d == 0xE1); break;
case 6: assert(d == 0x88); break;
case 7: assert(d == 0xB4); break;
case 8: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdw1.unittest\n");
auto s = "hello"d[];
int i;
foreach_reverse(wchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(wchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xDBC1); break;
case 2: assert(d == 0xDC56); break;
case 3: assert(d == 0x1234); break;
case 4: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/****************************************************************************/
/* 2 argument versions */
// dg is D, but _aApplyRcd2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
for (i = len; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d & 0x80)
{ char c = cast(char)d;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
}
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcd2.unittest\n");
auto s = "hello"c[];
int i;
foreach_reverse(k, dchar d; s)
{
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(d == 'b'); assert(k == 8); break;
case 1: assert(d == '\U00100456'); assert(k == 4); break;
case 2: assert(d == '\u1234'); assert(k == 1); break;
case 3: assert(d == 'a'); assert(k == 0); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwd2.unittest\n");
auto s = "hello"w[];
int i;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 4); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == '\U00100456'); break;
case 2: assert(k == 1); assert(d == '\u1234'); break;
case 3: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
wchar w;
i--;
w = aa[i];
if (w & 0x80)
{ char c = cast(char)w;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcw2.unittest\n");
auto s = "hello"c[];
int i;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 8); assert(d == 'b'); break;
case 1: assert(k == 4); assert(d == 0xDBC1); break;
case 2: assert(k == 4); assert(d == 0xDC56); break;
case 3: assert(k == 1); assert(d == 0x1234); break;
case 4: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/*****************************/
extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
char c;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
c = cast(char)d;
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwc2.unittest\n");
auto s = "hello"w[];
int i;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 4); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xF4); break;
case 2: assert(k == 2); assert(d == 0x80); break;
case 3: assert(k == 2); assert(d == 0x91); break;
case 4: assert(k == 2); assert(d == 0x96); break;
case 5: assert(k == 1); assert(d == 0xE1); break;
case 6: assert(k == 1); assert(d == 0x88); break;
case 7: assert(k == 1); assert(d == 0xB4); break;
case 8: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)d;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdc2.unittest\n");
auto s = "hello"d[];
int i;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 3); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xF4); break;
case 2: assert(k == 2); assert(d == 0x80); break;
case 3: assert(k == 2); assert(d == 0x91); break;
case 4: assert(k == 2); assert(d == 0x96); break;
case 5: assert(k == 1); assert(d == 0xE1); break;
case 6: assert(k == 1); assert(d == 0x88); break;
case 7: assert(k == 1); assert(d == 0xB4); break;
case 8: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdw2.unittest\n");
auto s = "hello"d[];
int i;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 3); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xDBC1); break;
case 2: assert(k == 2); assert(d == 0xDC56); break;
case 3: assert(k == 1); assert(d == 0x1234); break;
case 4: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}

View File

@@ -0,0 +1,872 @@
/**
* Implementation of associative arrays.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.aaA;
private
{
import core.stdc.stdarg;
import core.stdc.string;
import core.stdc.stdio;
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
immutable size_t[] prime_list = [
97UL, 389UL,
1_543UL, 6_151UL,
24_593UL, 98_317UL,
393_241UL, 1_572_869UL,
6_291_469UL, 25_165_843UL,
100_663_319UL, 402_653_189UL,
1_610_612_741UL, 4_294_967_291UL,
// 8_589_934_513UL, 17_179_869_143UL
];
/* This is the type of the return value for dynamic arrays.
* It should be a type that is returned in registers.
* Although DMD will return types of Array in registers,
* gcc will not, so we instead use a 'long'.
*/
alias long ArrayRet_t;
struct Array
{
size_t length;
void* ptr;
}
struct aaA
{
aaA *left;
aaA *right;
hash_t hash;
/* key */
/* value */
}
struct BB
{
aaA*[] b;
size_t nodes; // total number of aaA nodes
TypeInfo keyti; // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
}
/* This is the type actually seen by the programmer, although
* it is completely opaque.
*/
struct AA
{
BB* a;
}
/**********************************
* Align to next pointer boundary, so that
* GC won't be faced with misaligned pointers
* in value.
*/
size_t aligntsize(size_t tsize)
{
// Is pointer alignment on the x64 4 bytes or 8?
return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
}
extern (C):
/*************************************************
* Invariant for aa.
*/
/+
void _aaInvAh(aaA*[] aa)
{
for (size_t i = 0; i < aa.length; i++)
{
if (aa[i])
_aaInvAh_x(aa[i]);
}
}
private int _aaCmpAh_x(aaA *e1, aaA *e2)
{ int c;
c = e1.hash - e2.hash;
if (c == 0)
{
c = e1.key.length - e2.key.length;
if (c == 0)
c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
}
return c;
}
private void _aaInvAh_x(aaA *e)
{
hash_t key_hash;
aaA *e1;
aaA *e2;
key_hash = getHash(e.key);
assert(key_hash == e.hash);
while (1)
{ int c;
e1 = e.left;
if (e1)
{
_aaInvAh_x(e1); // ordinary recursion
do
{
c = _aaCmpAh_x(e1, e);
assert(c < 0);
e1 = e1.right;
} while (e1 != null);
}
e2 = e.right;
if (e2)
{
do
{
c = _aaCmpAh_x(e, e2);
assert(c < 0);
e2 = e2.left;
} while (e2 != null);
e = e.right; // tail recursion
}
else
break;
}
}
+/
/****************************************************
* Determine number of entries in associative array.
*/
size_t _aaLen(AA aa)
in
{
//printf("_aaLen()+\n");
//_aaInv(aa);
}
out (result)
{
size_t len = 0;
void _aaLen_x(aaA* ex)
{
auto e = ex;
len++;
while (1)
{
if (e.right)
_aaLen_x(e.right);
e = e.left;
if (!e)
break;
len++;
}
}
if (aa.a)
{
foreach (e; aa.a.b)
{
if (e)
_aaLen_x(e);
}
}
assert(len == result);
//printf("_aaLen()-\n");
}
body
{
return aa.a ? aa.a.nodes : 0;
}
/*************************************************
* Get pointer to value in associative array indexed by key.
* Add entry for key if it is not already there.
*/
void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
in
{
assert(aa);
}
out (result)
{
assert(result);
assert(aa.a);
assert(aa.a.b.length);
//assert(_aaInAh(*aa.a, key));
}
body
{
auto pkey = cast(void *)(&valuesize + 1);
size_t i;
aaA *e;
//printf("keyti = %p\n", keyti);
//printf("aa = %p\n", aa);
auto keysize = aligntsize(keyti.tsize());
if (!aa.a)
aa.a = new BB();
//printf("aa = %p\n", aa);
//printf("aa.a = %p\n", aa.a);
aa.a.keyti = keyti;
if (!aa.a.b.length)
{
alias aaA *pa;
auto len = prime_list[0];
aa.a.b = new pa[len];
}
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
i = key_hash % aa.a.b.length;
auto pe = &aa.a.b[i];
while ((e = *pe) !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
goto Lret;
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
// Not found, create new elem
//printf("create new one\n");
size_t size = aaA.sizeof + keysize + valuesize;
e = cast(aaA *) gc_calloc(size);
memcpy(e + 1, pkey, keysize);
e.hash = key_hash;
*pe = e;
auto nodes = ++aa.a.nodes;
//printf("length = %d, nodes = %d\n", aa.a.b.length, nodes);
if (nodes > aa.a.b.length * 4)
{
//printf("rehash\n");
_aaRehash(aa,keyti);
}
Lret:
return cast(void *)(e + 1) + keysize;
}
/*************************************************
* Get pointer to value in associative array indexed by key.
* Returns null if it is not already there.
*/
void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
{
//printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
if (!aa.a)
return null;
auto pkey = cast(void *)(&valuesize + 1);
auto keysize = aligntsize(keyti.tsize());
auto len = aa.a.b.length;
if (len)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % len;
auto e = aa.a.b[i];
while (e !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
return cast(void *)(e + 1) + keysize;
e = (c < 0) ? e.left : e.right;
}
else
e = (key_hash < e.hash) ? e.left : e.right;
}
}
return null; // not found, caller will throw exception
}
/*************************************************
* Determine if key is in aa.
* Returns:
* null not in aa
* !=null in aa, return pointer to value
*/
void* _aaIn(AA aa, TypeInfo keyti, ...)
in
{
}
out (result)
{
//assert(result == 0 || result == 1);
}
body
{
if (aa.a)
{
auto pkey = cast(void *)(&keyti + 1);
//printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
auto len = aa.a.b.length;
if (len)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % len;
auto e = aa.a.b[i];
while (e !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
return cast(void *)(e + 1) + aligntsize(keyti.tsize());
e = (c < 0) ? e.left : e.right;
}
else
e = (key_hash < e.hash) ? e.left : e.right;
}
}
}
// Not found
return null;
}
/*************************************************
* Delete key entry in aa[].
* If key is not in aa[], do nothing.
*/
void _aaDel(AA aa, TypeInfo keyti, ...)
{
auto pkey = cast(void *)(&keyti + 1);
aaA *e;
if (aa.a && aa.a.b.length)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % aa.a.b.length;
auto pe = &aa.a.b[i];
while ((e = *pe) !is null) // null means not found
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
{
if (!e.left && !e.right)
{
*pe = null;
}
else if (e.left && !e.right)
{
*pe = e.left;
e.left = null;
}
else if (!e.left && e.right)
{
*pe = e.right;
e.right = null;
}
else
{
*pe = e.left;
e.left = null;
do
pe = &(*pe).right;
while (*pe);
*pe = e.right;
e.right = null;
}
aa.a.nodes--;
gc_free(e);
break;
}
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
}
}
/********************************************
* Produce array of values from aa.
*/
ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
in
{
assert(keysize == aligntsize(keysize));
}
body
{
size_t resi;
Array a;
void _aaValues_x(aaA* e)
{
do
{
memcpy(a.ptr + resi * valuesize,
cast(byte*)e + aaA.sizeof + keysize,
valuesize);
resi++;
if (e.left)
{ if (!e.right)
{ e = e.left;
continue;
}
_aaValues_x(e.left);
}
e = e.right;
} while (e !is null);
}
if (aa.a)
{
a.length = _aaLen(aa);
a.ptr = cast(byte*) gc_malloc(a.length * valuesize,
valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
resi = 0;
foreach (e; aa.a.b)
{
if (e)
_aaValues_x(e);
}
assert(resi == a.length);
}
return *cast(ArrayRet_t*)(&a);
}
/********************************************
* Rehash an array.
*/
void* _aaRehash(AA* paa, TypeInfo keyti)
in
{
//_aaInvAh(paa);
}
out (result)
{
//_aaInvAh(result);
}
body
{
BB newb;
void _aaRehash_x(aaA* olde)
{
while (1)
{
auto left = olde.left;
auto right = olde.right;
olde.left = null;
olde.right = null;
aaA *e;
//printf("rehash %p\n", olde);
auto key_hash = olde.hash;
size_t i = key_hash % newb.b.length;
auto pe = &newb.b[i];
while ((e = *pe) !is null)
{
//printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
assert(e.left != e);
assert(e.right != e);
if (key_hash == e.hash)
{
auto c = keyti.compare(olde + 1, e + 1);
assert(c != 0);
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
*pe = olde;
if (right)
{
if (!left)
{ olde = right;
continue;
}
_aaRehash_x(right);
}
if (!left)
break;
olde = left;
}
}
//printf("Rehash\n");
if (paa.a)
{
auto aa = paa.a;
auto len = _aaLen(*paa);
if (len)
{ size_t i;
for (i = 0; i < prime_list.length - 1; i++)
{
if (len <= prime_list[i])
break;
}
len = prime_list[i];
newb.b = new aaA*[len];
foreach (e; aa.b)
{
if (e)
_aaRehash_x(e);
}
delete aa.b;
newb.nodes = aa.nodes;
newb.keyti = aa.keyti;
}
*paa.a = newb;
_aaBalance(paa);
}
return (*paa).a;
}
/********************************************
* Balance an array.
*/
void _aaBalance(AA* paa)
{
//printf("_aaBalance()\n");
if (paa.a)
{
aaA*[16] tmp;
aaA*[] array = tmp;
auto aa = paa.a;
foreach (j, e; aa.b)
{
/* Temporarily store contents of bucket in array[]
*/
size_t k = 0;
void addToArray(aaA* e)
{
while (e)
{ addToArray(e.left);
if (k == array.length)
array.length = array.length * 2;
array[k++] = e;
e = e.right;
}
}
addToArray(e);
/* The contents of the bucket are now sorted into array[].
* Rebuild the tree.
*/
void buildTree(aaA** p, size_t x1, size_t x2)
{
if (x1 >= x2)
*p = null;
else
{ auto mid = (x1 + x2) >> 1;
*p = array[mid];
buildTree(&(*p).left, x1, mid);
buildTree(&(*p).right, mid + 1, x2);
}
}
auto p = &aa.b[j];
buildTree(p, 0, k);
}
}
}
/********************************************
* Produce array of N byte keys from aa.
*/
ArrayRet_t _aaKeys(AA aa, size_t keysize)
{
byte[] res;
size_t resi;
void _aaKeys_x(aaA* e)
{
do
{
memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
resi++;
if (e.left)
{ if (!e.right)
{ e = e.left;
continue;
}
_aaKeys_x(e.left);
}
e = e.right;
} while (e !is null);
}
auto len = _aaLen(aa);
if (!len)
return 0;
res = (cast(byte*) gc_malloc(len * keysize,
!(aa.a.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0))[0 .. len * keysize];
resi = 0;
foreach (e; aa.a.b)
{
if (e)
_aaKeys_x(e);
}
assert(resi == len);
Array a;
a.length = len;
a.ptr = res.ptr;
return *cast(ArrayRet_t*)(&a);
}
/**********************************************
* 'apply' for associative arrays - to support foreach
*/
// dg is D, but _aaApply() is C
extern (D) typedef int delegate(void *) dg_t;
int _aaApply(AA aa, size_t keysize, dg_t dg)
in
{
assert(aligntsize(keysize) == keysize);
}
body
{ int result;
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
int treewalker(aaA* e)
{ int result;
do
{
//printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
result = dg(cast(void *)(e + 1) + keysize);
if (result)
break;
if (e.right)
{ if (!e.left)
{
e = e.right;
continue;
}
result = treewalker(e.right);
if (result)
break;
}
e = e.left;
} while (e);
return result;
}
if (aa.a)
{
foreach (e; aa.a.b)
{
if (e)
{
result = treewalker(e);
if (result)
break;
}
}
}
return result;
}
// dg is D, but _aaApply2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
int _aaApply2(AA aa, size_t keysize, dg2_t dg)
in
{
assert(aligntsize(keysize) == keysize);
}
body
{ int result;
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
int treewalker(aaA* e)
{ int result;
do
{
//printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
if (result)
break;
if (e.right)
{ if (!e.left)
{
e = e.right;
continue;
}
result = treewalker(e.right);
if (result)
break;
}
e = e.left;
} while (e);
return result;
}
if (aa.a)
{
foreach (e; aa.a.b)
{
if (e)
{
result = treewalker(e);
if (result)
break;
}
}
}
return result;
}
/***********************************
* Construct an associative array of type ti from
* length pairs of key/value pairs.
*/
extern (C)
BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
{
auto valuesize = ti.next.tsize(); // value size
auto keyti = ti.key;
auto keysize = keyti.tsize(); // key size
BB* result;
//printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
//printf("tivalue = %.*s\n", ti.next.classinfo.name);
if (length == 0 || valuesize == 0 || keysize == 0)
{
;
}
else
{
va_list q;
va_start!(size_t)(q, length);
result = new BB();
result.keyti = keyti;
size_t i;
for (i = 0; i < prime_list.length - 1; i++)
{
if (length <= prime_list[i])
break;
}
auto len = prime_list[i];
result.b = new aaA*[len];
size_t keystacksize = (keysize + int.sizeof - 1) & ~(int.sizeof - 1);
size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
size_t keytsize = aligntsize(keysize);
for (size_t j = 0; j < length; j++)
{ void* pkey = q;
q += keystacksize;
void* pvalue = q;
q += valuestacksize;
aaA* e;
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
i = key_hash % len;
auto pe = &result.b[i];
while (1)
{
e = *pe;
if (!e)
{
// Not found, create new elem
//printf("create new one\n");
e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
memcpy(e + 1, pkey, keysize);
e.hash = key_hash;
*pe = e;
result.nodes++;
break;
}
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
break;
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
}
va_end(q);
}
return result;
}

View File

@@ -0,0 +1,603 @@
/**
* Implementation of dynamic array property support routines.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.adi;
//debug=adi; // uncomment to turn on debugging printf's
private
{
debug(adi) import core.stdc.stdio;
import core.stdc.string;
import core.stdc.stdlib;
import rt.util.utf;
enum BlkAttr : uint
{
FINALIZE = 0b0000_0001,
NO_SCAN = 0b0000_0010,
NO_MOVE = 0b0000_0100,
ALL_BITS = 0b1111_1111
}
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
extern (C) void gc_free( void* p );
}
struct Array
{
size_t length;
void* ptr;
}
/**********************************************
* Reverse array of chars.
* Handled separately because embedded multibyte encodings should not be
* reversed.
*/
extern (C) long _adReverseChar(char[] a)
{
if (a.length > 1)
{
char[6] tmp;
char[6] tmplo;
char* lo = a.ptr;
char* hi = &a[length - 1];
while (lo < hi)
{ auto clo = *lo;
auto chi = *hi;
debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
if (clo <= 0x7F && chi <= 0x7F)
{
debug(adi) printf("\tascii\n");
*lo = chi;
*hi = clo;
lo++;
hi--;
continue;
}
uint stridelo = UTF8stride[clo];
uint stridehi = 1;
while ((chi & 0xC0) == 0x80)
{
chi = *--hi;
stridehi++;
assert(hi >= lo);
}
if (lo == hi)
break;
debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
if (stridelo == stridehi)
{
memcpy(tmp.ptr, lo, stridelo);
memcpy(lo, hi, stridelo);
memcpy(hi, tmp.ptr, stridelo);
lo += stridelo;
hi--;
continue;
}
/* Shift the whole array. This is woefully inefficient
*/
memcpy(tmp.ptr, hi, stridehi);
memcpy(tmplo.ptr, lo, stridelo);
memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo);
memcpy(lo, tmp.ptr, stridehi);
memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
lo += stridehi;
hi = hi - 1 + (stridehi - stridelo);
}
}
return *cast(long*)(&a);
}
unittest
{
auto a = "abcd"c[];
auto r = a.dup.reverse;
//writefln(r);
assert(r == "dcba");
a = "a\u1235\u1234c";
//writefln(a);
r = a.dup.reverse;
//writefln(r);
assert(r == "c\u1234\u1235a");
a = "ab\u1234c";
//writefln(a);
r = a.dup.reverse;
//writefln(r);
assert(r == "c\u1234ba");
a = "\u3026\u2021\u3061\n";
r = a.dup.reverse;
assert(r == "\n\u3061\u2021\u3026");
}
/**********************************************
* Reverse array of wchars.
* Handled separately because embedded multiword encodings should not be
* reversed.
*/
extern (C) long _adReverseWchar(wchar[] a)
{
if (a.length > 1)
{
wchar[2] tmp;
wchar* lo = a.ptr;
wchar* hi = &a[length - 1];
while (lo < hi)
{ auto clo = *lo;
auto chi = *hi;
if ((clo < 0xD800 || clo > 0xDFFF) &&
(chi < 0xD800 || chi > 0xDFFF))
{
*lo = chi;
*hi = clo;
lo++;
hi--;
continue;
}
int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
int stridehi = 1;
if (chi >= 0xDC00 && chi <= 0xDFFF)
{
chi = *--hi;
stridehi++;
assert(hi >= lo);
}
if (lo == hi)
break;
if (stridelo == stridehi)
{ int stmp;
assert(stridelo == 2);
assert(stmp.sizeof == 2 * (*lo).sizeof);
stmp = *cast(int*)lo;
*cast(int*)lo = *cast(int*)hi;
*cast(int*)hi = stmp;
lo += stridelo;
hi--;
continue;
}
/* Shift the whole array. This is woefully inefficient
*/
memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
lo += stridehi;
hi = hi - 1 + (stridehi - stridelo);
}
}
return *cast(long*)(&a);
}
unittest
{
wstring a = "abcd";
auto r = a.dup.reverse;
assert(r == "dcba");
a = "a\U00012356\U00012346c";
r = a.dup.reverse;
assert(r == "c\U00012346\U00012356a");
a = "ab\U00012345c";
r = a.dup.reverse;
assert(r == "c\U00012345ba");
}
/**********************************************
* Support for array.reverse property.
*/
extern (C) long _adReverse(Array a, size_t szelem)
out (result)
{
assert(result is *cast(long*)(&a));
}
body
{
if (a.length >= 2)
{
byte* tmp;
byte[16] buffer;
void* lo = a.ptr;
void* hi = a.ptr + (a.length - 1) * szelem;
tmp = buffer.ptr;
if (szelem > 16)
{
//version (Windows)
tmp = cast(byte*) alloca(szelem);
//else
//tmp = gc_malloc(szelem);
}
for (; lo < hi; lo += szelem, hi -= szelem)
{
memcpy(tmp, lo, szelem);
memcpy(lo, hi, szelem);
memcpy(hi, tmp, szelem);
}
version (Windows)
{
}
else
{
//if (szelem > 16)
// BUG: bad code is generate for delete pointer, tries
// to call delclass.
//gc_free(tmp);
}
}
return *cast(long*)(&a);
}
unittest
{
debug(adi) printf("array.reverse.unittest\n");
int[] a = new int[5];
int[] b;
size_t i;
for (i = 0; i < 5; i++)
a[i] = i;
b = a.reverse;
assert(b is a);
for (i = 0; i < 5; i++)
assert(a[i] == 4 - i);
struct X20
{ // More than 16 bytes in size
int a;
int b, c, d, e;
}
X20[] c = new X20[5];
X20[] d;
for (i = 0; i < 5; i++)
{ c[i].a = i;
c[i].e = 10;
}
d = c.reverse;
assert(d is c);
for (i = 0; i < 5; i++)
{
assert(c[i].a == 4 - i);
assert(c[i].e == 10);
}
}
/**********************************************
* Sort array of chars.
*/
extern (C) long _adSortChar(char[] a)
{
if (a.length > 1)
{
dstring da = toUTF32(a);
da.sort;
size_t i = 0;
foreach (dchar d; da)
{ char[4] buf;
auto t = toUTF8(buf, d);
a[i .. i + t.length] = t[];
i += t.length;
}
delete da;
}
return *cast(long*)(&a);
}
/**********************************************
* Sort array of wchars.
*/
extern (C) long _adSortWchar(wchar[] a)
{
if (a.length > 1)
{
dstring da = toUTF32(a);
da.sort;
size_t i = 0;
foreach (dchar d; da)
{ wchar[2] buf;
auto t = toUTF16(buf, d);
a[i .. i + t.length] = t[];
i += t.length;
}
delete da;
}
return *cast(long*)(&a);
}
/***************************************
* Support for array equality test.
* Returns:
* 1 equal
* 0 not equal
*/
extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
{
debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
if (a1.length != a2.length)
return 0; // not equal
auto sz = ti.tsize();
auto p1 = a1.ptr;
auto p2 = a2.ptr;
if (sz == 1)
// We should really have a ti.isPOD() check for this
return (memcmp(p1, p2, a1.length) == 0);
for (size_t i = 0; i < a1.length; i++)
{
if (!ti.equals(p1 + i * sz, p2 + i * sz))
return 0; // not equal
}
return 1; // equal
}
extern (C) int _adEq2(Array a1, Array a2, TypeInfo ti)
{
debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
if (a1.length != a2.length)
return 0; // not equal
if (!ti.equals(&a1, &a2))
return 0;
return 1;
}
unittest
{
debug(adi) printf("array.Eq unittest\n");
auto a = "hello"c;
assert(a != "hel");
assert(a != "helloo");
assert(a != "betty");
assert(a == "hello");
assert(a != "hxxxx");
}
/***************************************
* Support for array compare test.
*/
extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
{
debug(adi) printf("adCmp()\n");
auto len = a1.length;
if (a2.length < len)
len = a2.length;
auto sz = ti.tsize();
void *p1 = a1.ptr;
void *p2 = a2.ptr;
if (sz == 1)
{ // We should really have a ti.isPOD() check for this
auto c = memcmp(p1, p2, len);
if (c)
return c;
}
else
{
for (size_t i = 0; i < len; i++)
{
auto c = ti.compare(p1 + i * sz, p2 + i * sz);
if (c)
return c;
}
}
if (a1.length == a2.length)
return 0;
return (a1.length > a2.length) ? 1 : -1;
}
extern (C) int _adCmp2(Array a1, Array a2, TypeInfo ti)
{
debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
return ti.compare(&a1, &a2);
}
unittest
{
debug(adi) printf("array.Cmp unittest\n");
auto a = "hello"c;
assert(a > "hel");
assert(a >= "hel");
assert(a < "helloo");
assert(a <= "helloo");
assert(a > "betty");
assert(a >= "betty");
assert(a == "hello");
assert(a <= "hello");
assert(a >= "hello");
}
/***************************************
* Support for array compare test.
*/
extern (C) int _adCmpChar(Array a1, Array a2)
{
version (X86)
{
asm
{ naked ;
push EDI ;
push ESI ;
mov ESI,a1+4[4+ESP] ;
mov EDI,a2+4[4+ESP] ;
mov ECX,a1[4+ESP] ;
mov EDX,a2[4+ESP] ;
cmp ECX,EDX ;
jb GotLength ;
mov ECX,EDX ;
GotLength:
cmp ECX,4 ;
jb DoBytes ;
// Do alignment if neither is dword aligned
test ESI,3 ;
jz Aligned ;
test EDI,3 ;
jz Aligned ;
DoAlign:
mov AL,[ESI] ; //align ESI to dword bounds
mov DL,[EDI] ;
cmp AL,DL ;
jnz Unequal ;
inc ESI ;
inc EDI ;
test ESI,3 ;
lea ECX,[ECX-1] ;
jnz DoAlign ;
Aligned:
mov EAX,ECX ;
// do multiple of 4 bytes at a time
shr ECX,2 ;
jz TryOdd ;
repe ;
cmpsd ;
jnz UnequalQuad ;
TryOdd:
mov ECX,EAX ;
DoBytes:
// if still equal and not end of string, do up to 3 bytes slightly
// slower.
and ECX,3 ;
jz Equal ;
repe ;
cmpsb ;
jnz Unequal ;
Equal:
mov EAX,a1[4+ESP] ;
mov EDX,a2[4+ESP] ;
sub EAX,EDX ;
pop ESI ;
pop EDI ;
ret ;
UnequalQuad:
mov EDX,[EDI-4] ;
mov EAX,[ESI-4] ;
cmp AL,DL ;
jnz Unequal ;
cmp AH,DH ;
jnz Unequal ;
shr EAX,16 ;
shr EDX,16 ;
cmp AL,DL ;
jnz Unequal ;
cmp AH,DH ;
Unequal:
sbb EAX,EAX ;
pop ESI ;
or EAX,1 ;
pop EDI ;
ret ;
}
}
else
{
int len;
int c;
debug(adi) printf("adCmpChar()\n");
len = a1.length;
if (a2.length < len)
len = a2.length;
c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
if (!c)
c = cast(int)a1.length - cast(int)a2.length;
return c;
}
}
unittest
{
debug(adi) printf("array.CmpChar unittest\n");
auto a = "hello"c;
assert(a > "hel");
assert(a >= "hel");
assert(a < "helloo");
assert(a <= "helloo");
assert(a > "betty");
assert(a >= "betty");
assert(a == "hello");
assert(a <= "hello");
assert(a >= "hello");
}

View File

@@ -0,0 +1,135 @@
/**
* Implementation of alloca() standard C routine.
*
* Copyright: Copyright Digital Mars 1990 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 1990 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.alloca;
/+
#if DOS386
extern size_t _x386_break;
#else
extern size_t _pastdata;
#endif
+/
/*******************************************
* Allocate data from the caller's stack frame.
* This is a 'magic' function that needs help from the compiler to
* work right, do not change its name, do not call it from other compilers.
* Input:
* nbytes number of bytes to allocate
* ECX address of variable with # of bytes in locals
* This is adjusted upon return to reflect the additional
* size of the stack frame.
* Returns:
* EAX allocated data, null if stack overflows
*/
extern (C) void* __alloca(int nbytes)
{
asm
{
naked ;
mov EDX,ECX ;
mov EAX,4[ESP] ; // get nbytes
push EBX ;
push EDI ;
push ESI ;
}
version (OSX)
{
asm
{
add EAX,15 ;
and EAX,0xFFFFFFF0 ; // round up to 16 byte boundary
}
}
else
{
asm
{
add EAX,3 ;
and EAX,0xFFFFFFFC ; // round up to dword
}
}
asm
{
jnz Abegin ;
mov EAX,4 ; // allow zero bytes allocation, 0 rounded to dword is 4..
Abegin:
mov ESI,EAX ; // ESI = nbytes
neg EAX ;
add EAX,ESP ; // EAX is now what the new ESP will be.
jae Aoverflow ;
}
version (Windows)
{
asm
{
// We need to be careful about the guard page
// Thus, for every 4k page, touch it to cause the OS to load it in.
mov ECX,EAX ; // ECX is new location for stack
mov EBX,ESI ; // EBX is size to "grow" stack
L1:
test [ECX+EBX],EBX ; // bring in page
sub EBX,0x1000 ; // next 4K page down
jae L1 ; // if more pages
test [ECX],EBX ; // bring in last page
}
}
version (DOS386)
{
asm
{
// is ESP off bottom?
cmp EAX,_x386_break ;
jbe Aoverflow ;
}
}
version (Unix)
{
asm
{
cmp EAX,_pastdata ;
jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX
}
}
asm
{
// Copy down to [ESP] the temps on the stack.
// The number of temps is (EBP - ESP - locals).
mov ECX,EBP ;
sub ECX,ESP ;
sub ECX,[EDX] ; // ECX = number of temps (bytes) to move.
add [EDX],ESI ; // adjust locals by nbytes for next call to alloca()
mov ESP,EAX ; // Set up new stack pointer.
add EAX,ECX ; // Return value = ESP + temps.
mov EDI,ESP ; // Destination of copy of temps.
add ESI,ESP ; // Source of copy.
shr ECX,2 ; // ECX to count of dwords in temps
// Always at least 4 (nbytes, EIP, ESI,and EDI).
rep ;
movsd ;
jmp done ;
Aoverflow:
// Overflowed the stack. Return null
xor EAX,EAX ;
done:
pop ESI ;
pop EDI ;
pop EBX ;
ret ;
}
}

View File

@@ -0,0 +1,186 @@
/**
* Implementation of array assignment support routines.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.arrayassign;
private
{
import rt.util.string;
import core.stdc.string;
import core.stdc.stdlib;
debug(PRINTF) import core.stdc.stdio;
}
/**
* Does array assignment (not construction) from another
* array of the same element type.
* ti is the element type.
* Handles overlapping copies.
*/
extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to)
{
debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize());
if (to.length != from.length)
{
char[10] tmp = void;
string msg = "lengths don't match for array copy,"c;
msg ~= tmp.intToString(to.length) ~ " = " ~ tmp.intToString(from.length);
throw new Exception(msg);
}
auto element_size = ti.tsize();
/* Need a temporary buffer tmp[] big enough to hold one element
*/
void[16] buf = void;
void[] tmp;
if (element_size > buf.sizeof)
tmp = alloca(element_size)[0 .. element_size];
else
tmp = buf;
if (to.ptr <= from.ptr)
{
foreach (i; 0 .. to.length)
{
void* pto = to.ptr + i * element_size;
void* pfrom = from.ptr + i * element_size;
memcpy(tmp.ptr, pto, element_size);
memcpy(pto, pfrom, element_size);
ti.postblit(pto);
ti.destroy(tmp.ptr);
}
}
else
{
for (int i = to.length; i--; )
{
void* pto = to.ptr + i * element_size;
void* pfrom = from.ptr + i * element_size;
memcpy(tmp.ptr, pto, element_size);
memcpy(pto, pfrom, element_size);
ti.postblit(pto);
ti.destroy(tmp.ptr);
}
}
return to;
}
/**
* Does array initialization (not assignment) from another
* array of the same element type.
* ti is the element type.
*/
extern (C) void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to)
{
debug(PRINTF) printf("_d_arrayctor(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize());
if (to.length != from.length)
{
char[10] tmp = void;
string msg = "lengths don't match for array initialization,"c;
msg ~= tmp.intToString(to.length) ~ " = " ~ tmp.intToString(from.length);
throw new Exception(msg);
}
auto element_size = ti.tsize();
int i;
try
{
for (i = 0; i < to.length; i++)
{
// Copy construction is defined as bit copy followed by postblit.
memcpy(to.ptr + i * element_size, from.ptr + i * element_size, element_size);
ti.postblit(to.ptr + i * element_size);
}
}
catch (Object o)
{
/* Destroy, in reverse order, what we've constructed so far
*/
while (i--)
{
ti.destroy(to.ptr + i * element_size);
}
throw o;
}
return to;
}
/**
* Do assignment to an array.
* p[0 .. count] = value;
*/
extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti)
{
void* pstart = p;
auto element_size = ti.tsize();
//Need a temporary buffer tmp[] big enough to hold one element
void[16] buf = void;
void[] tmp;
if (element_size > buf.sizeof)
{
tmp = alloca(element_size)[0 .. element_size];
}
else
tmp = buf;
foreach (i; 0 .. count)
{
memcpy(tmp.ptr, p, element_size);
memcpy(p, value, element_size);
ti.postblit(p);
ti.destroy(tmp.ptr);
p += element_size;
}
return pstart;
}
/**
* Do construction of an array.
* ti[count] p = value;
*/
extern (C) void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti)
{
void* pstart = p;
auto element_size = ti.tsize();
try
{
foreach (i; 0 .. count)
{
// Copy construction is defined as bit copy followed by postblit.
memcpy(p, value, element_size);
ti.postblit(p);
p += element_size;
}
}
catch (Object o)
{
// Destroy, in reverse order, what we've constructed so far
while (p > pstart)
{
p -= element_size;
ti.destroy(p);
}
throw o;
}
return pstart;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
/**
* Implementation of array cast support routines.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.arraycast;
/******************************************
* Runtime helper to convert dynamic array of one
* type to dynamic array of another.
* Adjusts the length of the array.
* Throws exception if new length is not aligned.
*/
extern (C)
void[] _d_arraycast(size_t tsize, size_t fsize, void[] a)
{
auto length = a.length;
auto nbytes = length * fsize;
if (nbytes % tsize != 0)
{
throw new Exception("array cast misalignment");
}
length = nbytes / tsize;
*cast(size_t *)&a = length; // jam new length
return a;
}
unittest
{
byte[int.sizeof * 3] b;
int[] i;
short[] s;
i = cast(int[])b;
assert(i.length == 3);
s = cast(short[])b;
assert(s.length == 6);
s = cast(short[])i;
assert(s.length == 6);
}
/******************************************
* Runtime helper to convert dynamic array of bits
* dynamic array of another.
* Adjusts the length of the array.
* Throws exception if new length is not aligned.
*/
version (none)
{
extern (C)
void[] _d_arraycast_frombit(uint tsize, void[] a)
{
uint length = a.length;
if (length & 7)
{
throw new Exception("bit[] array cast misalignment");
}
length /= 8 * tsize;
*cast(size_t *)&a = length; // jam new length
return a;
}
unittest
{
version (D_Bits)
{
bit[int.sizeof * 3 * 8] b;
int[] i;
short[] s;
i = cast(int[])b;
assert(i.length == 3);
s = cast(short[])b;
assert(s.length == 6);
}
}
}

View File

@@ -0,0 +1,42 @@
/**
* Implementation of array copy support routines.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.arraycat;
private
{
import core.stdc.string;
debug import core.stdc.stdio;
}
extern (C):
byte[] _d_arraycopy(size_t size, byte[] from, byte[] to)
{
debug printf("f = %p,%d, t = %p,%d, size = %d\n",
from.ptr, from.length, to.ptr, to.length, size);
if (to.length != from.length)
{
throw new Exception("lengths don't match for array copy");
}
else if (to.ptr + to.length * size <= from.ptr ||
from.ptr + from.length * size <= to.ptr)
{
memcpy(to.ptr, from.ptr, to.length * size);
}
else
{
throw new Exception("overlapping array copy");
}
return to;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,241 @@
/**
* Contains SSE2 and MMX versions of certain operations for real.
*
* Copyright: Copyright Digital Mars 2008 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, based on code originally written by Burton Radons
*
* Copyright Digital Mars 2008 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.arrayreal;
import rt.util.cpuid;
version (unittest)
{
private import core.stdc.stdio : printf;
/* This is so unit tests will test every CPU variant
*/
int cpuid;
const int CPUID_MAX = 1;
bool mmx() { return cpuid == 1 && rt.util.cpuid.mmx(); }
bool sse() { return cpuid == 2 && rt.util.cpuid.sse(); }
bool sse2() { return cpuid == 3 && rt.util.cpuid.sse2(); }
bool amd3dnow() { return cpuid == 4 && rt.util.cpuid.amd3dnow(); }
}
else
{
alias rt.util.cpuid.mmx mmx;
alias rt.util.cpuid.sse sse;
alias rt.util.cpuid.sse2 sse2;
alias rt.util.cpuid.amd3dnow amd3dnow;
}
//version = log;
bool disjoint(T)(T[] a, T[] b)
{
return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
}
alias real T;
extern (C):
/* ======================================================================== */
/***********************
* Computes:
* a[] = b[] + c[]
*/
T[] _arraySliceSliceAddSliceAssign_r(T[] a, T[] c, T[] b)
in
{
assert(a.length == b.length && b.length == c.length);
assert(disjoint(a, b));
assert(disjoint(a, c));
assert(disjoint(b, c));
}
body
{
for (int i = 0; i < a.length; i++)
a[i] = b[i] + c[i];
return a;
}
unittest
{
printf("_arraySliceSliceAddSliceAssign_r unittest\n");
for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
{
version (log) printf(" cpuid %d\n", cpuid);
for (int j = 0; j < 2; j++)
{
const int dim = 67;
T[] a = new T[dim + j]; // aligned on 16 byte boundary
a = a[j .. dim + j]; // misalign for second iteration
T[] b = new T[dim + j];
b = b[j .. dim + j];
T[] c = new T[dim + j];
c = c[j .. dim + j];
for (int i = 0; i < dim; i++)
{ a[i] = cast(T)i;
b[i] = cast(T)(i + 7);
c[i] = cast(T)(i * 2);
}
c[] = a[] + b[];
for (int i = 0; i < dim; i++)
{
if (c[i] != cast(T)(a[i] + b[i]))
{
printf("[%d]: %Lg != %Lg + %Lg\n", i, c[i], a[i], b[i]);
assert(0);
}
}
}
}
}
/* ======================================================================== */
/***********************
* Computes:
* a[] = b[] - c[]
*/
T[] _arraySliceSliceMinSliceAssign_r(T[] a, T[] c, T[] b)
in
{
assert(a.length == b.length && b.length == c.length);
assert(disjoint(a, b));
assert(disjoint(a, c));
assert(disjoint(b, c));
}
body
{
for (int i = 0; i < a.length; i++)
a[i] = b[i] - c[i];
return a;
}
unittest
{
printf("_arraySliceSliceMinSliceAssign_r unittest\n");
for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
{
version (log) printf(" cpuid %d\n", cpuid);
for (int j = 0; j < 2; j++)
{
const int dim = 67;
T[] a = new T[dim + j]; // aligned on 16 byte boundary
a = a[j .. dim + j]; // misalign for second iteration
T[] b = new T[dim + j];
b = b[j .. dim + j];
T[] c = new T[dim + j];
c = c[j .. dim + j];
for (int i = 0; i < dim; i++)
{ a[i] = cast(T)i;
b[i] = cast(T)(i + 7);
c[i] = cast(T)(i * 2);
}
c[] = a[] - b[];
for (int i = 0; i < dim; i++)
{
if (c[i] != cast(T)(a[i] - b[i]))
{
printf("[%d]: %Lg != %Lg - %Lg\n", i, c[i], a[i], b[i]);
assert(0);
}
}
}
}
}
/* ======================================================================== */
/***********************
* Computes:
* a[] -= b[] * value
*/
T[] _arraySliceExpMulSliceMinass_r(T[] a, T value, T[] b)
{
return _arraySliceExpMulSliceAddass_r(a, -value, b);
}
/***********************
* Computes:
* a[] += b[] * value
*/
T[] _arraySliceExpMulSliceAddass_r(T[] a, T value, T[] b)
in
{
assert(a.length == b.length);
assert(disjoint(a, b));
}
body
{
auto aptr = a.ptr;
auto aend = aptr + a.length;
auto bptr = b.ptr;
// Handle remainder
while (aptr < aend)
*aptr++ += *bptr++ * value;
return a;
}
unittest
{
printf("_arraySliceExpMulSliceAddass_r unittest\n");
cpuid = 1;
{
version (log) printf(" cpuid %d\n", cpuid);
for (int j = 0; j < 1; j++)
{
const int dim = 67;
T[] a = new T[dim + j]; // aligned on 16 byte boundary
a = a[j .. dim + j]; // misalign for second iteration
T[] b = new T[dim + j];
b = b[j .. dim + j];
T[] c = new T[dim + j];
c = c[j .. dim + j];
for (int i = 0; i < dim; i++)
{ a[i] = cast(T)i;
b[i] = cast(T)(i + 7);
c[i] = cast(T)(i * 2);
}
b[] = c[];
c[] += a[] * 6;
for (int i = 0; i < dim; i++)
{
//printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]);
if (c[i] != cast(T)(b[i] + a[i] * 6))
{
printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]);
assert(0);
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
/**
* Implementation of array assignment support routines.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.cast_;
extern (C):
/******************************************
* Given a pointer:
* If it is an Object, return that Object.
* If it is an interface, return the Object implementing the interface.
* If it is null, return null.
* Else, undefined crash
*/
Object _d_toObject(void* p)
{ Object o;
if (p)
{
o = cast(Object)p;
ClassInfo oc = o.classinfo;
Interface *pi = **cast(Interface ***)p;
/* Interface.offset lines up with ClassInfo.name.ptr,
* so we rely on pointers never being less than 64K,
* and Objects never being greater.
*/
if (pi.offset < 0x10000)
{
//printf("\tpi.offset = %d\n", pi.offset);
o = cast(Object)(p - pi.offset);
}
}
return o;
}
/*************************************
* Attempts to cast Object o to class c.
* Returns o if successful, null if not.
*/
Object _d_interface_cast(void* p, ClassInfo c)
{ Object o;
//printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
if (p)
{
Interface *pi = **cast(Interface ***)p;
//printf("\tpi.offset = %d\n", pi.offset);
o = cast(Object)(p - pi.offset);
return _d_dynamic_cast(o, c);
}
return o;
}
Object _d_dynamic_cast(Object o, ClassInfo c)
{ ClassInfo oc;
size_t offset = 0;
//printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
if (o)
{
oc = o.classinfo;
if (_d_isbaseof2(oc, c, offset))
{
//printf("\toffset = %d\n", offset);
o = cast(Object)(cast(void*)o + offset);
}
else
o = null;
}
//printf("\tresult = %p\n", o);
return o;
}
int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout size_t offset)
{ int i;
if (oc is c)
return 1;
do
{
if (oc.base is c)
return 1;
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo ic;
ic = oc.interfaces[i].classinfo;
if (ic is c)
{ offset = oc.interfaces[i].offset;
return 1;
}
}
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo ic;
ic = oc.interfaces[i].classinfo;
if (_d_isbaseof2(ic, c, offset))
{ offset = oc.interfaces[i].offset;
return 1;
}
}
oc = oc.base;
} while (oc);
return 0;
}
int _d_isbaseof(ClassInfo oc, ClassInfo c)
{ int i;
if (oc is c)
return 1;
do
{
if (oc.base is c)
return 1;
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo ic;
ic = oc.interfaces[i].classinfo;
if (ic is c || _d_isbaseof(ic, c))
return 1;
}
oc = oc.base;
} while (oc);
return 0;
}
/*********************************
* Find the vtbl[] associated with Interface ic.
*/
void *_d_interface_vtbl(ClassInfo ic, Object o)
{ int i;
ClassInfo oc;
//printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
assert(o);
oc = o.classinfo;
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo oic;
oic = oc.interfaces[i].classinfo;
if (oic is ic)
{
return cast(void *)oc.interfaces[i].vtbl;
}
}
assert(0);
}

View File

@@ -0,0 +1,218 @@
/**
* Runtime support for complex arithmetic code generation (for Posix).
*
* Copyright: Copyright Digital Mars 2001 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2001 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.cmath2;
private import core.stdc.math;
extern (C):
/****************************
* Multiply two complex floating point numbers, x and y.
* Input:
* x.re ST3
* x.im ST2
* y.re ST1
* y.im ST0
* Output:
* ST1 real part
* ST0 imaginary part
*/
void _Cmul()
{
// p.re = x.re * y.re - x.im * y.im;
// p.im = x.im * y.re + x.re * y.im;
asm
{ naked ;
fld ST(1) ; // x.re
fmul ST,ST(4) ; // ST0 = x.re * y.re
fld ST(1) ; // y.im
fmul ST,ST(4) ; // ST0 = x.im * y.im
fsubp ST(1),ST ; // ST0 = x.re * y.re - x.im * y.im
fld ST(3) ; // x.im
fmul ST,ST(3) ; // ST0 = x.im * y.re
fld ST(5) ; // x.re
fmul ST,ST(3) ; // ST0 = x.re * y.im
faddp ST(1),ST ; // ST0 = x.im * y.re + x.re * y.im
fxch ST(4),ST ;
fstp ST(0) ;
fxch ST(4),ST ;
fstp ST(0) ;
fstp ST(0) ;
fstp ST(0) ;
ret ;
}
/+
if (isnan(x) && isnan(y))
{
// Recover infinities that computed as NaN+ iNaN ...
int recalc = 0;
if ( isinf( a) || isinf( b) )
{ // z is infinite
// "Box" the infinity and change NaNs in the other factor to 0
a = copysignl( isinf( a) ? 1.0 : 0.0, a);
b = copysignl( isinf( b) ? 1.0 : 0.0, b);
if (isnan( c)) c = copysignl( 0.0, c);
if (isnan( d)) d = copysignl( 0.0, d);
recalc = 1;
}
if (isinf(c) || isinf(d))
{ // w is infinite
// "Box" the infinity and change NaNs in the other factor to 0
c = copysignl( isinf( c) ? 1.0 : 0.0, c);
d = copysignl( isinf( d) ? 1.0 : 0.0, d);
if (isnan( a)) a = copysignl( 0.0, a);
if (isnan( b)) b = copysignl( 0.0, b);
recalc = 1;
}
if (!recalc && (isinf(ac) || isinf(bd) ||
isinf(ad) || isinf(bc)))
{
// Recover infinities from overflow by changing NaNs to 0 ...
if (isnan( a)) a = copysignl( 0.0, a);
if (isnan( b)) b = copysignl( 0.0, b);
if (isnan( c)) c = copysignl( 0.0, c);
if (isnan( d)) d = copysignl( 0.0, d);
recalc = 1;
}
if (recalc)
{
x = INFINITY * (a * c - b * d);
y = INFINITY * (a * d + b * c);
}
}
+/
}
/****************************
* Divide two complex floating point numbers, x / y.
* Input:
* x.re ST3
* x.im ST2
* y.re ST1
* y.im ST0
* Output:
* ST1 real part
* ST0 imaginary part
*/
void _Cdiv()
{
real x_re, x_im;
real y_re, y_im;
real q_re, q_im;
real r;
real den;
asm
{
fstp y_im ;
fstp y_re ;
fstp x_im ;
fstp x_re ;
}
if (fabs(y_re) < fabs(y_im))
{
r = y_re / y_im;
den = y_im + r * y_re;
q_re = (x_re * r + x_im) / den;
q_im = (x_im * r - x_re) / den;
}
else
{
r = y_im / y_re;
den = y_re + r * y_im;
q_re = (x_re + r * x_im) / den;
q_im = (x_im - r * x_re) / den;
}
//printf("q.re = %g, q.im = %g\n", (double)q_re, (double)q_im);
/+
if (isnan(q_re) && isnan(q_im))
{
real denom = y_re * y_re + y_im * y_im;
// non-zero / zero
if (denom == 0.0 && (!isnan(x_re) || !isnan(x_im)))
{
q_re = copysignl(INFINITY, y_re) * x_re;
q_im = copysignl(INFINITY, y_re) * x_im;
}
// infinite / finite
else if ((isinf(x_re) || isinf(x_im)) && isfinite(y_re) && isfinite(y_im))
{
x_re = copysignl(isinf(x_re) ? 1.0 : 0.0, x_re);
x_im = copysignl(isinf(x_im) ? 1.0 : 0.0, x_im);
q_re = INFINITY * (x_re * y_re + x_im * y_im);
q_im = INFINITY * (x_im * y_re - x_re * y_im);
}
// finite / infinite
else if (isinf(logbw) && isfinite(x_re) && isfinite(x_im))
{
y_re = copysignl(isinf(y_re) ? 1.0 : 0.0, y_re);
y_im = copysignl(isinf(y_im) ? 1.0 : 0.0, y_im);
q_re = 0.0 * (x_re * y_re + x_im * y_im);
q_im = 0.0 * (x_im * y_re - x_re * y_im);
}
}
return q_re + q_im * 1.0i;
+/
asm
{
fld q_re;
fld q_im;
}
}
/****************************
* Compare two complex floating point numbers, x and y.
* Input:
* x.re ST3
* x.im ST2
* y.re ST1
* y.im ST0
* Output:
* 8087 stack is cleared
* flags set
*/
void _Ccmp()
{
asm
{ naked ;
fucomp ST(2) ; // compare x.im and y.im
fstsw AX ;
sahf ;
jne L1 ;
jp L1 ; // jmp if NAN
fucomp ST(2) ; // compare x.re and y.re
fstsw AX ;
sahf ;
fstp ST(0) ; // pop
fstp ST(0) ; // pop
ret ;
L1:
fstp ST(0) ; // pop
fstp ST(0) ; // pop
fstp ST(0) ; // pop
ret ;
}
}

View File

@@ -0,0 +1,42 @@
/**
* Compiler information and associated routines.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.compiler;
// Identify the compiler used and its various features.
const
{
// Vendor specific string naming the compiler
char[] name = "Digital Mars D";
// Master list of D compiler vendors
enum Vendor
{
DigitalMars = 1
}
// Which vendor we are
Vendor vendor = Vendor.DigitalMars;
// The vendor specific version number, as in
// version_major.version_minor
uint version_major = 0;
uint version_minor = 0;
// The version of the D Programming Language Specification
// Supported by the compiler
uint D_major = 0;
uint D_minor = 0;
}

View File

@@ -0,0 +1,112 @@
/**
* Implementation of complex number support routines.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <math.h>
typedef struct Complex
{
long double re;
long double im;
} Complex;
Complex _complex_div(Complex x, Complex y)
{
Complex q;
long double r;
long double den;
if (fabs(y.re) < fabs(y.im))
{
r = y.re / y.im;
den = y.im + r * y.re;
q.re = (x.re * r + x.im) / den;
q.im = (x.im * r - x.re) / den;
}
else
{
r = y.im / y.re;
den = y.re + r * y.im;
q.re = (x.re + r * x.im) / den;
q.im = (x.im - r * x.re) / den;
}
return q;
}
Complex _complex_mul(Complex x, Complex y)
{
Complex p;
p.re = x.re * y.re - x.im * y.im;
p.im = x.im * y.re + x.re * y.im;
return p;
}
long double _complex_abs(Complex z)
{
long double x,y,ans,temp;
x = fabs(z.re);
y = fabs(z.im);
if (x == 0)
ans = y;
else if (y == 0)
ans = x;
else if (x > y)
{
temp = y / x;
ans = x * sqrt(1 + temp * temp);
}
else
{
temp = x / y;
ans = y * sqrt(1 + temp * temp);
}
return ans;
}
Complex _complex_sqrt(Complex z)
{
Complex c;
long double x,y,w,r;
if (z.re == 0 && z.im == 0)
{
c.re = 0;
c.im = 0;
}
else
{
x = fabs(z.re);
y = fabs(z.im);
if (x >= y)
{
r = y / x;
w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
}
else
{
r = x / y;
w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
}
if (z.re >= 0)
{
c.re = w;
c.im = z.im / (w + w);
}
else
{
c.im = (z.im >= 0) ? w : -w;
c.re = z.im / (c.im + c.im);
}
}
return c;
}

View File

@@ -0,0 +1,463 @@
/**
* Implementation of code coverage analyzer.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.cover;
private
{
version( Windows )
import core.sys.windows.windows;
else version( Posix )
{
import core.sys.posix.fcntl;
import core.sys.posix.unistd;
}
import core.bitop;
import core.stdc.stdio;
import rt.util.utf;
struct BitArray
{
size_t len;
uint* ptr;
bool opIndex( size_t i )
in
{
assert( i < len );
}
body
{
return cast(bool) bt( ptr, i );
}
}
struct Cover
{
string filename;
BitArray valid;
uint[] data;
}
__gshared
{
Cover[] gdata;
string srcpath;
string dstpath;
bool merge;
}
}
/**
* Set path to where source files are located.
*
* Params:
* pathname = The new path name.
*/
extern (C) void dmd_coverSourcePath( string pathname )
{
srcpath = pathname;
}
/**
* Set path to where listing files are to be written.
*
* Params:
* pathname = The new path name.
*/
extern (C) void dmd_coverDestPath( string pathname )
{
dstpath = pathname;
}
/**
* Set merge mode.
*
* Params:
* flag = true means new data is summed with existing data in the listing
* file; false means a new listing file is always created.
*/
extern (C) void dmd_coverSetMerge( bool flag )
{
merge = flag;
}
/**
* The coverage callback.
*
* Params:
* filename = The name of the coverage file.
* valid = ???
* data = ???
*/
extern (C) void _d_cover_register( string filename, BitArray valid, uint[] data )
{
Cover c;
c.filename = filename;
c.valid = valid;
c.data = data;
gdata ~= c;
}
static ~this()
{
const NUMLINES = 16384 - 1;
const NUMCHARS = 16384 * 16 - 1;
char[] srcbuf = new char[NUMCHARS];
char[][] srclines = new char[][NUMLINES];
char[] lstbuf = new char[NUMCHARS];
char[][] lstlines = new char[][NUMLINES];
foreach( Cover c; gdata )
{
if( !readFile( appendFN( srcpath, c.filename ), srcbuf ) )
continue;
splitLines( srcbuf, srclines );
if( merge )
{
if( !readFile( addExt( baseName( c.filename ), "lst" ), lstbuf ) )
break;
splitLines( lstbuf, lstlines );
for( size_t i = 0; i < lstlines.length; ++i )
{
if( i >= c.data.length )
break;
int count = 0;
foreach( char c2; lstlines[i] )
{
switch( c2 )
{
case ' ':
continue;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
count = count * 10 + c2 - '0';
continue;
default:
break;
}
}
c.data[i] += count;
}
}
FILE* flst = fopen( (addExt( baseName( c.filename ), "lst\0" )).ptr, "wb" );
if( !flst )
continue; //throw new Exception( "Error opening file for write: " ~ lstfn );
uint nno;
uint nyes;
for( int i = 0; i < c.data.length; i++ )
{
if( i < srclines.length )
{
uint n = c.data[i];
char[] line = srclines[i];
line = expandTabs( line );
if( n == 0 )
{
if( c.valid[i] )
{
nno++;
fprintf( flst, "0000000|%.*s\n", line );
}
else
{
fprintf( flst, " |%.*s\n", line );
}
}
else
{
nyes++;
fprintf( flst, "%7u|%.*s\n", n, line );
}
}
}
if( nyes + nno ) // no divide by 0 bugs
{
fprintf( flst, "%.*s is %d%% covered\n", c.filename, ( nyes * 100 ) / ( nyes + nno ) );
}
fclose( flst );
}
}
string appendFN( string path, string name )
{
version( Windows )
const char sep = '\\';
else
const char sep = '/';
auto dest = path;
if( dest && dest[$ - 1] != sep )
dest ~= sep;
dest ~= name;
return dest;
}
string baseName( string name, string ext = null )
{
auto i = name.length;
for( ; i > 0; --i )
{
version( Windows )
{
if( name[i - 1] == ':' || name[i - 1] == '\\' )
break;
}
else version( Posix )
{
if( name[i - 1] == '/' )
break;
}
}
return chomp( name[i .. $], ext ? ext : "" );
}
string getExt( string name )
{
auto i = name.length;
while( i > 0 )
{
if( name[i - 1] == '.' )
return name[i .. $];
--i;
version( Windows )
{
if( name[i] == ':' || name[i] == '\\' )
break;
}
else version( Posix )
{
if( name[i] == '/' )
break;
}
}
return null;
}
string addExt( string name, string ext )
{
auto existing = getExt( name );
if( existing.length == 0 )
{
if( name.length && name[$ - 1] == '.' )
name ~= ext;
else
name = name ~ "." ~ ext;
}
else
{
name = name[0 .. $ - existing.length] ~ ext;
}
return name;
}
string chomp( string str, string delim = null )
{
if( delim is null )
{
auto len = str.length;
if( len )
{
auto c = str[len - 1];
if( c == '\r' )
--len;
else if( c == '\n' && str[--len - 1] == '\r' )
--len;
}
return str[0 .. len];
}
else if( str.length >= delim.length )
{
if( str[$ - delim.length .. $] == delim )
return str[0 .. $ - delim.length];
}
return str;
}
bool readFile( string name, inout char[] buf )
{
version( Windows )
{
auto wnamez = toUTF16z( name );
HANDLE file = CreateFileW( wnamez,
GENERIC_READ,
FILE_SHARE_READ,
null,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
cast(HANDLE) null );
delete wnamez;
if( file == INVALID_HANDLE_VALUE )
return false;
scope( exit ) CloseHandle( file );
DWORD num = 0;
DWORD pos = 0;
buf.length = 4096;
while( true )
{
if( !ReadFile( file, &buf[pos], cast(DWORD)( buf.length - pos ), &num, null ) )
return false;
if( !num )
break;
pos += num;
buf.length = pos * 2;
}
buf.length = pos;
return true;
}
else version( Posix )
{
char[] namez = new char[name.length + 1];
namez[0 .. name.length] = name;
namez[$ - 1] = 0;
int file = open( namez.ptr, O_RDONLY );
delete namez;
if( file == -1 )
return false;
scope( exit ) close( file );
int num = 0;
uint pos = 0;
buf.length = 4096;
while( true )
{
num = read( file, &buf[pos], cast(uint)( buf.length - pos ) );
if( num == -1 )
return false;
if( !num )
break;
pos += num;
buf.length = pos * 2;
}
buf.length = pos;
return true;
}
}
void splitLines( char[] buf, inout char[][] lines )
{
size_t beg = 0,
pos = 0;
lines.length = 0;
for( ; pos < buf.length; ++pos )
{
char c = buf[pos];
switch( buf[pos] )
{
case '\r':
case '\n':
lines ~= buf[beg .. pos];
beg = pos + 1;
if( buf[pos] == '\r' && pos < buf.length - 1 && buf[pos + 1] == '\n' )
++pos, ++beg;
default:
continue;
}
}
if( beg != pos )
{
lines ~= buf[beg .. pos];
}
}
char[] expandTabs( char[] str, int tabsize = 8 )
{
const dchar LS = '\u2028'; // UTF line separator
const dchar PS = '\u2029'; // UTF paragraph separator
bool changes = false;
char[] result = str;
int column;
int nspaces;
foreach( size_t i, dchar c; str )
{
switch( c )
{
case '\t':
nspaces = tabsize - (column % tabsize);
if( !changes )
{
changes = true;
result = null;
result.length = str.length + nspaces - 1;
result.length = i + nspaces;
result[0 .. i] = str[0 .. i];
result[i .. i + nspaces] = ' ';
}
else
{ int j = result.length;
result.length = j + nspaces;
result[j .. j + nspaces] = ' ';
}
column += nspaces;
break;
case '\r':
case '\n':
case PS:
case LS:
column = 0;
goto L1;
default:
column++;
L1:
if (changes)
{
if (c <= 0x7F)
result ~= c;
else
encode(result, c);
}
break;
}
}
return result;
}

View File

@@ -0,0 +1,173 @@
/**
* Implementation of support routines for synchronized blocks.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
/* ================================= 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__
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// PTHREAD_MUTEX_RECURSIVE is the "standard" symbol,
// while the _NP version is specific to Linux
#ifndef PTHREAD_MUTEX_RECURSIVE
# define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#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);
// 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

View File

@@ -0,0 +1,724 @@
/**
* Implementation of exception handling support routines for Windows.
*
* Copyright: Copyright Digital Mars 1999 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 1999 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
/* ======================== Win32 =============================== */
#if _WIN32
#include <excpt.h>
#include <windows.h>
//#include "\sc\src\include\ehsup.h"
/*** From Digital Mars C runtime library ***/
EXCEPTION_DISPOSITION __cdecl _local_except_handler (EXCEPTION_RECORD *ExceptionRecord,
void* EstablisherFrame,
void *ContextRecord,
void *DispatcherContext
);
void __cdecl _global_unwind(void *frame,EXCEPTION_RECORD *eRecord);
#define EXCEPTION_UNWIND 6 // Flag to indicate if the system is unwinding
extern DWORD _except_list;
/*** ***/
#include "mars.h"
extern ClassInfo D6object9Throwable7__ClassZ;
#define _Class_9Throwable D6object9Throwable7__ClassZ;
extern ClassInfo D6object5Error7__ClassZ;
#define _Class_5Error D6object5Error7__ClassZ
typedef int (__pascal *fp_t)(); // function pointer in ambient memory model
// The layout of DEstablisherFrame is the same for C++
struct DEstablisherFrame
{
void *prev; // pointer to previous exception list
void *handler; // pointer to routine for exception handler
DWORD table_index; // current index into handler_info[]
DWORD ebp; // this is EBP of routine
};
struct DHandlerInfo
{
int prev_index; // previous table index
unsigned cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
void *finally_code; // pointer to finally code to execute
// (!=0 if try-finally)
};
// Address of DHandlerTable is passed in EAX to _d_framehandler()
struct DHandlerTable
{
void *fptr; // pointer to start of function
unsigned espoffset; // offset of ESP from EBP
unsigned retoffset; // offset from start of function to return code
struct DHandlerInfo handler_info[1];
};
struct DCatchBlock
{
ClassInfo *type; // catch type
unsigned bpoffset; // EBP offset of catch var
void *code; // catch handler code
};
// Create one of these for each try-catch
struct DCatchInfo
{
unsigned ncatches; // number of catch blocks
struct DCatchBlock catch_block[1]; // data for each catch block
};
// Macro to make our own exception code
#define MAKE_EXCEPTION_CODE(severity, facility, exception) \
(((severity) << 30) | (1 << 29) | (0 << 28) | ((facility) << 16) | (exception))
#define STATUS_DIGITAL_MARS_D_EXCEPTION MAKE_EXCEPTION_CODE(3,'D',1)
Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record);
void __cdecl _d_local_unwind(struct DHandlerTable *handler_table, struct DEstablisherFrame *frame, int stop_index);
/***********************************
* The frame handler, this is called for each frame that has been registered
* in the OS except_list.
* Input:
* EAX the handler table for the frame
*/
EXCEPTION_DISPOSITION _d_framehandler(
EXCEPTION_RECORD *exception_record,
struct DEstablisherFrame *frame,
CONTEXT context,
void *dispatcher_context)
{
struct DHandlerTable *handler_table;
__asm { mov handler_table,EAX }
if (exception_record->ExceptionFlags & EXCEPTION_UNWIND)
{
// Call all the finally blocks in this frame
_d_local_unwind(handler_table, frame, -1);
}
else
{
// Jump to catch block if matching one is found
int ndx,prev_ndx,i;
struct DHandlerInfo *phi;
struct DCatchInfo *pci;
struct DCatchBlock *pcb;
unsigned ncatches; // number of catches in the current handler
Object *pti;
ClassInfo *ci;
ci = NULL; // only compute it if we need it
// walk through handler table, checking each handler
// with an index smaller than the current table_index
for (ndx = frame->table_index; ndx != -1; ndx = prev_ndx)
{
phi = &handler_table->handler_info[ndx];
prev_ndx = phi->prev_index;
if (phi->cioffset)
{
// this is a catch handler (no finally)
pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
ncatches = pci->ncatches;
for (i = 0; i < ncatches; i++)
{
pcb = &pci->catch_block[i];
if (!ci)
{
// This code must match the translation code
if (exception_record->ExceptionCode == STATUS_DIGITAL_MARS_D_EXCEPTION)
{
//printf("ei[0] = %p\n", exception_record->ExceptionInformation[0]);
ci = **(ClassInfo ***)(exception_record->ExceptionInformation[0]);
}
else
ci = &_Class_9Throwable;
}
if (_d_isbaseof(ci, pcb->type))
{
// Matched the catch type, so we've found the handler.
int regebp;
pti = _d_translate_se_to_d_exception(exception_record);
// Initialize catch variable
regebp = (int)&frame->ebp; // EBP for this frame
*(void **)(regebp + (pcb->bpoffset)) = pti;
// Have system call all finally blocks in intervening frames
_global_unwind(frame, exception_record);
// Call all the finally blocks skipped in this frame
_d_local_unwind(handler_table, frame, ndx);
frame->table_index = prev_ndx; // we are out of this handler
// Jump to catch block. Does not return.
{
unsigned catch_esp;
fp_t catch_addr;
catch_addr = (fp_t)(pcb->code);
catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
_asm
{
mov EAX,catch_esp
mov ECX,catch_addr
mov [EAX],ECX
mov EBP,regebp
mov ESP,EAX // reset stack
ret // jump to catch block
}
}
}
}
}
}
}
return ExceptionContinueSearch;
}
/***********************************
* Exception filter for use in __try..__except block
* surrounding call to Dmain()
*/
int _d_exception_filter(struct _EXCEPTION_POINTERS *eptrs,
int retval,
Object **exception_object)
{
*exception_object = _d_translate_se_to_d_exception(eptrs->ExceptionRecord);
return retval;
}
/***********************************
* Throw a D object.
*/
void __stdcall _d_throw(Object *h)
{
//printf("_d_throw(h = %p, &h = %p)\n", h, &h);
//printf("\tvptr = %p\n", *(void **)h);
RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION,
EXCEPTION_NONCONTINUABLE,
1, (DWORD *)&h);
}
/***********************************
* Create an exception object
*/
Object *_d_create_exception_object(ClassInfo *ci, char *msg)
{
Throwable *exc;
exc = (Throwable *)_d_newclass(ci);
// BUG: what if _d_newclass() throws an out of memory exception?
if (msg)
{
exc->msglen = strlen(msg);
exc->msg = msg;
}
return (Object *)exc;
}
/***********************************
* Converts a Windows Structured Exception code to a D Exception Object.
*/
Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record)
{
Object *pti;
switch (exception_record->ExceptionCode) {
case STATUS_DIGITAL_MARS_D_EXCEPTION:
// Generated D exception
pti = (Object *)(exception_record->ExceptionInformation[0]);
break;
case STATUS_INTEGER_DIVIDE_BY_ZERO:
pti = _d_create_exception_object(&_Class_5Error, "Integer Divide by Zero");
break;
case STATUS_FLOAT_DIVIDE_BY_ZERO:
pti = _d_create_exception_object(&_Class_5Error, "Float Divide by Zero");
break;
case STATUS_ACCESS_VIOLATION:
pti = _d_create_exception_object(&_Class_5Error, "Access Violation");
break;
case STATUS_STACK_OVERFLOW:
pti = _d_create_exception_object(&_Class_5Error, "Stack Overflow");
break;
case STATUS_DATATYPE_MISALIGNMENT:
pti = _d_create_exception_object(&_Class_5Error, "Datatype Misalignment");
break;
case STATUS_ARRAY_BOUNDS_EXCEEDED:
pti = _d_create_exception_object(&_Class_5Error, "Array Bounds Exceeded");
break;
case STATUS_FLOAT_INVALID_OPERATION:
pti = _d_create_exception_object(&_Class_5Error, "Invalid Floating Point Operation");
break;
case STATUS_FLOAT_DENORMAL_OPERAND:
pti = _d_create_exception_object(&_Class_5Error, "Floating Point Denormal Operand");
break;
case STATUS_FLOAT_INEXACT_RESULT:
pti = _d_create_exception_object(&_Class_5Error, "Floating Point Inexact Result");
break;
case STATUS_FLOAT_OVERFLOW:
pti = _d_create_exception_object(&_Class_5Error, "Floating Point Overflow");
break;
case STATUS_FLOAT_UNDERFLOW:
pti = _d_create_exception_object(&_Class_5Error, "Floating Point Underflow");
break;
case STATUS_FLOAT_STACK_CHECK:
pti = _d_create_exception_object(&_Class_5Error, "Floating Point Stack Check");
break;
case STATUS_PRIVILEGED_INSTRUCTION:
pti = _d_create_exception_object(&_Class_5Error, "Privileged Instruction");
break;
case STATUS_ILLEGAL_INSTRUCTION:
pti = _d_create_exception_object(&_Class_5Error, "Illegal Instruction");
break;
case STATUS_BREAKPOINT:
pti = _d_create_exception_object(&_Class_5Error, "Breakpoint");
break;
case STATUS_IN_PAGE_ERROR:
pti = _d_create_exception_object(&_Class_5Error, "Win32 In Page Exception");
break;
/*
case STATUS_INTEGER_OVERFLOW: // not supported on any x86 processor
case STATUS_INVALID_DISPOSITION:
case STATUS_NONCONTINUABLE_EXCEPTION:
case STATUS_SINGLE_STEP:
case DBG_CONTROL_C: // only when a debugger is attached
// In DMC, but not in Microsoft docs
case STATUS_GUARD_PAGE_VIOLATION:
case STATUS_INVALID_HANDLE:
*/
// convert all other exception codes into a Win32Exception
default:
pti = _d_create_exception_object(&_Class_5Error, "Win32 Exception");
break;
}
return pti;
}
/**************************************
* Call finally blocks in the current stack frame until stop_index.
* This is roughly equivalent to _local_unwind() for C in \src\win32\ehsup.c
*/
void __cdecl _d_local_unwind(struct DHandlerTable *handler_table,
struct DEstablisherFrame *frame, int stop_index)
{
struct DHandlerInfo *phi;
struct DCatchInfo *pci;
int i;
// Set up a special exception handler to catch double-fault exceptions.
__asm
{
push dword ptr -1
push dword ptr 0
push offset _local_except_handler // defined in src\win32\ehsup.c
push dword ptr fs:_except_list
mov FS:_except_list,ESP
}
for (i = frame->table_index; i != -1 && i != stop_index; i = phi->prev_index)
{
phi = &handler_table->handler_info[i];
if (phi->finally_code)
{
// Note that it is unnecessary to adjust the ESP, as the finally block
// accesses all items on the stack as relative to EBP.
DWORD *catch_ebp = &frame->ebp;
void *blockaddr = phi->finally_code;
_asm
{
push EBX
mov EBX,blockaddr
push EBP
mov EBP,catch_ebp
call EBX
pop EBP
pop EBX
}
}
}
_asm
{
pop FS:_except_list
add ESP,12
}
}
/***********************************
* external version of the unwinder
*/
__declspec(naked) void __cdecl _d_local_unwind2()
{
__asm
{
jmp _d_local_unwind
}
}
/***********************************
* The frame handler, this is called for each frame that has been registered
* in the OS except_list.
* Input:
* EAX the handler table for the frame
*/
EXCEPTION_DISPOSITION _d_monitor_handler(
EXCEPTION_RECORD *exception_record,
struct DEstablisherFrame *frame,
CONTEXT context,
void *dispatcher_context)
{
if (exception_record->ExceptionFlags & EXCEPTION_UNWIND)
{
_d_monitorexit((Object *)frame->table_index);
}
else
{
}
return ExceptionContinueSearch;
}
/***********************************
*/
void _d_monitor_prolog(void *x, void *y, Object *h)
{
__asm
{
push EAX
}
//printf("_d_monitor_prolog(x=%p, y=%p, h=%p)\n", x, y, h);
_d_monitorenter(h);
__asm
{
pop EAX
}
}
/***********************************
*/
void _d_monitor_epilog(void *x, void *y, Object *h)
{
//printf("_d_monitor_epilog(x=%p, y=%p, h=%p)\n", x, y, h);
__asm
{
push EAX
push EDX
}
_d_monitorexit(h);
__asm
{
pop EDX
pop EAX
}
}
#endif
/* ======================== linux =============================== */
#if linux
#include "mars.h"
extern ClassInfo D6object9Throwable7__ClassZ;
#define _Class_9Throwable D6object9Throwable7__ClassZ;
extern ClassInfo D6object5Error7__ClassZ;
#define _Class_5Error D6object5Error7__ClassZ
typedef int (*fp_t)(); // function pointer in ambient memory model
struct DHandlerInfo
{
unsigned offset; // offset from function address to start of guarded section
int prev_index; // previous table index
unsigned cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
void *finally_code; // pointer to finally code to execute
// (!=0 if try-finally)
};
// Address of DHandlerTable, searched for by eh_finddata()
struct DHandlerTable
{
void *fptr; // pointer to start of function
unsigned espoffset; // offset of ESP from EBP
unsigned retoffset; // offset from start of function to return code
unsigned nhandlers; // dimension of handler_info[]
struct DHandlerInfo handler_info[1];
};
struct DCatchBlock
{
ClassInfo *type; // catch type
unsigned bpoffset; // EBP offset of catch var
void *code; // catch handler code
};
// Create one of these for each try-catch
struct DCatchInfo
{
unsigned ncatches; // number of catch blocks
struct DCatchBlock catch_block[1]; // data for each catch block
};
// One of these is generated for each function with try-catch or try-finally
struct FuncTable
{
void *fptr; // pointer to start of function
struct DHandlerTable *handlertable; // eh data for this function
unsigned size; // size of function in bytes
};
extern struct FuncTable *table_start;
extern struct FuncTable *table_end;
void terminate()
{
// _asm
// {
// hlt
// }
}
/*******************************************
* Given address that is inside a function,
* figure out which function it is in.
* Return DHandlerTable if there is one, NULL if not.
*/
struct DHandlerTable *__eh_finddata(void *address)
{
struct FuncTable *ft;
for (ft = (struct FuncTable *)table_start;
ft < (struct FuncTable *)table_end;
ft++)
{
if (ft->fptr <= address &&
address < (void *)((char *)ft->fptr + ft->size))
{
return ft->handlertable;
}
}
return NULL;
}
/******************************
* Given EBP, find return address to caller, and caller's EBP.
* Input:
* regbp Value of EBP for current function
* *pretaddr Return address
* Output:
* *pretaddr return address to caller
* Returns:
* caller's EBP
*/
unsigned __eh_find_caller(unsigned regbp, unsigned *pretaddr)
{
unsigned bp = *(unsigned *)regbp;
if (bp) // if not end of call chain
{
// Perform sanity checks on new EBP.
// If it is screwed up, terminate() hopefully before we do more damage.
if (bp <= regbp)
// stack should grow to smaller values
terminate();
*pretaddr = *(unsigned *)(regbp + sizeof(int));
}
return bp;
}
/***********************************
* Throw a D object.
*/
void __stdcall _d_throw(Object *h)
{
unsigned regebp;
//printf("_d_throw(h = %p, &h = %p)\n", h, &h);
//printf("\tvptr = %p\n", *(void **)h);
regebp = _EBP;
while (1) // for each function on the stack
{
struct DHandlerTable *handler_table;
struct FuncTable *pfunc;
struct DHandlerInfo *phi;
unsigned retaddr;
unsigned funcoffset;
unsigned spoff;
unsigned retoffset;
int index;
int dim;
int ndx;
int prev_ndx;
regebp = __eh_find_caller(regebp,&retaddr);
if (!regebp)
// if end of call chain
break;
handler_table = __eh_finddata((void *)retaddr); // find static data associated with function
if (!handler_table) // if no static data
{
continue;
}
funcoffset = (unsigned)handler_table->fptr;
spoff = handler_table->espoffset;
retoffset = handler_table->retoffset;
#ifdef DEBUG
printf("retaddr = x%x\n",(unsigned)retaddr);
printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
regebp,funcoffset,spoff,retoffset);
#endif
// Find start index for retaddr in static data
dim = handler_table->nhandlers;
index = -1;
for (int i = 0; i < dim; i++)
{
phi = &handler_table->handler_info[i];
if ((unsigned)retaddr >= funcoffset + phi->offset)
index = i;
}
// walk through handler table, checking each handler
// with an index smaller than the current table_index
for (ndx = index; ndx != -1; ndx = prev_ndx)
{
phi = &handler_table->handler_info[ndx];
prev_ndx = phi->prev_index;
if (phi->cioffset)
{
// this is a catch handler (no finally)
struct DCatchInfo *pci;
int ncatches;
int i;
pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
ncatches = pci->ncatches;
for (i = 0; i < ncatches; i++)
{
struct DCatchBlock *pcb;
ClassInfo *ci = **(ClassInfo ***)h;
pcb = &pci->catch_block[i];
if (_d_isbaseof(ci, pcb->type))
{ // Matched the catch type, so we've found the handler.
// Initialize catch variable
*(void **)(regebp + (pcb->bpoffset)) = h;
// Jump to catch block. Does not return.
{
unsigned catch_esp;
fp_t catch_addr;
catch_addr = (fp_t)(pcb->code);
catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
_asm
{
mov EAX,catch_esp
mov ECX,catch_addr
mov [EAX],ECX
mov EBP,regebp
mov ESP,EAX // reset stack
ret // jump to catch block
}
}
}
}
}
else if (phi->finally_code)
{ // Call finally block
// Note that it is unnecessary to adjust the ESP, as the finally block
// accesses all items on the stack as relative to EBP.
void *blockaddr = phi->finally_code;
_asm
{
push EBX
mov EBX,blockaddr
push EBP
mov EBP,regebp
call EBX
pop EBP
pop EBX
}
}
}
}
}
#endif

View File

@@ -0,0 +1,316 @@
/**
* Implementation of exception handling support routines for Posix.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.deh2;
//debug=1;
extern (C)
{
extern __gshared
{
void* _deh_beg;
void* _deh_end;
}
int _d_isbaseof(ClassInfo oc, ClassInfo c);
}
alias int (*fp_t)(); // function pointer in ambient memory model
struct DHandlerInfo
{
uint offset; // offset from function address to start of guarded section
uint endoffset; // offset of end of guarded section
int prev_index; // previous table index
uint cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
void *finally_code; // pointer to finally code to execute
// (!=0 if try-finally)
}
// Address of DHandlerTable, searched for by eh_finddata()
struct DHandlerTable
{
void *fptr; // pointer to start of function
uint espoffset; // offset of ESP from EBP
uint retoffset; // offset from start of function to return code
uint nhandlers; // dimension of handler_info[]
DHandlerInfo handler_info[1];
}
struct DCatchBlock
{
ClassInfo type; // catch type
uint bpoffset; // EBP offset of catch var
void *code; // catch handler code
}
// Create one of these for each try-catch
struct DCatchInfo
{
uint ncatches; // number of catch blocks
DCatchBlock catch_block[1]; // data for each catch block
}
// One of these is generated for each function with try-catch or try-finally
struct FuncTable
{
void *fptr; // pointer to start of function
DHandlerTable *handlertable; // eh data for this function
uint fsize; // size of function in bytes
}
void terminate()
{
asm
{
hlt ;
}
}
/*******************************************
* Given address that is inside a function,
* figure out which function it is in.
* Return DHandlerTable if there is one, NULL if not.
*/
DHandlerTable *__eh_finddata(void *address)
{
FuncTable *ft;
// debug printf("__eh_finddata(address = x%x)\n", address);
// debug printf("_deh_beg = x%x, _deh_end = x%x\n", &_deh_beg, &_deh_end);
for (ft = cast(FuncTable *)&_deh_beg;
ft < cast(FuncTable *)&_deh_end;
ft++)
{
// debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n",
// ft.fptr, ft.fsize, ft.handlertable);
if (ft.fptr <= address &&
address < cast(void *)(cast(char *)ft.fptr + ft.fsize))
{
// debug printf("\tfound handler table\n");
return ft.handlertable;
}
}
// debug printf("\tnot found\n");
return null;
}
/******************************
* Given EBP, find return address to caller, and caller's EBP.
* Input:
* regbp Value of EBP for current function
* *pretaddr Return address
* Output:
* *pretaddr return address to caller
* Returns:
* caller's EBP
*/
uint __eh_find_caller(uint regbp, uint *pretaddr)
{
uint bp = *cast(uint *)regbp;
if (bp) // if not end of call chain
{
// Perform sanity checks on new EBP.
// If it is screwed up, terminate() hopefully before we do more damage.
if (bp <= regbp)
// stack should grow to smaller values
terminate();
*pretaddr = *cast(uint *)(regbp + int.sizeof);
}
return bp;
}
/***********************************
* Throw a D object.
*/
extern (Windows) void _d_throw(Object *h)
{
uint regebp;
debug
{
printf("_d_throw(h = %p, &h = %p)\n", h, &h);
printf("\tvptr = %p\n", *cast(void **)h);
}
asm
{
mov regebp,EBP ;
}
//static uint abc;
//if (++abc == 2) *(char *)0=0;
//int count = 0;
while (1) // for each function on the stack
{
DHandlerTable *handler_table;
FuncTable *pfunc;
DHandlerInfo *phi;
uint retaddr;
uint funcoffset;
uint spoff;
uint retoffset;
int index;
int dim;
int ndx;
int prev_ndx;
regebp = __eh_find_caller(regebp,&retaddr);
if (!regebp)
{ // if end of call chain
debug printf("end of call chain\n");
break;
}
debug printf("found caller, EBP = x%x, retaddr = x%x\n", regebp, retaddr);
//if (++count == 12) *(char*)0=0;
handler_table = __eh_finddata(cast(void *)retaddr); // find static data associated with function
if (!handler_table) // if no static data
{
debug printf("no handler table\n");
continue;
}
funcoffset = cast(uint)handler_table.fptr;
spoff = handler_table.espoffset;
retoffset = handler_table.retoffset;
debug
{
printf("retaddr = x%x\n",cast(uint)retaddr);
printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
regebp,funcoffset,spoff,retoffset);
}
// Find start index for retaddr in static data
dim = handler_table.nhandlers;
debug
{
printf("handler_info[]:\n");
for (int i = 0; i < dim; i++)
{
phi = &handler_table.handler_info[i];
printf("\t[%d]: offset = x%04x, endoffset = x%04x, prev_index = %d, cioffset = x%04x, finally_code = %x\n",
i, phi.offset, phi.endoffset, phi.prev_index, phi.cioffset, phi.finally_code);
}
}
index = -1;
for (int i = 0; i < dim; i++)
{
phi = &handler_table.handler_info[i];
debug printf("i = %d, phi.offset = %04x\n", i, funcoffset + phi.offset);
if (cast(uint)retaddr > funcoffset + phi.offset &&
cast(uint)retaddr <= funcoffset + phi.endoffset)
index = i;
}
debug printf("index = %d\n", index);
// walk through handler table, checking each handler
// with an index smaller than the current table_index
for (ndx = index; ndx != -1; ndx = prev_ndx)
{
phi = &handler_table.handler_info[ndx];
prev_ndx = phi.prev_index;
if (phi.cioffset)
{
// this is a catch handler (no finally)
DCatchInfo *pci;
int ncatches;
int i;
pci = cast(DCatchInfo *)(cast(char *)handler_table + phi.cioffset);
ncatches = pci.ncatches;
for (i = 0; i < ncatches; i++)
{
DCatchBlock *pcb;
ClassInfo ci = **cast(ClassInfo **)h;
pcb = &pci.catch_block[i];
if (_d_isbaseof(ci, pcb.type))
{ // Matched the catch type, so we've found the handler.
// Initialize catch variable
*cast(void **)(regebp + (pcb.bpoffset)) = h;
// Jump to catch block. Does not return.
{
uint catch_esp;
fp_t catch_addr;
catch_addr = cast(fp_t)(pcb.code);
catch_esp = regebp - handler_table.espoffset - fp_t.sizeof;
asm
{
mov EAX,catch_esp ;
mov ECX,catch_addr ;
mov [EAX],ECX ;
mov EBP,regebp ;
mov ESP,EAX ; // reset stack
ret ; // jump to catch block
}
}
}
}
}
else if (phi.finally_code)
{ // Call finally block
// Note that it is unnecessary to adjust the ESP, as the finally block
// accesses all items on the stack as relative to EBP.
void *blockaddr = phi.finally_code;
version (OSX)
{
asm
{
sub ESP,4 ; // align stack to 16
push EBX ;
mov EBX,blockaddr ;
push EBP ;
mov EBP,regebp ;
call EBX ;
pop EBP ;
pop EBX ;
add ESP,4 ;
}
}
else
{
asm
{
push EBX ;
mov EBX,blockaddr ;
push EBP ;
mov EBP,regebp ;
call EBX ;
pop EBP ;
pop EBX ;
}
}
}
}
}
}

View File

@@ -0,0 +1,374 @@
/*
* Placed into the Public Domain.
* written by Walter Bright
* www.digitalmars.com
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.dmain2;
private
{
import 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(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;
}

View File

@@ -0,0 +1,394 @@
/**
* Contains main program entry point and support routines.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.dmain2;
private
{
import rt.memory;
import rt.util.console;
import core.stdc.stddef;
import core.stdc.stdlib;
import core.stdc.string;
}
version (Windows)
{
private import core.stdc.wchar_;
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();
version (OSX)
{
// The bottom of the stack
extern (C) void* __osx_stack_end = cast(void*)0xC0000000;
}
/***********************************
* 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 (Posix)
{
throw new Exception("rt_loadLibrary not yet implemented on Posix.");
}
}
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 (Posix)
{
throw new Exception("rt_unloadLibrary not yet implemented on Posix.");
}
}
/***********************************
* 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);
}
shared bool _d_isHalting = false;
extern (C) bool rt_isHalting()
{
return _d_isHalting;
}
extern (C) shared bool rt_trapExceptions = true;
void _d_criticalInit()
{
version (Posix)
{
_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();
runModuleUnitTests();
return true;
}
catch (Throwable e)
{
if (dg)
dg(e);
}
catch
{
}
_d_criticalTerm();
return false;
}
void _d_criticalTerm()
{
version (Posix)
{
_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 (OSX)
{ /* OSX does not provide a way to get at the top of the
* stack, except for the magic value 0xC0000000.
* But as far as the gc is concerned, argv is at the top
* of the main thread's stack, so save the address of that.
*/
__osx_stack_end = cast(void*)&argv;
}
version (Posix)
{
_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 (Posix)
{
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 (Posix)
{
_STD_critical_term();
_STD_monitor_staticdtor();
}
return result;
}

View File

@@ -0,0 +1,35 @@
/**
* Implementation of invariant support routines.
*
* Copyright: Copyright Digital Mars 2007 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2007 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
/**
*
*/
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);
}

View File

@@ -0,0 +1,32 @@
/**
* Implementation of invariant support routines.
*
* Copyright: Copyright Digital Mars 2007 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2007 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.invariant_;
extern (C) void _d_invariant(Object o)
{ ClassInfo c;
//printf("__d_invariant(%p)\n", o);
// BUG: needs to be filename/line of caller, not library routine
assert(o !is null); // just do null check, not invariant check
c = o.classinfo;
do
{
if (c.classInvariant)
{
(*c.classInvariant)(o);
}
c = c.base;
} while (c);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,531 @@
/**
* Support for 64-bit longs.
*
* Copyright: Copyright Digital Mars 1993 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 1993 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.llmath;
extern (C):
/***************************************
* Unsigned long divide.
* Input:
* [EDX,EAX],[ECX,EBX]
* Output:
* [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
* [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
*/
void __ULDIV__()
{
asm
{
naked ;
test ECX,ECX ;
jz uldiv ;
// if ECX > EDX, then quotient is 0 and remainder is [EDX,EAX]
cmp ECX,EDX ;
ja quo0 ;
test ECX,ECX ;
js Lleft ;
/* We have n>d, and know that n/d will fit in 32 bits.
* d will be left justified if we shift it left s bits.
* [d1,d0] <<= s
* [n2,n1,n0] = [n1,n0] << s
*
* Use one divide, by this reasoning:
* ([n2,n1]<<32 + n0)/(d1<<32 + d0)
* becomes:
* ([n2,n1]<<32)/(d1<<32 + d0) + n0/(d1<<32 + d0)
* The second divide is always 0.
* Ignore the d0 in the first divide, which will yield a quotient
* that might be too high by 1 (because d1 is left justified).
* We can tell if it's too big if:
* q*[d1,d0] > [n2,n1,n0]
* which is:
* q*[d1,d0] > [[q*[d1,0]+q%[d1,0],n1,n0]
* If we subtract q*[d1,0] from both sides, we get:
* q*d0 > [[n2,n1]%d1,n0]
* So if it is too big by one, reduce q by one to q'=q-one.
* Compute remainder as:
* r = ([n1,n0] - q'*[d1,d0]) >> s
* Again, we can subtract q*[d1,0]:
* r = ([n1,n0] - q*[d1,0] - (q'*[d1,d0] - q*[d1,0])) >> s
* r = ([[n2,n1]%d1,n0] + (q*[d1,0] - (q - one)*[d1,d0])) >> s
* r = ([[n2,n1]%d1,n0] + (q*[d1,0] - [d1 *(q-one),d0*(1-q)])) >> s
* r = ([[n2,n1]%d1,n0] + [d1 *one,d0*(one-q)])) >> s
*/
push EBP ;
push ESI ;
push EDI ;
mov ESI,EDX ;
mov EDI,EAX ;
mov EBP,ECX ;
bsr EAX,ECX ; // EAX is now 30..0
xor EAX,0x1F ; // EAX is now 1..31
mov CH,AL ;
neg EAX ;
add EAX,32 ;
mov CL,AL ;
mov EAX,EBX ;
shr EAX,CL ;
xchg CH,CL ;
shl EBP,CL ;
or EBP,EAX ;
shl EBX,CL ;
mov EDX,ESI ;
xchg CH,CL ;
shr EDX,CL ;
mov EAX,EDI ;
shr EAX,CL ;
xchg CH,CL ;
shl EDI,CL ;
shl ESI,CL ;
or EAX,ESI ;
div EBP ;
push EBP ;
mov EBP,EAX ;
mov ESI,EDX ;
mul EBX ;
cmp EDX,ESI ;
ja L1 ;
jb L2 ;
cmp EAX,EDI ;
jbe L2 ;
L1: dec EBP ;
sub EAX,EBX ;
sbb EDX,0[ESP] ;
L2:
add ESP,4 ;
sub EDI,EAX ;
sbb ESI,EDX ;
mov EAX,ESI ;
xchg CH,CL ;
shl EAX,CL ;
xchg CH,CL ;
shr EDI,CL ;
or EDI,EAX ;
shr ESI,CL ;
mov EBX,EDI ;
mov ECX,ESI ;
mov EAX,EBP ;
xor EDX,EDX ;
pop EDI ;
pop ESI ;
pop EBP ;
ret ;
uldiv: test EDX,EDX ;
jnz D3 ;
// Both high words are 0, we can use the DIV instruction
div EBX ;
mov EBX,EDX ;
mov EDX,ECX ; // EDX = ECX = 0
ret ;
even ;
D3: // Divide [EDX,EAX] by EBX
mov ECX,EAX ;
mov EAX,EDX ;
xor EDX,EDX ;
div EBX ;
xchg ECX,EAX ;
div EBX ;
// ECX,EAX = result
// EDX = remainder
mov EBX,EDX ;
mov EDX,ECX ;
xor ECX,ECX ;
ret ;
quo0: // Quotient is 0
// Remainder is [EDX,EAX]
mov EBX,EAX ;
mov ECX,EDX ;
xor EAX,EAX ;
xor EDX,EDX ;
ret ;
Lleft: // The quotient is 0 or 1 and EDX >= ECX
cmp EDX,ECX ;
ja quo1 ; // [EDX,EAX] > [ECX,EBX]
// EDX == ECX
cmp EAX,EBX ;
jb quo0 ;
quo1: // Quotient is 1
// Remainder is [EDX,EAX] - [ECX,EBX]
sub EAX,EBX ;
sbb EDX,ECX ;
mov EBX,EAX ;
mov ECX,EDX ;
mov EAX,1 ;
xor EDX,EDX ;
ret ;
}
}
/***************************************
* Signed long divide.
* Input:
* [EDX,EAX],[ECX,EBX]
* Output:
* [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
* [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
* ESI,EDI destroyed
*/
void __LDIV__()
{
asm
{
naked ;
test EDX,EDX ; // [EDX,EAX] negative?
jns L10 ; // no
//neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX]
neg EDX ;
neg EAX ;
sbb EDX,0 ;
test ECX,ECX ; // [ECX,EBX] negative?
jns L11 ; // no
//neg64 ECX,EBX ;
neg ECX ;
neg EBX ;
sbb ECX,0 ;
call __ULDIV__ ;
//neg64 ECX,EBX ; // remainder same sign as dividend
neg ECX ;
neg EBX ;
sbb ECX,0 ;
ret ;
L11: call __ULDIV__ ;
//neg64 ECX,EBX ; // remainder same sign as dividend
neg ECX ;
neg EBX ;
sbb ECX,0 ;
//neg64 EDX,EAX ; // quotient is negative
neg EDX ;
neg EAX ;
sbb EDX,0 ;
ret ;
L10: test ECX,ECX ; // [ECX,EBX] negative?
jns L12 ; // no (all is positive)
//neg64 ECX,EBX ;
neg ECX ;
neg EBX ;
sbb ECX,0 ;
call __ULDIV__ ;
//neg64 EDX,EAX ; // quotient is negative
neg EDX ;
neg EAX ;
sbb EDX,0 ;
ret ;
L12: jmp __ULDIV__ ;
}
}
/***************************************
* Compare [EDX,EAX] with [ECX,EBX]
* Signed
* Returns result in flags
*/
void __LCMP__()
{
asm
{
naked ;
cmp EDX,ECX ;
jne C1 ;
push EDX ;
xor EDX,EDX ;
cmp EAX,EBX ;
jz C2 ;
ja C3 ;
dec EDX ;
pop EDX ;
ret ;
C3: inc EDX ;
C2: pop EDX ;
C1: ret ;
}
}
// Convert ulong to real
private __gshared real adjust = cast(real)0x800_0000_0000_0000 * 0x10;
real __U64_LDBL()
{
version (OSX)
{ /* OSX version has to be concerned about 16 byte stack
* alignment and the inability to reference the data segment
* because of PIC.
*/
asm
{ naked ;
push EDX ;
push EAX ;
and dword ptr 4[ESP], 0x7FFFFFFF ;
fild qword ptr [ESP] ;
test EDX,EDX ;
jns L1 ;
push 0x0000403e ;
push 0x80000000 ;
push 0 ;
fld real ptr [ESP] ; // adjust
add ESP,12 ;
faddp ST(1), ST ;
L1: ;
add ESP, 8 ;
ret ;
}
}
else
{
asm
{ naked ;
push EDX ;
push EAX ;
and dword ptr 4[ESP], 0x7FFFFFFF ;
fild qword ptr [ESP] ;
test EDX,EDX ;
jns L1 ;
fld real ptr adjust ;
faddp ST(1), ST ;
L1: ;
add ESP, 8 ;
ret ;
}
}
}
// Same as __U64_LDBL, but return result as double in [EDX,EAX]
ulong __ULLNGDBL()
{
asm
{ naked ;
call __U64_LDBL ;
sub ESP,8 ;
fstp double ptr [ESP] ;
pop EAX ;
pop EDX ;
ret ;
}
}
// Convert double to ulong
private __gshared short roundTo0 = 0xFBF;
ulong __DBLULLNG()
{
// BUG: should handle NAN's and overflows
version (OSX)
{
asm
{ naked ;
push 0xFBF ; // roundTo0
push 0x0000403e ;
push 0x80000000 ;
push 0 ; // adjust
push EDX ;
push EAX ;
fld double ptr [ESP] ;
sub ESP,8 ;
fld real ptr 16[ESP] ; // adjust
fcomp ;
fstsw AX ;
fstcw 8[ESP] ;
fldcw 28[ESP] ; // roundTo0
sahf ;
jae L1 ;
fld real ptr 16[ESP] ; // adjust
fsubp ST(1), ST ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,24 ;
add EDX,0x8000_0000 ;
ret ;
L1: ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,24 ;
ret ;
}
}
else
{
asm
{ naked ;
push EDX ;
push EAX ;
fld double ptr [ESP] ;
sub ESP,8 ;
fld real ptr adjust ;
fcomp ;
fstsw AX ;
fstcw 8[ESP] ;
fldcw roundTo0 ;
sahf ;
jae L1 ;
fld real ptr adjust ;
fsubp ST(1), ST ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,8 ;
add EDX,0x8000_0000 ;
ret ;
L1: ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,8 ;
ret ;
}
}
}
// Convert double in ST0 to uint
uint __DBLULNG()
{
// BUG: should handle NAN's and overflows
version (OSX)
{
asm
{ naked ;
push 0xFBF ; // roundTo0
sub ESP,12 ;
fstcw 8[ESP] ;
fldcw 12[ESP] ; // roundTo0
fistp qword ptr [ESP] ;
fldcw 8[ESP] ;
pop EAX ;
add ESP,12 ;
ret ;
}
}
else
{
asm
{ naked ;
sub ESP,16 ;
fstcw 8[ESP] ;
fldcw roundTo0 ;
fistp qword ptr [ESP] ;
fldcw 8[ESP] ;
pop EAX ;
add ESP,12 ;
ret ;
}
}
}
// Convert real in ST0 to ulong
ulong __LDBLULLNG()
{
version (OSX)
{
asm
{ naked ;
push 0xFBF ; // roundTo0
push 0x0000403e ;
push 0x80000000 ;
push 0 ; // adjust
sub ESP,16 ;
fld real ptr 16[ESP] ; // adjust
fcomp ;
fstsw AX ;
fstcw 8[ESP] ;
fldcw 28[ESP] ; // roundTo0
sahf ;
jae L1 ;
fld real ptr 16[ESP] ; // adjust
fsubp ST(1), ST ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,24 ;
add EDX,0x8000_0000 ;
ret ;
L1: ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,24 ;
ret ;
}
}
else
{
asm
{ naked ;
sub ESP,16 ;
fld real ptr adjust ;
fcomp ;
fstsw AX ;
fstcw 8[ESP] ;
fldcw roundTo0 ;
sahf ;
jae L1 ;
fld real ptr adjust ;
fsubp ST(1), ST ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,8 ;
add EDX,0x8000_0000 ;
ret ;
L1: ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,8 ;
ret ;
}
}
}

View File

@@ -0,0 +1,105 @@
/**
* Common declarations for runtime implementation.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <stddef.h>
#if __cplusplus
extern "C" {
#endif
struct ClassInfo;
struct Vtbl;
typedef struct Vtbl
{
size_t len;
void **vptr;
} Vtbl;
typedef struct Interface
{
struct ClassInfo *classinfo;
struct Vtbl vtbl;
int offset;
} Interface;
typedef struct Object
{
void **vptr;
void *monitor;
} Object;
typedef struct ClassInfo
{
Object object;
size_t initlen;
void *init;
size_t namelen;
char *name;
Vtbl vtbl;
size_t interfacelen;
Interface *interfaces;
struct ClassInfo *baseClass;
void *destructor;
void *invariant;
int flags;
} ClassInfo;
typedef struct Throwable
{
Object object;
size_t msglen;
char* msg;
size_t filelen;
char* file;
size_t line;
struct Interface *info;
struct Throwable *next;
} Throwable;
typedef struct Array
{
size_t length;
void *ptr;
} Array;
typedef struct Delegate
{
void *thisptr;
void (*funcptr)();
} Delegate;
void _d_monitorenter(Object *h);
void _d_monitorexit(Object *h);
int _d_isbaseof(ClassInfo *b, ClassInfo *c);
Object *_d_dynamic_cast(Object *o, ClassInfo *ci);
Object * _d_newclass(ClassInfo *ci);
void _d_delclass(Object **p);
void _d_OutOfMemory();
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,213 @@
/**
* This module exposes functionality for inspecting and manipulating memory.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.memory;
private
{
version( linux )
{
version = SimpleLibcStackEnd;
version( SimpleLibcStackEnd )
{
extern (C) extern __gshared void* __libc_stack_end;
}
}
version( FreeBSD )
{
version = SimpleLibcStackEnd;
version( SimpleLibcStackEnd )
{
extern (C) extern __gshared void* __libc_stack_end;
}
}
version( Solaris )
{
version = SimpleLibcStackEnd;
version( SimpleLibcStackEnd )
{
extern (C) extern __gshared void* __libc_stack_end;
}
}
extern (C) void gc_addRange( void* p, size_t sz );
extern (C) void gc_removeRange( void* p );
}
/**
*
*/
extern (C) void* rt_stackBottom()
{
version( Windows )
{
asm
{
naked;
mov EAX,FS:4;
ret;
}
}
else version( linux )
{
version( SimpleLibcStackEnd )
{
return __libc_stack_end;
}
else
{
// See discussion: http://autopackage.org/forums/viewtopic.php?t=22
static void** libc_stack_end;
if( libc_stack_end == libc_stack_end.init )
{
void* handle = dlopen( null, RTLD_NOW );
libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" );
dlclose( handle );
}
return *libc_stack_end;
}
}
else version( OSX )
{
return cast(void*) 0xc0000000;
}
else version( FreeBSD )
{
return __libc_stack_end;
}
else version( Solaris )
{
return __libc_stack_end;
}
else
{
static assert( false, "Operating system not supported." );
}
}
/**
*
*/
extern (C) void* rt_stackTop()
{
version( D_InlineAsm_X86 )
{
asm
{
naked;
mov EAX, ESP;
ret;
}
}
else
{
static assert( false, "Architecture not supported." );
}
}
private
{
version( Windows )
{
extern (C)
{
extern __gshared
{
int _xi_a; // &_xi_a just happens to be start of data segment
int _edata; // &_edata is start of BSS segment
int _end; // &_end is past end of BSS
}
}
}
else version( linux )
{
extern (C)
{
extern __gshared
{
int _data;
int __data_start;
int _end;
int _data_start__;
int _data_end__;
int _bss_start__;
int _bss_end__;
int __fini_array_end;
}
}
alias __data_start Data_Start;
alias _end Data_End;
}
else version( OSX )
{
extern (C) void _d_osx_image_init();
}
else version( FreeBSD )
{
extern (C)
{
extern __gshared
{
int etext;
int _end;
}
}
}
else version( Solaris )
{
extern (C)
{
extern __gshared
{
int etext;
int _end;
}
}
}
}
void initStaticDataGC()
{
version( Windows )
{
gc_addRange( &_xi_a, cast(size_t) &_end - cast(size_t) &_xi_a );
}
else version( linux )
{
gc_addRange( &__data_start, cast(size_t) &_end - cast(size_t) &__data_start );
}
else version( OSX )
{
_d_osx_image_init();
}
else version( FreeBSD )
{
gc_addRange( &etext, cast(size_t) &_end - cast(size_t) &etext );
}
else version( Solaris )
{
gc_addRange( &etext, cast(size_t) &_end - cast(size_t) &etext );
}
else
{
static assert( false, "Operating system not supported." );
}
}

View File

@@ -0,0 +1,75 @@
/**
* This module provides OSX-specific support routines for memory.d.
*
* Copyright: Copyright Digital Mars 2008 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2008 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <mach-o/getsect.h>
void gc_addRange( void* p, size_t sz );
void gc_removeRange( void* p );
typedef struct
{
const char* seg;
const char* sect;
} seg_ref;
const static seg_ref data_segs[] = {{SEG_DATA, SECT_DATA},
{SEG_DATA, SECT_BSS},
{SEG_DATA, SECT_COMMON}};
const static int NUM_DATA_SEGS = sizeof(data_segs) / sizeof(seg_ref);
static void on_add_image( const struct mach_header* h, intptr_t slide )
{
const struct section* sect;
int i;
for( i = 0; i < NUM_DATA_SEGS; ++i )
{
sect = getsectbynamefromheader( h,
data_segs[i].seg,
data_segs[i].sect );
if( sect == NULL || sect->size == 0 )
continue;
gc_addRange( (void*) sect->addr + slide, sect->size );
}
}
static void on_remove_image( const struct mach_header* h, intptr_t slide )
{
const struct section* sect;
int i;
for( i = 0; i < NUM_DATA_SEGS; ++i )
{
sect = getsectbynamefromheader( h,
data_segs[i].seg,
data_segs[i].sect );
if( sect == NULL || sect->size == 0 )
continue;
gc_removeRange( (void*) sect->addr + slide );
}
}
void _d_osx_image_init()
{
_dyld_register_func_for_add_image( &on_add_image );
_dyld_register_func_for_remove_image( &on_remove_image );
}
#endif

View File

@@ -0,0 +1,109 @@
/**
* Contains a memset implementation used by compiler-generated code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.memset;
extern (C)
{
// Functions from the C library.
void *memcpy(void *, void *, size_t);
}
extern (C):
short *_memset16(short *p, short value, size_t count)
{
short *pstart = p;
short *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
int *_memset32(int *p, int value, size_t count)
{
version (X86)
{
asm
{
mov EDI,p ;
mov EAX,value ;
mov ECX,count ;
mov EDX,EDI ;
rep ;
stosd ;
mov EAX,EDX ;
}
}
else
{
int *pstart = p;
int *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
}
long *_memset64(long *p, long value, size_t count)
{
long *pstart = p;
long *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
cdouble *_memset128(cdouble *p, cdouble value, size_t count)
{
cdouble *pstart = p;
cdouble *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
real *_memset80(real *p, real value, size_t count)
{
real *pstart = p;
real *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
creal *_memset160(creal *p, creal value, size_t count)
{
creal *pstart = p;
creal *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
void *_memsetn(void *p, void *value, int count, size_t sizelem)
{ void *pstart = p;
int i;
for (i = 0; i < count; i++)
{
memcpy(p, value, sizelem);
p = cast(void *)(cast(char *)p + sizelem);
}
return pstart;
}

View File

@@ -0,0 +1,85 @@
;_ minit.asm
; Module initialization support.
;
; Copyright: Copyright Digital Mars 2000 - 2009.
; License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
; Authors: Walter Bright
;
; Copyright Digital Mars 2000 - 2009.
; Distributed under the Boost Software License, Version 1.0.
; (See accompanying file LICENSE_1_0.txt or copy at
; http://www.boost.org/LICENSE_1_0.txt)
;
include macros.asm
ifdef _WIN32
DATAGRP EQU FLAT
else
DATAGRP EQU DGROUP
endif
; Provide a default resolution for weak extern records, no way in C
; to define an omf symbol with a specific value
public __nullext
__nullext equ 0
extrn __moduleinfo_array:near
; This bit of assembler is needed because, from C or D, one cannot
; specify the names of data segments. Why does this matter?
; All the ModuleInfo pointers are placed into a segment named 'FM'.
; The order in which they are placed in 'FM' is arbitrarily up to the linker.
; In order to walk all the pointers, we need to be able to find the
; beginning and the end of the 'FM' segment.
; This is done by bracketing the 'FM' segment with two other, empty,
; segments named 'FMB' and 'FME'. Since this module is the only one that
; ever refers to 'FMB' and 'FME', we get to control the order in which
; these segments appear relative to 'FM' by using a GROUP statement.
; So, we have in memory:
; FMB empty segment
; FM contains all the pointers
; FME empty segment
; and finding the limits of FM is as easy as taking the address of FMB
; and the address of FME.
; These segments bracket FM, which contains the list of ModuleInfo pointers
FMB segment dword use32 public 'DATA'
FMB ends
FM segment dword use32 public 'DATA'
FM ends
FME segment dword use32 public 'DATA'
FME ends
; This leaves room in the _fatexit() list for _moduleDtor()
XOB segment dword use32 public 'BSS'
XOB ends
XO segment dword use32 public 'BSS'
dd ?
XO ends
XOE segment dword use32 public 'BSS'
XOE ends
DGROUP group FMB,FM,FME
begcode minit
; extern (C) void _minit();
; Converts array of ModuleInfo pointers to a D dynamic array of them,
; so they can be accessed via D.
; Result is written to:
; extern (C) ModuleInfo[] _moduleinfo_array;
public __minit
__minit proc near
mov EDX,offset DATAGRP:FMB
mov EAX,offset DATAGRP:FME
mov dword ptr __moduleinfo_array+4,EDX
sub EAX,EDX ; size in bytes of FM segment
shr EAX,2 ; convert to array length
mov dword ptr __moduleinfo_array,EAX
ret
__minit endp
endcode minit
end

View File

@@ -0,0 +1,215 @@
/**
* Contains the implementation for object monitors.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#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
#ifndef PTHREAD_MUTEX_RECURSIVE
# define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#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);
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

View File

@@ -0,0 +1,34 @@
/**
* Containts object comparator functions called by generated code.
*
* Copyright: Copyright Digital Mars 2002 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.obj;
extern (C):
/********************************
* Compiler helper for operator == for class objects.
*/
int _d_obj_eq(Object o1, Object o2)
{
return o1 is o2 || (o1 && o1.opEquals(o2));
}
/********************************
* Compiler helper for operator <, <=, >, >= for class objects.
*/
int _d_obj_cmp(Object o1, Object o2)
{
return o1.opCmp(o2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
# Makefile to build the compiler runtime D library for Linux
# Designed to work with GNU make
# Targets:
# make
# Same as make all
# make debug
# Build the debug version of the library
# make release
# Build the release version of the library
# make doc
# Generate documentation
# make clean
# Delete all files created by build process
# Essentials
LIBDIR=../../../lib
DOCDIR=../../../doc
IMPDIR=../../../import
LIBBASENAME=libdruntime-rt-dmd.a
MODULES=
BUILDS=debug release unittest
MODULES_BASE=aaA aApply aApplyR adi alloca arrayassign arraybyte \
arraycast arraycat arraydouble arrayfloat arrayint arrayreal \
arrayshort cast_ cmath2 cover deh2 dmain2 invariant invariant_ \
lifetime llmath memory memset obj object_ qsort switch_ trace
# NOTE: trace.o and cover.o are not necessary for a successful build
# as both are used for debugging features (profiling and coverage)
# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and
# minit.asm is not used by dmd for Linux
# NOTE: deh.o is only needed for Win32, Linux uses deh2.o
MODULES_UTIL=$(addprefix util/,console cpuid ctype string utf)
MODULES_TI=$(addprefix typeinfo/ti_,AC Acdouble Acfloat Acreal Adouble \
Afloat Ag Aint Along Areal Ashort byte C cdouble cfloat char creal \
dchar delegate double float idouble ifloat int ireal long ptr real \
short ubyte uint ulong ushort void wchar)
C_SRCS=complex.c critical.c memory_osx.c monitor.c
# Symbols
DMD=dmd
DOCFLAGS=-version=DDoc
DFLAGS_release=-d -release -O -inline -w -nofloat
DFLAGS_debug=-d -g -w -nofloat
DFLAGS_unittest=$(DFLAGS_release) -unittest
CFLAGS_release=-m32 -O
CFLAGS_debug=-m32 -g
CFLAGS_unittest=$(CFLAGS_release)
# Derived symbols
C_OBJS=$(addsuffix .o,$(basename $(C_SRCS)))
AS_OBJS=$(addsuffix .o,$(basename $(AS_SRCS)))
ALL_MODULES=$(MODULES_BASE) $(MODULES_UTIL) $(MODULES_TI)
D_SRCS=$(addsuffix .d,$(ALL_MODULES))
ALLLIBS=$(addsuffix /$(LIBBASENAME),$(addprefix $(LIBDIR)/,$(BUILDS)))
# Patterns
$(LIBDIR)/%/$(LIBBASENAME) : $(D_SRCS) $(C_SRCS) $(AS_SRCS)
$(CC) -c $(CFLAGS_$*) $(C_SRCS)
$(DMD) $(DFLAGS_$*) -lib -of$@ $(D_SRCS) $(C_OBJS) $(AS_OBJS)
rm $(C_OBJS) $(AS_OBJS)
$(DOCDIR)/%.html : %.d
$(DMD) -c -d -o- -Df$@ $<
$(IMPDIR)/%.di : %.d
$(DMD) -c -d -o- -Hf$@ $<
# Rulez
all : $(BUILDS) doc
debug : $(LIBDIR)/debug/$(LIBBASENAME) $(IMPORTS)
release : $(LIBDIR)/release/$(LIBBASENAME) $(IMPORTS)
unittest : $(LIBDIR)/unittest/$(LIBBASENAME) $(IMPORTS)
#doc : $(DOCS)
clean :
rm -f $(IMPORTS) $(DOCS) $(ALLLIBS)

View File

@@ -0,0 +1,158 @@
/*
Portions of this file are:
Copyright Prototronics, 1987
Totem Lake P.O. 8117
Kirkland, Washington 98034
(206) 820-1972
Licensed to Digital Mars.
June 11, 1987 from Ray Gardner's
Denver, Colorado) public domain version
Use qsort2.d instead of this file if a redistributable version of
_adSort() is required.
*/
module rt.qsort;
/*
** Sorts an array starting at base, of length nbr_elements, each
** element of size width_bytes, ordered via compare_function; which
** is called as (*comp_fp)(ptr_to_element1, ptr_to_element2)
** and returns < 0 if element1 < element2, 0 if element1 = element2,
** > 0 if element1 > element2. Most of the refinements are due to
** R. Sedgewick. See "Implementing Quicksort Programs", Comm. ACM,
** Oct. 1978, and Corrigendum, Comm. ACM, June 1979.
*/
//debug=qsort; // uncomment to turn on debugging printf's
struct Array
{
size_t length;
void* ptr;
}
private const int _maxspan = 7; // subarrays of _maxspan or fewer elements
// will be sorted by a simple insertion sort
/* Adjust _maxspan according to relative cost of a swap and a compare. Reduce
_maxspan (not less than 1) if a swap is very expensive such as when you have
an array of large structures to be sorted, rather than an array of pointers to
structures. The default value is optimized for a high cost for compares. */
extern (C) long _adSort(Array a, TypeInfo ti)
{
byte* base;
byte*[40] stack; // stack
byte** sp; // stack pointer
byte* i, j, limit; // scan and limit pointers
uint thresh; // size of _maxspan elements in bytes
uint width = ti.tsize();
base = cast(byte *)a.ptr;
thresh = _maxspan * width; // init threshold
sp = stack.ptr; // init stack pointer
limit = base + a.length * width; // pointer past end of array
while (1) // repeat until done then return
{
while (limit - base > thresh) // if more than _maxspan elements
{
//swap middle, base
ti.swap((cast(uint)(limit - base) >> 1) -
(((cast(uint)(limit - base) >> 1)) % width) + base, base);
i = base + width; // i scans from left to right
j = limit - width; // j scans from right to left
if (ti.compare(i, j) > 0) // Sedgewick's
ti.swap(i, j); // three-element sort
if (ti.compare(base, j) > 0) // sets things up
ti.swap(base, j); // so that
if (ti.compare(i, base) > 0) // *i <= *base <= *j
ti.swap(i, base); // *base is the pivot element
while (1)
{
do // move i right until *i >= pivot
i += width;
while (ti.compare(i, base) < 0);
do // move j left until *j <= pivot
j -= width;
while (ti.compare(j, base) > 0);
if (i > j) // break loop if pointers crossed
break;
ti.swap(i, j); // else swap elements, keep scanning
}
ti.swap(base, j); // move pivot into correct place
if (j - base > limit - i) // if left subarray is larger...
{
sp[0] = base; // stack left subarray base
sp[1] = j; // and limit
base = i; // sort the right subarray
}
else // else right subarray is larger
{
sp[0] = i; // stack right subarray base
sp[1] = limit; // and limit
limit = j; // sort the left subarray
}
sp += 2; // increment stack pointer
assert(sp < cast(byte**)stack + stack.length);
}
// Insertion sort on remaining subarray
i = base + width;
while (i < limit)
{
j = i;
while (j > base && ti.compare(j - width, j) > 0)
{
ti.swap(j - width, j);
j -= width;
}
i += width;
}
if (sp > stack.ptr) // if any entries on stack...
{
sp -= 2; // pop the base and limit
base = sp[0];
limit = sp[1];
}
else // else stack empty, all done
return *cast(long*)(&a);
}
assert(0);
}
unittest
{
debug(qsort) printf("array.sort.unittest()\n");
int a[] = new int[10];
a[0] = 23;
a[1] = 1;
a[2] = 64;
a[3] = 5;
a[4] = 6;
a[5] = 5;
a[6] = 17;
a[7] = 3;
a[8] = 0;
a[9] = -1;
a.sort;
for (int i = 0; i < a.length - 1; i++)
{
//printf("i = %d", i);
//printf(" %d %d\n", a[i], a[i + 1]);
assert(a[i] <= a[i + 1]);
}
}

View File

@@ -0,0 +1,71 @@
/**
* 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.
*
* Copyright: Copyright Digital Mars 2000 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2000 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.qsort2;
//debug=qsort;
private import core.stdc.stdlib;
struct Array
{
size_t length;
void* ptr;
}
private TypeInfo tiglobal;
extern (C) int cmp(void* p1, void* p2)
{
return tiglobal.compare(p1, p2);
}
extern (C) long _adSort(Array a, TypeInfo ti)
{
synchronized
{
tiglobal = ti;
qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp);
}
return *cast(long*)(&a);
}
unittest
{
debug(qsort) printf("array.sort.unittest()\n");
int a[] = new int[10];
a[0] = 23;
a[1] = 1;
a[2] = 64;
a[3] = 5;
a[4] = 6;
a[5] = 5;
a[6] = 17;
a[7] = 3;
a[8] = 0;
a[9] = -1;
a.sort;
for (int i = 0; i < a.length - 1; i++)
{
//printf("i = %d", i);
//printf(" %d %d\n", a[i], a[i + 1]);
assert(a[i] <= a[i + 1]);
}
}

View File

@@ -0,0 +1,411 @@
/**
* Contains support code for switch blocks using string constants.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.switch_;
private import core.stdc.string;
/******************************************************
* Support for switch statements switching on strings.
* Input:
* table[] sorted array of strings generated by compiler
* ca string to look up in table
* Output:
* result index of match in table[]
* -1 if not in table
*/
extern (C):
int _d_switch_string(char[][] table, char[] ca)
in
{
//printf("in _d_switch_string()\n");
assert(table.length >= 0);
assert(ca.length >= 0);
// Make sure table[] is sorted correctly
int j;
for (j = 1; j < table.length; j++)
{
int len1 = table[j - 1].length;
int len2 = table[j].length;
assert(len1 <= len2);
if (len1 == len2)
{
int ci;
ci = memcmp(table[j - 1].ptr, table[j].ptr, len1);
assert(ci < 0); // ci==0 means a duplicate
}
}
}
out (result)
{
int i;
int cj;
//printf("out _d_switch_string()\n");
if (result == -1)
{
// Not found
for (i = 0; i < table.length; i++)
{
if (table[i].length == ca.length)
{ cj = memcmp(table[i].ptr, ca.ptr, ca.length);
assert(cj != 0);
}
}
}
else
{
assert(0 <= result && result < table.length);
for (i = 0; 1; i++)
{
assert(i < table.length);
if (table[i].length == ca.length)
{
cj = memcmp(table[i].ptr, ca.ptr, ca.length);
if (cj == 0)
{
assert(i == result);
break;
}
}
}
}
}
body
{
//printf("body _d_switch_string(%.*s)\n", ca);
int low;
int high;
int mid;
int c;
char[] pca;
low = 0;
high = table.length;
version (none)
{
// Print table
printf("ca[] = '%s'\n", cast(char *)ca);
for (mid = 0; mid < high; mid++)
{
pca = table[mid];
printf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
}
}
if (high &&
ca.length >= table[0].length &&
ca.length <= table[high - 1].length)
{
// Looking for 0 length string, which would only be at the beginning
if (ca.length == 0)
return 0;
char c1 = ca[0];
// Do binary search
while (low < high)
{
mid = (low + high) >> 1;
pca = table[mid];
c = ca.length - pca.length;
if (c == 0)
{
c = cast(ubyte)c1 - cast(ubyte)pca[0];
if (c == 0)
{
c = memcmp(ca.ptr, pca.ptr, ca.length);
if (c == 0)
{ //printf("found %d\n", mid);
return mid;
}
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
}
//printf("not found\n");
return -1; // not found
}
unittest
{
switch (cast(char []) "c")
{
case "coo":
default:
break;
}
}
/**********************************
* Same thing, but for wide chars.
*/
int _d_switch_ustring(wchar[][] table, wchar[] ca)
in
{
//printf("in _d_switch_ustring()\n");
assert(table.length >= 0);
assert(ca.length >= 0);
// Make sure table[] is sorted correctly
int j;
for (j = 1; j < table.length; j++)
{
int len1 = table[j - 1].length;
int len2 = table[j].length;
assert(len1 <= len2);
if (len1 == len2)
{
int c;
c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof);
assert(c < 0); // c==0 means a duplicate
}
}
}
out (result)
{
int i;
int c;
//printf("out _d_switch_string()\n");
if (result == -1)
{
// Not found
for (i = 0; i < table.length; i++)
{
if (table[i].length == ca.length)
{ c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
assert(c != 0);
}
}
}
else
{
assert(0 <= result && result < table.length);
for (i = 0; 1; i++)
{
assert(i < table.length);
if (table[i].length == ca.length)
{
c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
if (c == 0)
{
assert(i == result);
break;
}
}
}
}
}
body
{
//printf("body _d_switch_ustring()\n");
int low;
int high;
int mid;
int c;
wchar[] pca;
low = 0;
high = table.length;
/*
// Print table
wprintf("ca[] = '%.*s'\n", ca);
for (mid = 0; mid < high; mid++)
{
pca = table[mid];
wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
}
*/
// Do binary search
while (low < high)
{
mid = (low + high) >> 1;
pca = table[mid];
c = ca.length - pca.length;
if (c == 0)
{
c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof);
if (c == 0)
{ //printf("found %d\n", mid);
return mid;
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
//printf("not found\n");
return -1; // not found
}
unittest
{
switch (cast(wchar []) "c")
{
case "coo":
default:
break;
}
}
/**********************************
* Same thing, but for wide chars.
*/
int _d_switch_dstring(dchar[][] table, dchar[] ca)
in
{
//printf("in _d_switch_dstring()\n");
assert(table.length >= 0);
assert(ca.length >= 0);
// Make sure table[] is sorted correctly
int j;
for (j = 1; j < table.length; j++)
{
int len1 = table[j - 1].length;
int len2 = table[j].length;
assert(len1 <= len2);
if (len1 == len2)
{
int c;
c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof);
assert(c < 0); // c==0 means a duplicate
}
}
}
out (result)
{
int i;
int c;
//printf("out _d_switch_string()\n");
if (result == -1)
{
// Not found
for (i = 0; i < table.length; i++)
{
if (table[i].length == ca.length)
{ c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
assert(c != 0);
}
}
}
else
{
assert(0 <= result && result < table.length);
for (i = 0; 1; i++)
{
assert(i < table.length);
if (table[i].length == ca.length)
{
c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
if (c == 0)
{
assert(i == result);
break;
}
}
}
}
}
body
{
//printf("body _d_switch_ustring()\n");
int low;
int high;
int mid;
int c;
dchar[] pca;
low = 0;
high = table.length;
/*
// Print table
wprintf("ca[] = '%.*s'\n", ca);
for (mid = 0; mid < high; mid++)
{
pca = table[mid];
wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
}
*/
// Do binary search
while (low < high)
{
mid = (low + high) >> 1;
pca = table[mid];
c = ca.length - pca.length;
if (c == 0)
{
c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof);
if (c == 0)
{ //printf("found %d\n", mid);
return mid;
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
//printf("not found\n");
return -1; // not found
}
unittest
{
switch (cast(dchar []) "c")
{
case "coo":
default:
break;
}
}

View File

@@ -0,0 +1,44 @@
/**
* Contains support code for thread-local storage.
*
* Copyright: Copyright Digital Mars 2008 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2008 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#if linux
/* The memory between the addresses of _tlsstart and _tlsend is the storage for
* thread-local data in D 2.0. Both of these rely on the default linker script
* of:
* .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
* .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
* to group the sections in that order.
*
* Sadly, this does not work because ld orders .tdata after .tdata.*, despite
* what the linker script says.
*/
.file "tls.S"
.globl _tlsstart
.section .tdata,"awT",@progbits
.align 4
.type _tlsstart, @object
.size _tlsstart, 4
_tlsstart:
.long 3
.globl _tlsend
.section .tcommon,"awT",@nobits
.align 4
.type _tlsend, @object
.size _tlsend, 4
_tlsend:
.zero 4
#endif

View File

@@ -0,0 +1,919 @@
/**
* Contains support code for code profiling.
*
* Copyright: Copyright Digital Mars 1995 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright, Sean Kelly
*
* Copyright Digital Mars 1995 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.trace;
private
{
import rt.util.string;
import core.stdc.ctype;
import core.stdc.stdio;
import core.stdc.string;
import core.stdc.stdlib;
}
extern (C):
char* unmangle_ident(char*); // from DMC++ runtime library
alias long timer_t;
/////////////////////////////////////
//
struct SymPair
{
SymPair* next;
Symbol* sym; // function that is called
uint count; // number of times sym is called
}
/////////////////////////////////////
// A Symbol for each function name.
struct Symbol
{
Symbol* Sl, Sr; // left, right children
SymPair* Sfanin; // list of calling functions
SymPair* Sfanout; // list of called functions
timer_t totaltime; // aggregate time
timer_t functime; // time excluding subfunction calls
ubyte Sflags;
char[] Sident; // name of symbol
}
const ubyte SFvisited = 1; // visited
//////////////////////////////////
// Build a linked list of these.
struct Stack
{
Stack* prev;
Symbol* sym;
timer_t starttime; // time when function was entered
timer_t ohd; // overhead of all the bookkeeping code
timer_t subtime; // time used by all subfunctions
}
__gshared // doesn't work with multithreaded code anyway
{
Symbol* root; // root of symbol table
Stack* stack_freelist;
Stack* trace_tos; // top of stack
int trace_inited; // !=0 if initialized
timer_t trace_ohd;
Symbol** psymbols;
uint nsymbols; // number of symbols
string trace_logfilename = "trace.log";
FILE* fplog;
string trace_deffilename = "trace.def";
FILE* fpdef;
}
////////////////////////////////////////
// Set file name for output.
// A file name of "" means write results to stdout.
// Returns:
// 0 success
// !=0 failure
int trace_setlogfilename(string name)
{
trace_logfilename = name;
return 0;
}
////////////////////////////////////////
// Set file name for output.
// A file name of "" means write results to stdout.
// Returns:
// 0 success
// !=0 failure
int trace_setdeffilename(string name)
{
trace_deffilename = name;
return 0;
}
////////////////////////////////////////
// Output optimal function link order.
static void trace_order(Symbol *s)
{
while (s)
{
trace_place(s,0);
if (s.Sl)
trace_order(s.Sl);
s = s.Sr;
}
}
//////////////////////////////////////////////
//
static Stack* stack_malloc()
{ Stack *s;
if (stack_freelist)
{ s = stack_freelist;
stack_freelist = s.prev;
}
else
s = cast(Stack *)trace_malloc(Stack.sizeof);
return s;
}
//////////////////////////////////////////////
//
static void stack_free(Stack *s)
{
s.prev = stack_freelist;
stack_freelist = s;
}
//////////////////////////////////////
// Qsort() comparison routine for array of pointers to SymPair's.
static int sympair_cmp(in void* e1, in void* e2)
{ SymPair** psp1;
SymPair** psp2;
psp1 = cast(SymPair**)e1;
psp2 = cast(SymPair**)e2;
return (*psp2).count - (*psp1).count;
}
//////////////////////////////////////
// Place symbol s, and then place any fan ins or fan outs with
// counts greater than count.
static void trace_place(Symbol *s, uint count)
{ SymPair* sp;
SymPair** base;
if (!(s.Sflags & SFvisited))
{ size_t num;
uint u;
//printf("\t%.*s\t%u\n", s.Sident, count);
fprintf(fpdef,"\t%.*s\n", s.Sident);
s.Sflags |= SFvisited;
// Compute number of items in array
num = 0;
for (sp = s.Sfanin; sp; sp = sp.next)
num++;
for (sp = s.Sfanout; sp; sp = sp.next)
num++;
if (!num)
return;
// Allocate and fill array
base = cast(SymPair**)trace_malloc(SymPair.sizeof * num);
u = 0;
for (sp = s.Sfanin; sp; sp = sp.next)
base[u++] = sp;
for (sp = s.Sfanout; sp; sp = sp.next)
base[u++] = sp;
// Sort array
qsort(base, num, (SymPair *).sizeof, &sympair_cmp);
//for (u = 0; u < num; u++)
//printf("\t\t%.*s\t%u\n", base[u].sym.Sident, base[u].count);
// Place symbols
for (u = 0; u < num; u++)
{
if (base[u].count >= count)
{ uint u2;
uint c2;
u2 = (u + 1 < num) ? u + 1 : u;
c2 = base[u2].count;
if (c2 < count)
c2 = count;
trace_place(base[u].sym,c2);
}
else
break;
}
// Clean up
trace_free(base);
}
}
/////////////////////////////////////
// Initialize and terminate.
static this()
{
trace_init();
}
static ~this()
{
trace_term();
}
///////////////////////////////////
// Report results.
// Also compute nsymbols.
static void trace_report(Symbol* s)
{ SymPair* sp;
uint count;
//printf("trace_report()\n");
while (s)
{ nsymbols++;
if (s.Sl)
trace_report(s.Sl);
fprintf(fplog,"------------------\n");
count = 0;
for (sp = s.Sfanin; sp; sp = sp.next)
{
fprintf(fplog,"\t%5d\t%.*s\n", sp.count, sp.sym.Sident);
count += sp.count;
}
fprintf(fplog,"%.*s\t%u\t%lld\t%lld\n",s.Sident,count,s.totaltime,s.functime);
for (sp = s.Sfanout; sp; sp = sp.next)
{
fprintf(fplog,"\t%5d\t%.*s\n",sp.count,sp.sym.Sident);
}
s = s.Sr;
}
}
////////////////////////////////////
// Allocate and fill array of symbols.
static void trace_array(Symbol *s)
{
__gshared uint u;
if (!psymbols)
{ u = 0;
psymbols = cast(Symbol **)trace_malloc((Symbol *).sizeof * nsymbols);
}
while (s)
{
psymbols[u++] = s;
trace_array(s.Sl);
s = s.Sr;
}
}
//////////////////////////////////////
// Qsort() comparison routine for array of pointers to Symbol's.
static int symbol_cmp(in void* e1, in void* e2)
{ Symbol** ps1;
Symbol** ps2;
timer_t diff;
ps1 = cast(Symbol **)e1;
ps2 = cast(Symbol **)e2;
diff = (*ps2).functime - (*ps1).functime;
return (diff == 0) ? 0 : ((diff > 0) ? 1 : -1);
}
///////////////////////////////////
// Report function timings
static void trace_times(Symbol* root)
{ uint u;
timer_t freq;
// Sort array
qsort(psymbols, nsymbols, (Symbol *).sizeof, &symbol_cmp);
// Print array
QueryPerformanceFrequency(&freq);
fprintf(fplog,"\n======== Timer Is %lld Ticks/Sec, Times are in Microsecs ========\n\n",freq);
fprintf(fplog," Num Tree Func Per\n");
fprintf(fplog," Calls Time Time Call\n\n");
for (u = 0; u < nsymbols; u++)
{ Symbol* s = psymbols[u];
timer_t tl,tr;
timer_t fl,fr;
timer_t pl,pr;
timer_t percall;
SymPair* sp;
uint calls;
char[] id;
version (Windows)
{
char* p = (s.Sident ~ '\0').ptr;
p = unmangle_ident(p);
if (p)
id = p[0 .. strlen(p)];
}
if (!id)
id = s.Sident;
calls = 0;
for (sp = s.Sfanin; sp; sp = sp.next)
calls += sp.count;
if (calls == 0)
calls = 1;
version (all)
{
tl = (s.totaltime * 1000000) / freq;
fl = (s.functime * 1000000) / freq;
percall = s.functime / calls;
pl = (s.functime * 1000000) / calls / freq;
fprintf(fplog,"%7d%12lld%12lld%12lld %.*s\n",
calls,tl,fl,pl,id);
}
else
{
tl = s.totaltime / freq;
tr = ((s.totaltime - tl * freq) * 10000000) / freq;
fl = s.functime / freq;
fr = ((s.functime - fl * freq) * 10000000) / freq;
percall = s.functime / calls;
pl = percall / freq;
pr = ((percall - pl * freq) * 10000000) / freq;
fprintf(fplog,"%7d\t%3lld.%07lld\t%3lld.%07lld\t%3lld.%07lld\t%.*s\n",
calls,tl,tr,fl,fr,pl,pr,id);
}
if (id !is s.Sident)
free(id.ptr);
}
}
///////////////////////////////////
// Initialize.
static void trace_init()
{
if (!trace_inited)
{
trace_inited = 1;
{ // See if we can determine the overhead.
uint u;
timer_t starttime;
timer_t endtime;
Stack *st;
st = trace_tos;
trace_tos = null;
QueryPerformanceCounter(&starttime);
for (u = 0; u < 100; u++)
{
asm
{
call _trace_pro_n ;
db 0 ;
call _trace_epi_n ;
}
}
QueryPerformanceCounter(&endtime);
trace_ohd = (endtime - starttime) / u;
//printf("trace_ohd = %lld\n",trace_ohd);
if (trace_ohd > 0)
trace_ohd--; // round down
trace_tos = st;
}
}
}
/////////////////////////////////
// Terminate.
void trace_term()
{
//printf("trace_term()\n");
if (trace_inited == 1)
{ Stack *n;
trace_inited = 2;
// Free remainder of the stack
while (trace_tos)
{
n = trace_tos.prev;
stack_free(trace_tos);
trace_tos = n;
}
while (stack_freelist)
{
n = stack_freelist.prev;
stack_free(stack_freelist);
stack_freelist = n;
}
// Merge in data from any existing file
trace_merge();
// Report results
fplog = fopen(trace_logfilename.ptr, "w");
if (fplog)
{ nsymbols = 0;
trace_report(root);
trace_array(root);
trace_times(root);
fclose(fplog);
}
// Output function link order
fpdef = fopen(trace_deffilename.ptr,"w");
if (fpdef)
{ fprintf(fpdef,"\nFUNCTIONS\n");
trace_order(root);
fclose(fpdef);
}
trace_free(psymbols);
psymbols = null;
}
}
/////////////////////////////////
// Our storage allocator.
static void *trace_malloc(size_t nbytes)
{ void *p;
p = malloc(nbytes);
if (!p)
exit(EXIT_FAILURE);
return p;
}
static void trace_free(void *p)
{
free(p);
}
//////////////////////////////////////////////
//
static Symbol* trace_addsym(char[] id)
{
Symbol** parent;
Symbol* rover;
Symbol* s;
int cmp;
char c;
//printf("trace_addsym('%s',%d)\n",p,len);
parent = &root;
rover = *parent;
while (rover !is null) // while we haven't run out of tree
{
cmp = dstrcmp(id, rover.Sident);
if (cmp == 0)
{
return rover;
}
parent = (cmp < 0) ? /* if we go down left side */
&(rover.Sl) : /* then get left child */
&(rover.Sr); /* else get right child */
rover = *parent; /* get child */
}
/* not in table, so insert into table */
s = cast(Symbol *)trace_malloc(Symbol.sizeof);
memset(s,0,Symbol.sizeof);
s.Sident = id;
*parent = s; // link new symbol into tree
return s;
}
/***********************************
* Add symbol s with count to SymPair list.
*/
static void trace_sympair_add(SymPair** psp, Symbol* s, uint count)
{ SymPair* sp;
for (; 1; psp = &sp.next)
{
sp = *psp;
if (!sp)
{
sp = cast(SymPair *)trace_malloc(SymPair.sizeof);
sp.sym = s;
sp.count = 0;
sp.next = null;
*psp = sp;
break;
}
else if (sp.sym == s)
{
break;
}
}
sp.count += count;
}
//////////////////////////////////////////////
//
static void trace_pro(char[] id)
{
Stack* n;
Symbol* s;
timer_t starttime;
timer_t t;
QueryPerformanceCounter(&starttime);
if (id.length == 0)
return;
if (!trace_inited)
trace_init(); // initialize package
n = stack_malloc();
n.prev = trace_tos;
trace_tos = n;
s = trace_addsym(id);
trace_tos.sym = s;
if (trace_tos.prev)
{
Symbol* prev;
int i;
// Accumulate Sfanout and Sfanin
prev = trace_tos.prev.sym;
trace_sympair_add(&prev.Sfanout,s,1);
trace_sympair_add(&s.Sfanin,prev,1);
}
QueryPerformanceCounter(&t);
trace_tos.starttime = starttime;
trace_tos.ohd = trace_ohd + t - starttime;
trace_tos.subtime = 0;
//printf("trace_tos.ohd=%lld, trace_ohd=%lld + t=%lld - starttime=%lld\n",
// trace_tos.ohd,trace_ohd,t,starttime);
}
/////////////////////////////////////////
//
static void trace_epi()
{ Stack* n;
timer_t endtime;
timer_t t;
timer_t ohd;
//printf("trace_epi()\n");
if (trace_tos)
{
timer_t starttime;
timer_t totaltime;
QueryPerformanceCounter(&endtime);
starttime = trace_tos.starttime;
totaltime = endtime - starttime - trace_tos.ohd;
if (totaltime < 0)
{ //printf("endtime=%lld - starttime=%lld - trace_tos.ohd=%lld < 0\n",
// endtime,starttime,trace_tos.ohd);
totaltime = 0; // round off error, just make it 0
}
// totaltime is time spent in this function + all time spent in
// subfunctions - bookkeeping overhead.
trace_tos.sym.totaltime += totaltime;
//if (totaltime < trace_tos.subtime)
//printf("totaltime=%lld < trace_tos.subtime=%lld\n",totaltime,trace_tos.subtime);
trace_tos.sym.functime += totaltime - trace_tos.subtime;
ohd = trace_tos.ohd;
n = trace_tos.prev;
stack_free(trace_tos);
trace_tos = n;
if (n)
{ QueryPerformanceCounter(&t);
n.ohd += ohd + t - endtime;
n.subtime += totaltime;
//printf("n.ohd = %lld\n",n.ohd);
}
}
}
////////////////////////// FILE INTERFACE /////////////////////////
/////////////////////////////////////
// Read line from file fp.
// Returns:
// trace_malloc'd line buffer
// null if end of file
static char* trace_readline(FILE* fp)
{ int c;
int dim;
int i;
char *buf;
//printf("trace_readline(%p)\n", fp);
i = 0;
dim = 0;
buf = null;
while (1)
{
if (i == dim)
{ char *p;
dim += 80;
p = cast(char *)trace_malloc(dim);
memcpy(p,buf,i);
trace_free(buf);
buf = p;
}
c = fgetc(fp);
switch (c)
{
case EOF:
if (i == 0)
{ trace_free(buf);
return null;
}
case '\n':
goto L1;
default:
break;
}
buf[i] = cast(char)c;
i++;
}
L1:
buf[i] = 0;
//printf("line '%s'\n",buf);
return buf;
}
//////////////////////////////////////
// Skip space
static char *skipspace(char *p)
{
while (isspace(*p))
p++;
return p;
}
////////////////////////////////////////////////////////
// Merge in profiling data from existing file.
static void trace_merge()
{ FILE *fp;
char *buf;
char *p;
uint count;
Symbol *s;
SymPair *sfanin;
SymPair **psp;
if (trace_logfilename && (fp = fopen(trace_logfilename.ptr,"r")) !is null)
{
buf = null;
sfanin = null;
psp = &sfanin;
while (1)
{
trace_free(buf);
buf = trace_readline(fp);
if (!buf)
break;
switch (*buf)
{
case '=': // ignore rest of file
trace_free(buf);
goto L1;
case ' ':
case '\t': // fan in or fan out line
count = strtoul(buf,&p,10);
if (p == buf) // if invalid conversion
continue;
p = skipspace(p);
if (!*p)
continue;
s = trace_addsym(p[0 .. strlen(p)]);
trace_sympair_add(psp,s,count);
break;
default:
if (!isalpha(*buf))
{
if (!sfanin)
psp = &sfanin;
continue; // regard unrecognized line as separator
}
case '?':
case '_':
case '$':
case '@':
p = buf;
while (isgraph(*p))
p++;
*p = 0;
//printf("trace_addsym('%s')\n",buf);
s = trace_addsym(buf[0 .. strlen(buf)]);
if (s.Sfanin)
{ SymPair *sp;
for (; sfanin; sfanin = sp)
{
trace_sympair_add(&s.Sfanin,sfanin.sym,sfanin.count);
sp = sfanin.next;
trace_free(sfanin);
}
}
else
{ s.Sfanin = sfanin;
}
sfanin = null;
psp = &s.Sfanout;
{ timer_t t;
p++;
count = strtoul(p,&p,10);
t = cast(long)strtoull(p,&p,10);
s.totaltime += t;
t = cast(long)strtoull(p,&p,10);
s.functime += t;
}
break;
}
}
L1:
fclose(fp);
}
}
////////////////////////// COMPILER INTERFACE /////////////////////
/////////////////////////////////////////////
// Function called by trace code in function prolog.
void _trace_pro_n()
{
/* Length of string is either:
* db length
* ascii string
* or:
* db 0x0FF
* db 0
* dw length
* ascii string
*/
version (OSX)
{ // 16 byte align stack
asm
{ naked ;
pushad ;
mov ECX,8*4[ESP] ;
xor EAX,EAX ;
mov AL,[ECX] ;
cmp AL,0xFF ;
jne L1 ;
cmp byte ptr 1[ECX],0 ;
jne L1 ;
mov AX,2[ECX] ;
add 8*4[ESP],3 ;
add ECX,3 ;
L1: inc EAX ;
inc ECX ;
add 8*4[ESP],EAX ;
dec EAX ;
sub ESP,4 ;
push ECX ;
push EAX ;
call trace_pro ;
add ESP,12 ;
popad ;
ret ;
}
}
else
{
asm
{ naked ;
pushad ;
mov ECX,8*4[ESP] ;
xor EAX,EAX ;
mov AL,[ECX] ;
cmp AL,0xFF ;
jne L1 ;
cmp byte ptr 1[ECX],0 ;
jne L1 ;
mov AX,2[ECX] ;
add 8*4[ESP],3 ;
add ECX,3 ;
L1: inc EAX ;
inc ECX ;
add 8*4[ESP],EAX ;
dec EAX ;
push ECX ;
push EAX ;
call trace_pro ;
add ESP,8 ;
popad ;
ret ;
}
}
}
/////////////////////////////////////////////
// Function called by trace code in function epilog.
void _trace_epi_n()
{
version (OSX)
{ // 16 byte align stack
asm
{ naked ;
pushad ;
sub ESP,12 ;
}
trace_epi();
asm
{
add ESP,12 ;
popad ;
ret ;
}
}
else
{
asm
{ naked ;
pushad ;
}
trace_epi();
asm
{
popad ;
ret ;
}
}
}
version (Windows)
{
extern (Windows)
{
export int QueryPerformanceCounter(timer_t *);
export int QueryPerformanceFrequency(timer_t *);
}
}
else version (X86)
{
extern (D)
{
void QueryPerformanceCounter(timer_t* ctr)
{
asm
{ naked ;
mov ECX,EAX ;
rdtsc ;
mov [ECX],EAX ;
mov 4[ECX],EDX ;
ret ;
}
}
void QueryPerformanceFrequency(timer_t* freq)
{
*freq = 3579545;
}
}
}
else
{
static assert(0);
}

View File

@@ -0,0 +1,107 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
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);
}
}

View File

@@ -0,0 +1,94 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_Acdouble;
private import rt.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);
}
}

View File

@@ -0,0 +1,92 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_Acfloat;
private import rt.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);
}
}

View File

@@ -0,0 +1,95 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_Acreal;
private import rt.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);
}
}

View File

@@ -0,0 +1,104 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_Adouble;
private import rt.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);
}
}

View File

@@ -0,0 +1,103 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_Afloat;
private import rt.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);
}
}

View File

@@ -0,0 +1,228 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_Ag;
private import rt.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);
}
}
// string
class TypeInfo_Aya : TypeInfo_Aa
{
override string toString() { return "immutable(char)[]"; }
override TypeInfo next()
{
return typeid(immutable(char));
}
}

View File

@@ -0,0 +1,140 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
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);
}
}

View File

@@ -0,0 +1,120 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
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);
}
}

View File

@@ -0,0 +1,105 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_Areal;
private import rt.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);
}
}

View File

@@ -0,0 +1,143 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
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);
}
}

View File

@@ -0,0 +1,63 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
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;
}
}

View File

@@ -0,0 +1,49 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_byte;
// 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;
}
}

View File

@@ -0,0 +1,77 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_cdouble;
// 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 immutable cdouble r;
return (cast(cdouble *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,76 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_cfloat;
// 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 immutable cfloat r;
return (cast(cfloat *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,55 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_char;
// 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 immutable char c;
return (cast(char *)&c)[0 .. 1];
}
}

View File

@@ -0,0 +1,78 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_creal;
// 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 immutable creal r;
return (cast(creal *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,55 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_dchar;
// 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 immutable dchar c;
return (cast(dchar *)&c)[0 .. 1];
}
}

View File

@@ -0,0 +1,50 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_delegate;
// 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;
}
}

View File

@@ -0,0 +1,75 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_double;
// 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 immutable double r;
return (cast(double *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,75 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_float;
// 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 immutable float r;
return (cast(float *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,22 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_idouble;
// idouble
private import rt.typeinfo.ti_double;
class TypeInfo_p : TypeInfo_d
{
override string toString() { return "idouble"; }
}

View File

@@ -0,0 +1,22 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_ifloat;
// ifloat
private import rt.typeinfo.ti_float;
class TypeInfo_o : TypeInfo_f
{
override string toString() { return "ifloat"; }
}

View File

@@ -0,0 +1,53 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_int;
// 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;
}
}

View File

@@ -0,0 +1,22 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_ireal;
// ireal
private import rt.typeinfo.ti_real;
class TypeInfo_j : TypeInfo_e
{
override string toString() { return "ireal"; }
}

View File

@@ -0,0 +1,53 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_long;
// 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;
}
}

View File

@@ -0,0 +1,57 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_ptr;
// pointer
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;
}
}

View File

@@ -0,0 +1,75 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_real;
// 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 immutable real r;
return (cast(real *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,49 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_short;
// 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;
}
}

View File

@@ -0,0 +1,54 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_ubyte;
// 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"; }
}

View File

@@ -0,0 +1,53 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_uint;
// 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;
}
}

View File

@@ -0,0 +1,53 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_ulong;
// 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;
}
}

View File

@@ -0,0 +1,49 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_ushort;
// 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;
}
}

View File

@@ -0,0 +1,54 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_void;
// 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;
}
}

View File

@@ -0,0 +1,55 @@
/**
* TypeInfo support code.
*
* Copyright: Copyright Digital Mars 2004 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Walter Bright
*
* Copyright Digital Mars 2004 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.typeinfo.ti_wchar;
// 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 immutable wchar c;
return (cast(wchar *)&c)[0 .. 1];
}
}

View File

@@ -0,0 +1,54 @@
/**
* The console module contains some simple routines for console output.
*
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Sean Kelly
*
* Copyright Sean Kelly 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.util.console;
private
{
version (Windows)
{
import core.sys.windows.windows;
}
else version( Posix )
{
import core.sys.posix.unistd;
}
import rt.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 ) );
}
}
__gshared Console console;

View File

@@ -0,0 +1,719 @@
/**
* Identify the characteristics of the host CPU, providing information
* about cache sizes and assembly optimisation hints.
*
* Some of this information was extremely difficult to track down. Some of the
* documents below were found only in cached versions stored by search engines!
* This code relies on information found in:
* - "Intel(R) 64 and IA-32 Architectures Software Developers Manual,
* Volume 2A: Instruction Set Reference, A-M" (2007).
* - "AMD CPUID Specification", Advanced Micro Devices, Rev 2.28 (2008).
* - "AMD Processor Recognition Application Note For Processors Prior to AMD
* Family 0Fh Processors", Advanced Micro Devices, Rev 3.13 (2005).
* - "AMD Geode(TM) GX Processors Data Book",
* Advanced Micro Devices, Publication ID 31505E, (2005).
* - "AMD K6 Processor Code Optimisation", Advanced Micro Devices, Rev D (2000).
* - "Application note 106: Software Customization for the 6x86 Family",
* Cyrix Corporation, Rev 1.5 (1998)
* - http://ftp.intron.ac/pub/document/cpu/cpuid.htm
* - "Geode(TM) GX1 Processor Series Low Power Integrated X86 Solution",
* National Semiconductor, (2002)
* - "The VIA Isaiah Architecture", G. Glenn Henry, Centaur Technology, Inc (2008).
* - http://www.sandpile.org/ia32/cpuid.htm
* - http://grafi.ii.pw.edu.pl/gbm/x86/cpuid.html
* - "What every programmer should know about memory",
* Ulrich Depper, Red Hat, Inc., (2007).
*
* Bugs: Currently only works on x86 and Itanium CPUs.
* Many processors have bugs in their microcode for the CPUID instruction,
* so sometimes the cache information may be incorrect.
*
* Copyright: Copyright Don Clugston 2007 - 2009.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
* Authors: Don Clugston, Tomas Lindquist Olsen &lt;tomas@famolsen.dk&gt;
*
* Copyright Don Clugston 2007 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.util.cpuid;
// If optimizing for a particular processor, it is generally better
// to identify based on features rather than model. NOTE: Normally
// it's only worthwhile to optimise for the latest Intel and AMD CPU,
// with a backup for other CPUs.
// Pentium -- preferPentium1()
// PMMX -- + mmx()
// PPro -- default
// PII -- + mmx()
// PIII -- + mmx() + sse()
// PentiumM -- + mmx() + sse() + sse2()
// Pentium4 -- preferPentium4()
// PentiumD -- + isX86_64()
// Core2 -- default + isX86_64()
// AMD K5 -- preferPentium1()
// AMD K6 -- + mmx()
// AMD K6-II -- + mmx() + 3dnow()
// AMD K7 -- preferAthlon()
// AMD K8 -- + sse2()
// AMD K10 -- + isX86_64()
// Cyrix 6x86 -- preferPentium1()
// 6x86MX -- + mmx()
public:
/// Cache size and behaviour
struct CacheInfo
{
/// Size of the cache, in kilobytes, per CPU.
/// For L1 unified (data + code) caches, this size is half the physical size.
/// (we don't halve it for larger sizes, since normally
/// data size is much greater than code size for critical loops).
uint size;
/// Number of ways of associativity, eg:
/// 1 = direct mapped
/// 2 = 2-way set associative
/// 3 = 3-way set associative
/// ubyte.max = fully associative
ubyte associativity;
/// Number of bytes read into the cache when a cache miss occurs.
uint lineSize;
}
public:
/// Returns vendor string, for display purposes only.
/// Do NOT use this to determine features!
/// Note that some CPUs have programmable vendorIDs.
char[] vendor() {return vendorID;}
/// Returns processor string, for display purposes only
char[] processor() {return processorName;}
/// The data caches. If there are fewer than 5 physical caches levels,
/// the remaining levels are set to uint.max (== entire memory space)
__gshared CacheInfo[5] datacache;
/// Does it have an x87 FPU on-chip?
bool x87onChip() {return (features&FPU_BIT)!=0;}
/// Is MMX supported?
bool mmx() {return (features&MMX_BIT)!=0;}
/// Is SSE supported?
bool sse() {return (features&SSE_BIT)!=0;}
/// Is SSE2 supported?
bool sse2() {return (features&SSE2_BIT)!=0;}
/// Is SSE3 supported?
bool sse3() {return (miscfeatures&SSE3_BIT)!=0;}
/// Is SSSE3 supported?
bool ssse3() {return (miscfeatures&SSSE3_BIT)!=0;}
/// Is SSE4.1 supported?
bool sse41() {return (miscfeatures&SSE41_BIT)!=0;}
/// Is SSE4.2 supported?
bool sse42() {return (miscfeatures&SSE42_BIT)!=0;}
/// Is SSE4a supported?
bool sse4a() {return (amdmiscfeatures&SSE4A_BIT)!=0;}
/// Is SSE5 supported?
bool sse5() {return (amdmiscfeatures&SSE5_BIT)!=0;}
/// Is AMD 3DNOW supported?
bool amd3dnow() {return (amdfeatures&AMD_3DNOW_BIT)!=0;}
/// Is AMD 3DNOW Ext supported?
bool amd3dnowExt() {return (amdfeatures&AMD_3DNOW_EXT_BIT)!=0;}
/// Are AMD extensions to MMX supported?
bool amdMmx() {return (amdfeatures&AMD_MMX_BIT)!=0;}
/// Is fxsave/fxrstor supported?
bool hasFxsr() {return (features&FXSR_BIT)!=0;}
/// Is cmov supported?
bool hasCmov() {return (features&CMOV_BIT)!=0;}
/// Is rdtsc supported?
bool hasRdtsc() {return (features&TIMESTAMP_BIT)!=0;}
/// Is cmpxchg8b supported?
bool hasCmpxchg8b() {return (features&CMPXCHG8B_BIT)!=0;}
/// Is cmpxchg8b supported?
bool hasCmpxchg16b() {return (miscfeatures&CMPXCHG16B_BIT)!=0;}
/// Is 3DNow prefetch supported?
bool has3dnowPrefetch()
{return (amdmiscfeatures&AMD_3DNOW_PREFETCH_BIT)!=0;}
/// Are LAHF and SAHF supported in 64-bit mode?
bool hasLahfSahf() {return (amdmiscfeatures&LAHFSAHF_BIT)!=0;}
/// Is POPCNT supported?
bool hasPopcnt() {return (miscfeatures&POPCNT_BIT)!=0;}
/// Is LZCNT supported?
bool hasLzcnt() {return (amdmiscfeatures&LZCNT_BIT)!=0;}
/// Is this an Intel64 or AMD 64?
bool isX86_64() {return (amdfeatures&AMD64_BIT)!=0;}
/// Is this an IA64 (Itanium) processor?
bool isItanium() { return (features&IA64_BIT)!=0; }
/// Is hyperthreading supported?
bool hyperThreading() { return maxThreads>maxCores; }
/// Returns number of threads per CPU
uint threadsPerCPU() {return maxThreads;}
/// Returns number of cores in CPU
uint coresPerCPU() {return maxCores;}
/// Optimisation hints for assembly code.
/// For forward compatibility, the CPU is compared against different
/// microarchitectures. For 32-bit X86, comparisons are made against
/// the Intel PPro/PII/PIII/PM family.
///
/// The major 32-bit x86 microarchitecture 'dynasties' have been:
/// (1) Intel P6 (PentiumPro, PII, PIII, PM, Core, Core2).
/// (2) AMD Athlon (K7, K8, K10).
/// (3) Intel NetBurst (Pentium 4, Pentium D).
/// (4) In-order Pentium (Pentium1, PMMX)
/// Other early CPUs (Nx586, AMD K5, K6, Centaur C3, Transmeta,
/// Cyrix, Rise) were mostly in-order.
/// Some new processors do not fit into the existing categories:
/// Intel Atom 230/330 (family 6, model 0x1C) is an in-order core.
/// Centaur Isiah = VIA Nano (family 6, model F) is an out-of-order core.
///
/// Within each dynasty, the optimisation techniques are largely
/// identical (eg, use instruction pairing for group 4). Major
/// instruction set improvements occur within each group.
/// Does this CPU perform better on AMD K7 code than PentiumPro..Core2 code?
bool preferAthlon() { return probablyAMD && family >=6; }
/// Does this CPU perform better on Pentium4 code than PentiumPro..Core2 code?
bool preferPentium4() { return probablyIntel && family == 0xF; }
/// Does this CPU perform better on Pentium I code than Pentium Pro code?
bool preferPentium1() { return family < 6 || (family==6 && model < 0xF && !probablyIntel); }
__gshared:
public:
/// Processor type (vendor-dependent).
/// This should be visible ONLY for display purposes.
uint stepping, model, family;
uint numCacheLevels = 1;
private:
bool probablyIntel; // true = _probably_ an Intel processor, might be faking
bool probablyAMD; // true = _probably_ an AMD processor
char [12] vendorID;
char [] processorName;
char [48] processorNameBuffer;
uint features = 0; // mmx, sse, sse2, hyperthreading, etc
uint miscfeatures = 0; // sse3, etc.
uint amdfeatures = 0; // 3DNow!, mmxext, etc
uint amdmiscfeatures = 0; // sse4a, sse5, svm, etc
uint maxCores = 1;
uint maxThreads = 1;
// Note that this may indicate multi-core rather than hyperthreading.
bool hyperThreadingBit() { return (features&HTT_BIT)!=0;}
// feature flags CPUID1_EDX
enum : uint
{
FPU_BIT = 1,
TIMESTAMP_BIT = 1<<4, // rdtsc
MDSR_BIT = 1<<5, // RDMSR/WRMSR
CMPXCHG8B_BIT = 1<<8,
CMOV_BIT = 1<<15,
MMX_BIT = 1<<23,
FXSR_BIT = 1<<24,
SSE_BIT = 1<<25,
SSE2_BIT = 1<<26,
HTT_BIT = 1<<28,
IA64_BIT = 1<<30
}
// feature flags misc CPUID1_ECX
enum : uint
{
SSE3_BIT = 1,
PCLMULQDQ_BIT = 1<<1, // from AVX
MWAIT_BIT = 1<<3,
SSSE3_BIT = 1<<9,
FMA_BIT = 1<<12, // from AVX
CMPXCHG16B_BIT = 1<<13,
SSE41_BIT = 1<<19,
SSE42_BIT = 1<<20,
POPCNT_BIT = 1<<23,
AES_BIT = 1<<25, // AES instructions from AVX
OSXSAVE_BIT = 1<<27, // Used for AVX
AVX_BIT = 1<<28
}
/+
version(X86_64) {
bool hasAVXinHardware() {
// This only indicates hardware support, not OS support.
return (miscfeatures&AVX_BIT) && (miscfeatures&OSXSAVE_BIT);
}
// Is AVX supported (in both hardware & OS)?
bool Avx() {
if (!hasAVXinHardware()) return false;
// Check for OS support
uint xfeatures;
asm {mov ECX, 0; xgetbv; mov xfeatures, EAX; }
return (xfeatures&0x6)==6;
}
bool hasAvxFma() {
if (!AVX()) return false;
return (features&FMA_BIT)!=0;
}
}
+/
// AMD feature flags CPUID80000001_EDX
enum : uint
{
AMD_MMX_BIT = 1<<22,
// FXR_OR_CYRIXMMX_BIT = 1<<24, // Cyrix/NS: 6x86MMX instructions.
FFXSR_BIT = 1<<25,
PAGE1GB_BIT = 1<<26, // support for 1GB pages
RDTSCP_BIT = 1<<27,
AMD64_BIT = 1<<29,
AMD_3DNOW_EXT_BIT = 1<<30,
AMD_3DNOW_BIT = 1<<31
}
// AMD misc feature flags CPUID80000001_ECX
enum : uint
{
LAHFSAHF_BIT = 1,
LZCNT_BIT = 1<<5,
SSE4A_BIT = 1<<6,
AMD_3DNOW_PREFETCH_BIT = 1<<8,
SSE5_BIT = 1<<11
}
version(GNU){
// GDC is a filthy liar. It can't actually do inline asm.
} else version(D_InlineAsm_X86) {
version = Really_D_InlineAsm_X86;
}
version(Really_D_InlineAsm_X86) {
// Note that this code will also work for Itanium in x86 mode.
shared uint max_cpuid, max_extended_cpuid;
// CPUID2: "cache and tlb information"
void getcacheinfoCPUID2()
{
// We are only interested in the data caches
void decipherCpuid2(ubyte x) {
if (x==0) return;
// Values from http://www.sandpile.org/ia32/cpuid.htm.
// Includes Itanium and non-Intel CPUs.
//
immutable ubyte [47] ids = [
0x0A, 0x0C, 0x2C, 0x60, 0x0E, 0x66, 0x67, 0x68,
// level 2 cache
0x41, 0x42, 0x43, 0x44, 0x45, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7F,
0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x49, 0x4E,
0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x48, 0x80, 0x81,
// level 3 cache
0x22, 0x23, 0x25, 0x29, 0x46, 0x47, 0x4A, 0x4B, 0x4C, 0x4D
];
immutable uint [47] sizes = [
8, 16, 32, 16, 24, 8, 16, 32,
128, 256, 512, 1024, 2048, 1024, 128, 256, 512, 1024, 2048, 512,
256, 512, 1024, 2048, 512, 1024, 4096, 6*1024,
128, 192, 128, 256, 384, 512, 3072, 512, 128,
512, 1024, 2048, 4096, 4096, 8192, 6*1024, 8192, 12*1024, 16*1024
];
// CPUBUG: Pentium M reports 0x2C but tests show it is only 4-way associative
immutable ubyte [47] ways = [
2, 4, 8, 8, 6, 4, 4, 4,
4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 2,
8, 8, 8, 8, 4, 8, 16, 24,
4, 6, 2, 4, 6, 4, 12, 8, 8,
4, 8, 8, 8, 4, 8, 12, 16, 12, 16
];
enum { FIRSTDATA2 = 8, FIRSTDATA3 = 28+9 }
for (int i=0; i< ids.length; ++i) {
if (x==ids[i]) {
int level = i< FIRSTDATA2 ? 0: i<FIRSTDATA3 ? 1 : 2;
if (x==0x49 && family==0xF && model==0x6) level=2;
datacache[level].size=sizes[i];
datacache[level].associativity=ways[i];
if (level == 3 || x==0x2C || (x>=0x48 && x<=0x80)
|| x==0x86 || x==0x87
|| (x>=0x66 && x<=0x68) || (x>=0x39 && x<=0x3E)){
datacache[level].lineSize = 64;
} else datacache[level].lineSize = 32;
}
}
}
uint[4] a;
bool firstTime = true;
// On a multi-core system, this could theoretically fail, but it's only used
// for old single-core CPUs.
uint numinfos = 1;
do {
asm {
mov EAX, 2;
cpuid;
mov a, EAX;
mov a+4, EBX;
mov a+8, ECX;
mov a+12, EDX;
}
if (firstTime) {
if (a[0]==0x0000_7001 && a[3]==0x80 && a[1]==0 && a[2]==0) {
// Cyrix MediaGX MMXEnhanced returns: EAX= 00007001, EDX=00000080.
// These are NOT standard Intel values
// (TLB = 32 entry, 4 way associative, 4K pages)
// (L1 cache = 16K, 4way, linesize16)
datacache[0].size=8;
datacache[0].associativity=4;
datacache[0].lineSize=16;
return;
}
// lsb of a is how many times to loop.
numinfos = a[0] & 0xFF;
// and otherwise it should be ignored
a[0] &= 0xFFFF_FF00;
firstTime = false;
}
for (int c=0; c<4;++c) {
// high bit set == no info.
if (a[c] & 0x8000_0000) continue;
decipherCpuid2(cast(ubyte)(a[c] & 0xFF));
decipherCpuid2(cast(ubyte)((a[c]>>8) & 0xFF));
decipherCpuid2(cast(ubyte)((a[c]>>16) & 0xFF));
decipherCpuid2(cast(ubyte)((a[c]>>24) & 0xFF));
}
} while (--numinfos);
}
// CPUID4: "Deterministic cache parameters" leaf
void getcacheinfoCPUID4()
{
int cachenum = 0;
for(;;) {
uint a, b, number_of_sets;
asm {
mov EAX, 4;
mov ECX, cachenum;
cpuid;
mov a, EAX;
mov b, EBX;
mov number_of_sets, ECX;
}
++cachenum;
if ((a&0x1F)==0) break; // no more caches
uint numthreads = ((a>>14) & 0xFFF) + 1;
uint numcores = ((a>>26) & 0x3F) + 1;
if (numcores > maxCores) maxCores = numcores;
if ((a&0x1F)!=1 && ((a&0x1F)!=3)) continue; // we only want data & unified caches
++number_of_sets;
ubyte level = cast(ubyte)(((a>>5)&7)-1);
if (level > datacache.length) continue; // ignore deep caches
datacache[level].associativity = a & 0x200 ? ubyte.max :cast(ubyte)((b>>22)+1);
datacache[level].lineSize = (b & 0xFFF)+ 1; // system coherency line size
uint line_partitions = ((b >> 12)& 0x3FF) + 1;
// Size = number of sets * associativity * cachelinesize * linepartitions
// and must convert to Kb, also dividing by the number of hyperthreads using this cache.
ulong sz = (datacache[level].associativity< ubyte.max)? number_of_sets *
datacache[level].associativity : number_of_sets;
datacache[level].size = cast(uint)(
(sz * datacache[level].lineSize * line_partitions ) / (numthreads *1024));
if (level == 0 && (a&0xF)==3) {
// Halve the size for unified L1 caches
datacache[level].size/=2;
}
}
}
// CPUID8000_0005 & 6
void getAMDcacheinfo()
{
uint c5, c6, d6;
asm {
mov EAX, 0x8000_0005; // L1 cache
cpuid;
// EAX has L1_TLB_4M.
// EBX has L1_TLB_4K
// EDX has L1 instruction cache
mov c5, ECX;
}
datacache[0].size = ( (c5>>24) & 0xFF);
datacache[0].associativity = cast(ubyte)( (c5 >> 16) & 0xFF);
datacache[0].lineSize = c5 & 0xFF;
if (max_extended_cpuid >= 0x8000_0006) {
// AMD K6-III or K6-2+ or later.
ubyte numcores = 1;
if (max_extended_cpuid >=0x8000_0008) {
asm {
mov EAX, 0x8000_0008;
cpuid;
mov numcores, CL;
}
++numcores;
if (numcores>maxCores) maxCores = numcores;
}
asm {
mov EAX, 0x8000_0006; // L2/L3 cache
cpuid;
mov c6, ECX; // L2 cache info
mov d6, EDX; // L3 cache info
}
immutable ubyte [] assocmap = [ 0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 0xFF ];
datacache[1].size = (c6>>16) & 0xFFFF;
datacache[1].associativity = assocmap[(c6>>12)&0xF];
datacache[1].lineSize = c6 & 0xFF;
// The L3 cache value is TOTAL, not per core.
datacache[2].size = ((d6>>18)*512)/numcores; // could be up to 2 * this, -1.
datacache[2].associativity = assocmap[(d6>>12)&0xF];
datacache[2].lineSize = d6 & 0xFF;
}
}
void cpuidX86()
{
char * venptr = vendorID.ptr;
asm {
mov EAX, 0;
cpuid;
mov max_cpuid, EAX;
mov EAX, venptr;
mov [EAX], EBX;
mov [EAX + 4], EDX;
mov [EAX + 8], ECX;
mov EAX, 0x8000_0000;
cpuid;
mov max_extended_cpuid, EAX;
}
probablyIntel = vendorID == "GenuineIntel";
probablyAMD = vendorID == "AuthenticAMD";
uint a, b, c, d;
uint apic = 0; // brand index, apic id
asm {
mov EAX, 1; // model, stepping
cpuid;
mov a, EAX;
mov apic, EBX;
mov miscfeatures, ECX;
mov features, EDX;
}
amdfeatures = 0;
amdmiscfeatures = 0;
if (max_extended_cpuid >= 0x8000_0001) {
asm {
mov EAX, 0x8000_0001;
cpuid;
mov amdmiscfeatures, ECX;
mov amdfeatures, EDX;
}
}
// Try to detect fraudulent vendorIDs
if (amd3dnow) probablyIntel = false;
stepping = a & 0xF;
uint fbase = (a >> 8) & 0xF;
uint mbase = (a >> 4) & 0xF;
family = ((fbase == 0xF) || (fbase == 0)) ? fbase + (a >> 20) & 0xFF : fbase;
model = ((fbase == 0xF) || (fbase == 6 && probablyIntel) ) ?
mbase + ((a >> 12) & 0xF0) : mbase;
if (!probablyIntel && max_extended_cpuid >= 0x8000_0008) {
// determine max number of cores for AMD
asm {
mov EAX, 0x8000_0008;
cpuid;
mov c, ECX;
}
uint apicsize = (c>>12) & 0xF;
if (apicsize == 0) {
// use legacy method
if (hyperThreadingBit) maxCores = c & 0xFF;
else maxCores = 1;
} else {
// maxcores = 2^ apicsize
maxCores = 1;
while (apicsize) { maxCores<<=1; --apicsize; }
}
}
if (max_extended_cpuid >= 0x8000_0004) {
char *procptr = processorNameBuffer.ptr;
asm {
push ESI;
mov ESI, procptr;
mov EAX, 0x8000_0002;
cpuid;
mov [ESI], EAX;
mov [ESI+4], EBX;
mov [ESI+8], ECX;
mov [ESI+12], EDX;
mov EAX, 0x8000_0003;
cpuid;
mov [ESI+16], EAX;
mov [ESI+20], EBX;
mov [ESI+24], ECX;
mov [ESI+28], EDX;
mov EAX, 0x8000_0004;
cpuid;
mov [ESI+32], EAX;
mov [ESI+36], EBX;
mov [ESI+40], ECX;
mov [ESI+44], EDX;
pop ESI;
}
// Intel P4 and PM pad at front with spaces.
// Other CPUs pad at end with nulls.
int start = 0, end = 0;
while (processorNameBuffer[start] == ' ') { ++start; }
while (processorNameBuffer[$-end-1] == 0) { ++end; }
processorName = processorNameBuffer[start..$-end];
} else {
processorName[] = "Unknown CPU";
}
// Determine cache sizes
// Intel docs specify that they return 0 for 0x8000_0005.
// AMD docs do not specify the behaviour for 0004 and 0002.
// Centaur/VIA and most other manufacturers use the AMD method,
// except Cyrix MediaGX MMX Enhanced uses their OWN form of CPUID2!
// NS Geode GX1 provides CyrixCPUID2 _and_ does the same wrong behaviour
// for CPUID80000005. But Geode GX uses the AMD method
// Deal with Geode GX1 - make it same as MediaGX MMX.
if (max_extended_cpuid==0x8000_0005 && max_cpuid==2) {
max_extended_cpuid = 0x8000_0004;
}
// Therefore, we try the AMD method unless it's an Intel chip.
// If we still have no info, try the Intel methods.
datacache[0].size = 0;
if (max_cpuid<2 || !probablyIntel) {
if (max_extended_cpuid >= 0x8000_0005) {
getAMDcacheinfo();
} else if (probablyAMD) {
// According to AMDProcRecognitionAppNote, this means CPU
// K5 model 0, or Am5x86 (model 4), or Am4x86DX4 (model 4)
// Am5x86 has 16Kb 4-way unified data & code cache.
datacache[0].size = 8;
datacache[0].associativity = 4;
datacache[0].lineSize = 32;
} else {
// Some obscure CPU.
// Values for Cyrix 6x86MX (family 6, model 0)
datacache[0].size = 64;
datacache[0].associativity = 4;
datacache[0].lineSize = 32;
}
}
if ((datacache[0].size == 0) && max_cpuid>=4) {
getcacheinfoCPUID4();
}
if ((datacache[0].size == 0) && max_cpuid>=2) {
getcacheinfoCPUID2();
}
if (datacache[0].size == 0) {
// Pentium, PMMX, late model 486, or an obscure CPU
if (mmx) { // Pentium MMX. Also has 8kB code cache.
datacache[0].size = 16;
datacache[0].associativity = 4;
datacache[0].lineSize = 32;
} else { // Pentium 1 (which also has 8kB code cache)
// or 486.
// Cyrix 6x86: 16, 4way, 32 linesize
datacache[0].size = 8;
datacache[0].associativity = 2;
datacache[0].lineSize = 32;
}
}
if (hyperThreadingBit) maxThreads = (apic>>>16) & 0xFF;
else maxThreads = maxCores;
}
// Return true if the cpuid instruction is supported.
// BUG(WONTFIX): Returns false for Cyrix 6x86 and 6x86L. They will be treated as 486 machines.
bool hasCPUID()
{
uint flags;
asm {
pushfd;
pop EAX;
mov flags, EAX;
xor EAX, 0x0020_0000;
push EAX;
popfd;
pushfd;
pop EAX;
xor flags, EAX;
}
return (flags & 0x0020_0000) !=0;
}
} else { // inline asm X86
bool hasCPUID() { return false; }
void cpuidX86()
{
datacache[0].size = 8;
datacache[0].associativity = 2;
datacache[0].lineSize = 32;
}
}
// TODO: Implement this function with OS support
void cpuidPPC()
{
enum :int { PPC601, PPC603, PPC603E, PPC604,
PPC604E, PPC620, PPCG3, PPCG4, PPCG5 };
// TODO:
// asm { mfpvr; } returns the CPU version but unfortunately it can
// only be used in kernel mode. So OS support is required.
int cputype = PPC603;
// 601 has a 8KB combined data & code L1 cache.
uint sizes[] = [4, 8, 16, 16, 32, 32, 32, 32, 64];
ubyte ways[] = [8, 2, 4, 4, 4, 8, 8, 8, 8];
uint L2size[]= [0, 0, 0, 0, 0, 0, 0, 256, 512];
uint L3size[]= [0, 0, 0, 0, 0, 0, 0, 2048, 0];
datacache[0].size = sizes[cputype];
datacache[0].associativity = ways[cputype];
datacache[0].lineSize = (cputype==PPCG5)? 128 :
(cputype == PPC620 || cputype == PPCG3)? 64 : 32;
datacache[1].size = L2size[cputype];
datacache[2].size = L3size[cputype];
datacache[1].lineSize = datacache[0].lineSize;
datacache[2].lineSize = datacache[0].lineSize;
}
// TODO: Implement this function with OS support
void cpuidSparc()
{
// UltaSparcIIi : L1 = 16, 2way. L2 = 512, 4 way.
// UltraSparcIII : L1 = 64, 4way. L2= 4096 or 8192.
// UltraSparcIIIi: L1 = 64, 4way. L2= 1024, 4 way
// UltraSparcIV : L1 = 64, 4way. L2 = 16*1024.
// UltraSparcIV+ : L1 = 64, 4way. L2 = 2048, L3=32*1024.
// Sparc64V : L1 = 128, 2way. L2 = 4096 4way.
}
static this()
{
if (hasCPUID()) {
cpuidX86();
} else {
// it's a 386 or 486, or a Cyrix 6x86.
//Probably still has an external cache.
}
if (datacache[0].size==0) {
// Guess same as Pentium 1.
datacache[0].size = 8;
datacache[0].associativity = 2;
datacache[0].lineSize = 32;
}
numCacheLevels = 1;
// And now fill up all the unused levels with full memory space.
for (int i=1; i< datacache.length; ++i) {
if (datacache[i].size==0) {
// Set all remaining levels of cache equal to full address space.
datacache[i].size = uint.max/1024;
datacache[i].associativity = 1;
datacache[i].lineSize = datacache[i-1].lineSize;
} else numCacheLevels = i+1;
}
}

Some files were not shown because too many files have changed in this diff Show More