mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-19 05:03:13 +01:00
Added druntime (this should be removed once it works).
This commit is contained in:
5
druntime/src/build-dmd.bat
Normal file
5
druntime/src/build-dmd.bat
Normal 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
19
druntime/src/build-dmd.sh
Normal 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
19
druntime/src/build-ldc.sh
Executable 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
|
||||
286
druntime/src/common/core/bitmanip.d
Normal file
286
druntime/src/common/core/bitmanip.d
Normal 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 );
|
||||
}
|
||||
}
|
||||
290
druntime/src/common/core/bitop.d
Normal file
290
druntime/src/common/core/bitop.d
Normal 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 );
|
||||
}
|
||||
}
|
||||
279
druntime/src/common/core/exception.d
Normal file
279
druntime/src/common/core/exception.d
Normal 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 );
|
||||
}
|
||||
452
druntime/src/common/core/memory.d
Normal file
452
druntime/src/common/core/memory.d
Normal 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 );
|
||||
}
|
||||
}
|
||||
211
druntime/src/common/core/runtime.d
Normal file
211
druntime/src/common/core/runtime.d
Normal 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();
|
||||
}
|
||||
26
druntime/src/common/core/stdc/errno.c
Normal file
26
druntime/src/common/core/stdc/errno.c
Normal 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;
|
||||
}
|
||||
153
druntime/src/common/core/sync/barrier.d
Normal file
153
druntime/src/common/core/sync/barrier.d
Normal 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 );
|
||||
}
|
||||
}
|
||||
573
druntime/src/common/core/sync/condition.d
Normal file
573
druntime/src/common/core/sync/condition.d
Normal 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();
|
||||
}
|
||||
}
|
||||
72
druntime/src/common/core/sync/config.d
Normal file
72
druntime/src/common/core/sync/config.d
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
druntime/src/common/core/sync/exception.d
Normal file
26
druntime/src/common/core/sync/exception.d
Normal 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 );
|
||||
}
|
||||
}
|
||||
268
druntime/src/common/core/sync/mutex.d
Normal file
268
druntime/src/common/core/sync/mutex.d
Normal 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 );
|
||||
}
|
||||
}
|
||||
512
druntime/src/common/core/sync/rwmutex.d
Normal file
512
druntime/src/common/core/sync/rwmutex.d
Normal 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 );
|
||||
}
|
||||
}
|
||||
506
druntime/src/common/core/sync/semaphore.d
Normal file
506
druntime/src/common/core/sync/semaphore.d
Normal 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();
|
||||
}
|
||||
}
|
||||
3516
druntime/src/common/core/thread.d
Normal file
3516
druntime/src/common/core/thread.d
Normal file
File diff suppressed because it is too large
Load Diff
143
druntime/src/common/core/threadasm.S
Normal file
143
druntime/src/common/core/threadasm.S
Normal 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
|
||||
81
druntime/src/common/core/vararg.d
Normal file
81
druntime/src/common/core/vararg.d
Normal 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;
|
||||
}
|
||||
81
druntime/src/common/posix.mak
Normal file
81
druntime/src/common/posix.mak
Normal 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)
|
||||
226
druntime/src/common/win32.mak
Normal file
226
druntime/src/common/win32.mak
Normal 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)
|
||||
386
druntime/src/compiler/dmd/aApply.d
Normal file
386
druntime/src/compiler/dmd/aApply.d
Normal 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;
|
||||
}
|
||||
957
druntime/src/compiler/dmd/aApplyR.d
Normal file
957
druntime/src/compiler/dmd/aApplyR.d
Normal 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);
|
||||
}
|
||||
872
druntime/src/compiler/dmd/aaA.d
Normal file
872
druntime/src/compiler/dmd/aaA.d
Normal 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;
|
||||
}
|
||||
603
druntime/src/compiler/dmd/adi.d
Normal file
603
druntime/src/compiler/dmd/adi.d
Normal 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");
|
||||
}
|
||||
135
druntime/src/compiler/dmd/alloca.d
Normal file
135
druntime/src/compiler/dmd/alloca.d
Normal 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 ;
|
||||
}
|
||||
}
|
||||
186
druntime/src/compiler/dmd/arrayassign.d
Normal file
186
druntime/src/compiler/dmd/arrayassign.d
Normal 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;
|
||||
}
|
||||
1893
druntime/src/compiler/dmd/arraybyte.d
Normal file
1893
druntime/src/compiler/dmd/arraybyte.d
Normal file
File diff suppressed because it is too large
Load Diff
94
druntime/src/compiler/dmd/arraycast.d
Normal file
94
druntime/src/compiler/dmd/arraycast.d
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
42
druntime/src/compiler/dmd/arraycat.d
Normal file
42
druntime/src/compiler/dmd/arraycat.d
Normal 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;
|
||||
}
|
||||
1720
druntime/src/compiler/dmd/arraydouble.d
Normal file
1720
druntime/src/compiler/dmd/arraydouble.d
Normal file
File diff suppressed because it is too large
Load Diff
2309
druntime/src/compiler/dmd/arrayfloat.d
Normal file
2309
druntime/src/compiler/dmd/arrayfloat.d
Normal file
File diff suppressed because it is too large
Load Diff
2430
druntime/src/compiler/dmd/arrayint.d
Normal file
2430
druntime/src/compiler/dmd/arrayint.d
Normal file
File diff suppressed because it is too large
Load Diff
241
druntime/src/compiler/dmd/arrayreal.d
Normal file
241
druntime/src/compiler/dmd/arrayreal.d
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2303
druntime/src/compiler/dmd/arrayshort.d
Normal file
2303
druntime/src/compiler/dmd/arrayshort.d
Normal file
File diff suppressed because it is too large
Load Diff
169
druntime/src/compiler/dmd/cast_.d
Normal file
169
druntime/src/compiler/dmd/cast_.d
Normal 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);
|
||||
}
|
||||
218
druntime/src/compiler/dmd/cmath2.d
Normal file
218
druntime/src/compiler/dmd/cmath2.d
Normal 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 ;
|
||||
}
|
||||
}
|
||||
42
druntime/src/compiler/dmd/compiler.d
Normal file
42
druntime/src/compiler/dmd/compiler.d
Normal 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;
|
||||
}
|
||||
112
druntime/src/compiler/dmd/complex.c
Normal file
112
druntime/src/compiler/dmd/complex.c
Normal 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;
|
||||
}
|
||||
463
druntime/src/compiler/dmd/cover.d
Normal file
463
druntime/src/compiler/dmd/cover.d
Normal 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;
|
||||
}
|
||||
173
druntime/src/compiler/dmd/critical.c
Normal file
173
druntime/src/compiler/dmd/critical.c
Normal 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
|
||||
|
||||
724
druntime/src/compiler/dmd/deh.c
Normal file
724
druntime/src/compiler/dmd/deh.c
Normal 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
|
||||
316
druntime/src/compiler/dmd/deh2.d
Normal file
316
druntime/src/compiler/dmd/deh2.d
Normal 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 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
374
druntime/src/compiler/dmd/dmain2.BAK
Normal file
374
druntime/src/compiler/dmd/dmain2.BAK
Normal 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;
|
||||
}
|
||||
394
druntime/src/compiler/dmd/dmain2.d
Normal file
394
druntime/src/compiler/dmd/dmain2.d
Normal 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;
|
||||
}
|
||||
35
druntime/src/compiler/dmd/invariant.d
Normal file
35
druntime/src/compiler/dmd/invariant.d
Normal 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);
|
||||
}
|
||||
32
druntime/src/compiler/dmd/invariant_.d
Normal file
32
druntime/src/compiler/dmd/invariant_.d
Normal 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);
|
||||
}
|
||||
1073
druntime/src/compiler/dmd/lifetime.d
Normal file
1073
druntime/src/compiler/dmd/lifetime.d
Normal file
File diff suppressed because it is too large
Load Diff
531
druntime/src/compiler/dmd/llmath.d
Normal file
531
druntime/src/compiler/dmd/llmath.d
Normal 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 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
105
druntime/src/compiler/dmd/mars.h
Normal file
105
druntime/src/compiler/dmd/mars.h
Normal 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
|
||||
213
druntime/src/compiler/dmd/memory.d
Normal file
213
druntime/src/compiler/dmd/memory.d
Normal 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." );
|
||||
}
|
||||
}
|
||||
75
druntime/src/compiler/dmd/memory_osx.c
Normal file
75
druntime/src/compiler/dmd/memory_osx.c
Normal 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
|
||||
109
druntime/src/compiler/dmd/memset.d
Normal file
109
druntime/src/compiler/dmd/memset.d
Normal 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;
|
||||
}
|
||||
85
druntime/src/compiler/dmd/minit.asm
Normal file
85
druntime/src/compiler/dmd/minit.asm
Normal 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
|
||||
215
druntime/src/compiler/dmd/monitor.c
Normal file
215
druntime/src/compiler/dmd/monitor.c
Normal 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
|
||||
34
druntime/src/compiler/dmd/obj.d
Normal file
34
druntime/src/compiler/dmd/obj.d
Normal 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);
|
||||
}
|
||||
1599
druntime/src/compiler/dmd/object_.d
Normal file
1599
druntime/src/compiler/dmd/object_.d
Normal file
File diff suppressed because it is too large
Load Diff
82
druntime/src/compiler/dmd/posix.mak
Normal file
82
druntime/src/compiler/dmd/posix.mak
Normal 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)
|
||||
158
druntime/src/compiler/dmd/qsort.d
Normal file
158
druntime/src/compiler/dmd/qsort.d
Normal 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]);
|
||||
}
|
||||
}
|
||||
71
druntime/src/compiler/dmd/qsort2.d
Normal file
71
druntime/src/compiler/dmd/qsort2.d
Normal 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]);
|
||||
}
|
||||
}
|
||||
411
druntime/src/compiler/dmd/switch_.d
Normal file
411
druntime/src/compiler/dmd/switch_.d
Normal 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;
|
||||
}
|
||||
}
|
||||
44
druntime/src/compiler/dmd/tls.S
Normal file
44
druntime/src/compiler/dmd/tls.S
Normal 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
|
||||
919
druntime/src/compiler/dmd/trace.d
Normal file
919
druntime/src/compiler/dmd/trace.d
Normal 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);
|
||||
}
|
||||
107
druntime/src/compiler/dmd/typeinfo/ti_AC.d
Normal file
107
druntime/src/compiler/dmd/typeinfo/ti_AC.d
Normal 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);
|
||||
}
|
||||
}
|
||||
94
druntime/src/compiler/dmd/typeinfo/ti_Acdouble.d
Normal file
94
druntime/src/compiler/dmd/typeinfo/ti_Acdouble.d
Normal 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);
|
||||
}
|
||||
}
|
||||
92
druntime/src/compiler/dmd/typeinfo/ti_Acfloat.d
Normal file
92
druntime/src/compiler/dmd/typeinfo/ti_Acfloat.d
Normal 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);
|
||||
}
|
||||
}
|
||||
95
druntime/src/compiler/dmd/typeinfo/ti_Acreal.d
Normal file
95
druntime/src/compiler/dmd/typeinfo/ti_Acreal.d
Normal 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);
|
||||
}
|
||||
}
|
||||
104
druntime/src/compiler/dmd/typeinfo/ti_Adouble.d
Normal file
104
druntime/src/compiler/dmd/typeinfo/ti_Adouble.d
Normal 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);
|
||||
}
|
||||
}
|
||||
103
druntime/src/compiler/dmd/typeinfo/ti_Afloat.d
Normal file
103
druntime/src/compiler/dmd/typeinfo/ti_Afloat.d
Normal 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);
|
||||
}
|
||||
}
|
||||
228
druntime/src/compiler/dmd/typeinfo/ti_Ag.d
Normal file
228
druntime/src/compiler/dmd/typeinfo/ti_Ag.d
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
140
druntime/src/compiler/dmd/typeinfo/ti_Aint.d
Normal file
140
druntime/src/compiler/dmd/typeinfo/ti_Aint.d
Normal 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);
|
||||
}
|
||||
}
|
||||
120
druntime/src/compiler/dmd/typeinfo/ti_Along.d
Normal file
120
druntime/src/compiler/dmd/typeinfo/ti_Along.d
Normal 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);
|
||||
}
|
||||
}
|
||||
105
druntime/src/compiler/dmd/typeinfo/ti_Areal.d
Normal file
105
druntime/src/compiler/dmd/typeinfo/ti_Areal.d
Normal 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);
|
||||
}
|
||||
}
|
||||
143
druntime/src/compiler/dmd/typeinfo/ti_Ashort.d
Normal file
143
druntime/src/compiler/dmd/typeinfo/ti_Ashort.d
Normal 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);
|
||||
}
|
||||
}
|
||||
63
druntime/src/compiler/dmd/typeinfo/ti_C.d
Normal file
63
druntime/src/compiler/dmd/typeinfo/ti_C.d
Normal 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;
|
||||
}
|
||||
}
|
||||
49
druntime/src/compiler/dmd/typeinfo/ti_byte.d
Normal file
49
druntime/src/compiler/dmd/typeinfo/ti_byte.d
Normal 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;
|
||||
}
|
||||
}
|
||||
77
druntime/src/compiler/dmd/typeinfo/ti_cdouble.d
Normal file
77
druntime/src/compiler/dmd/typeinfo/ti_cdouble.d
Normal 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];
|
||||
}
|
||||
}
|
||||
76
druntime/src/compiler/dmd/typeinfo/ti_cfloat.d
Normal file
76
druntime/src/compiler/dmd/typeinfo/ti_cfloat.d
Normal 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];
|
||||
}
|
||||
}
|
||||
55
druntime/src/compiler/dmd/typeinfo/ti_char.d
Normal file
55
druntime/src/compiler/dmd/typeinfo/ti_char.d
Normal 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];
|
||||
}
|
||||
}
|
||||
78
druntime/src/compiler/dmd/typeinfo/ti_creal.d
Normal file
78
druntime/src/compiler/dmd/typeinfo/ti_creal.d
Normal 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];
|
||||
}
|
||||
}
|
||||
55
druntime/src/compiler/dmd/typeinfo/ti_dchar.d
Normal file
55
druntime/src/compiler/dmd/typeinfo/ti_dchar.d
Normal 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];
|
||||
}
|
||||
}
|
||||
50
druntime/src/compiler/dmd/typeinfo/ti_delegate.d
Normal file
50
druntime/src/compiler/dmd/typeinfo/ti_delegate.d
Normal 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;
|
||||
}
|
||||
}
|
||||
75
druntime/src/compiler/dmd/typeinfo/ti_double.d
Normal file
75
druntime/src/compiler/dmd/typeinfo/ti_double.d
Normal 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];
|
||||
}
|
||||
}
|
||||
75
druntime/src/compiler/dmd/typeinfo/ti_float.d
Normal file
75
druntime/src/compiler/dmd/typeinfo/ti_float.d
Normal 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];
|
||||
}
|
||||
}
|
||||
22
druntime/src/compiler/dmd/typeinfo/ti_idouble.d
Normal file
22
druntime/src/compiler/dmd/typeinfo/ti_idouble.d
Normal 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"; }
|
||||
}
|
||||
22
druntime/src/compiler/dmd/typeinfo/ti_ifloat.d
Normal file
22
druntime/src/compiler/dmd/typeinfo/ti_ifloat.d
Normal 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"; }
|
||||
}
|
||||
53
druntime/src/compiler/dmd/typeinfo/ti_int.d
Normal file
53
druntime/src/compiler/dmd/typeinfo/ti_int.d
Normal 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;
|
||||
}
|
||||
}
|
||||
22
druntime/src/compiler/dmd/typeinfo/ti_ireal.d
Normal file
22
druntime/src/compiler/dmd/typeinfo/ti_ireal.d
Normal 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"; }
|
||||
}
|
||||
53
druntime/src/compiler/dmd/typeinfo/ti_long.d
Normal file
53
druntime/src/compiler/dmd/typeinfo/ti_long.d
Normal 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;
|
||||
}
|
||||
}
|
||||
57
druntime/src/compiler/dmd/typeinfo/ti_ptr.d
Normal file
57
druntime/src/compiler/dmd/typeinfo/ti_ptr.d
Normal 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;
|
||||
}
|
||||
}
|
||||
75
druntime/src/compiler/dmd/typeinfo/ti_real.d
Normal file
75
druntime/src/compiler/dmd/typeinfo/ti_real.d
Normal 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];
|
||||
}
|
||||
}
|
||||
49
druntime/src/compiler/dmd/typeinfo/ti_short.d
Normal file
49
druntime/src/compiler/dmd/typeinfo/ti_short.d
Normal 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;
|
||||
}
|
||||
}
|
||||
54
druntime/src/compiler/dmd/typeinfo/ti_ubyte.d
Normal file
54
druntime/src/compiler/dmd/typeinfo/ti_ubyte.d
Normal 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"; }
|
||||
}
|
||||
53
druntime/src/compiler/dmd/typeinfo/ti_uint.d
Normal file
53
druntime/src/compiler/dmd/typeinfo/ti_uint.d
Normal 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;
|
||||
}
|
||||
}
|
||||
53
druntime/src/compiler/dmd/typeinfo/ti_ulong.d
Normal file
53
druntime/src/compiler/dmd/typeinfo/ti_ulong.d
Normal 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;
|
||||
}
|
||||
}
|
||||
49
druntime/src/compiler/dmd/typeinfo/ti_ushort.d
Normal file
49
druntime/src/compiler/dmd/typeinfo/ti_ushort.d
Normal 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;
|
||||
}
|
||||
}
|
||||
54
druntime/src/compiler/dmd/typeinfo/ti_void.d
Normal file
54
druntime/src/compiler/dmd/typeinfo/ti_void.d
Normal 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;
|
||||
}
|
||||
}
|
||||
55
druntime/src/compiler/dmd/typeinfo/ti_wchar.d
Normal file
55
druntime/src/compiler/dmd/typeinfo/ti_wchar.d
Normal 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];
|
||||
}
|
||||
}
|
||||
54
druntime/src/compiler/dmd/util/console.d
Normal file
54
druntime/src/compiler/dmd/util/console.d
Normal 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;
|
||||
719
druntime/src/compiler/dmd/util/cpuid.d
Normal file
719
druntime/src/compiler/dmd/util/cpuid.d
Normal 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 <tomas@famolsen.dk>
|
||||
*
|
||||
* 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
Reference in New Issue
Block a user