From 5a07183e26b7ca151959629420a83f59af5339f3 Mon Sep 17 00:00:00 2001 From: sean Date: Fri, 19 Sep 2008 02:35:12 +0000 Subject: [PATCH] First commit of the D Runtime Project. This includes a fully functional runtime for DMD/D1. Support for DMD/D2 is next on the agenda. git-svn-id: http://svn.dsource.org/projects/druntime/trunk@5 4a9d5153-6564-4b3f-b5e1-7e8e9dac548f --- import/bitmanip.di | 262 ++ import/object.di | 179 ++ import/std/c/stdarg.di | 32 + import/std/intrinsic.di | 176 ++ import/std/stdarg.di | 32 + import/stdc/complex.d | 99 + import/stdc/config.d | 30 + import/stdc/ctype.d | 26 + import/stdc/errno.d | 375 +++ import/stdc/fenv.d | 132 + import/stdc/inttypes.d | 252 ++ import/stdc/limits.d | 33 + import/stdc/locale.d | 55 + import/stdc/math.d | 691 +++++ import/stdc/posix/arpa/inet.d | 127 + import/stdc/posix/config.d | 27 + import/stdc/posix/dirent.d | 198 ++ import/stdc/posix/dlfcn.d | 65 + import/stdc/posix/fcntl.d | 248 ++ import/stdc/posix/inttypes.d | 30 + import/stdc/posix/net/if_.d | 77 + import/stdc/posix/netinet/in_.d | 327 +++ import/stdc/posix/netinet/tcp.d | 33 + import/stdc/posix/poll.d | 133 + import/stdc/posix/pthread.d | 534 ++++ import/stdc/posix/pwd.d | 132 + import/stdc/posix/sched.d | 132 + import/stdc/posix/semaphore.d | 112 + import/stdc/posix/setjmp.d | 103 + import/stdc/posix/signal.d | 824 ++++++ import/stdc/posix/stdio.d | 214 ++ import/stdc/posix/stdlib.d | 298 +++ import/stdc/posix/sys/ipc.d | 99 + import/stdc/posix/sys/mman.d | 308 +++ import/stdc/posix/sys/select.d | 150 ++ import/stdc/posix/sys/shm.d | 111 + import/stdc/posix/sys/socket.d | 642 +++++ import/stdc/posix/sys/stat.d | 399 +++ import/stdc/posix/sys/time.d | 121 + import/stdc/posix/sys/types.d | 452 ++++ import/stdc/posix/sys/uio.d | 65 + import/stdc/posix/sys/wait.d | 136 + import/stdc/posix/termios.d | 415 +++ import/stdc/posix/time.d | 255 ++ import/stdc/posix/ucontext.d | 155 ++ import/stdc/posix/unistd.d | 589 +++++ import/stdc/posix/utime.d | 58 + import/stdc/signal.d | 48 + import/stdc/stdarg.d | 47 + import/stdc/stddef.d | 33 + import/stdc/stdint.d | 151 ++ import/stdc/stdio.d | 445 ++++ import/stdc/stdlib.d | 101 + import/stdc/string.d | 76 + import/stdc/tgmath.d | 331 +++ import/stdc/time.d | 95 + import/stdc/wctype.d | 33 + import/sys/windows/windows.d | 3221 +++++++++++++++++++++++ license.txt | 10 + src/build-dmd.bat | 7 + src/build-dmd.sh | 19 + src/compiler/dmd/aApply.d | 408 +++ src/compiler/dmd/aApplyR.d | 974 +++++++ src/compiler/dmd/aaA.d | 839 ++++++ src/compiler/dmd/adi.d | 626 +++++ src/compiler/dmd/alloca.d | 110 + src/compiler/dmd/arraybyte.d | 1890 +++++++++++++ src/compiler/dmd/arraycast.d | 109 + src/compiler/dmd/arraycat.d | 61 + src/compiler/dmd/arraydouble.d | 1714 ++++++++++++ src/compiler/dmd/arrayfloat.d | 2303 ++++++++++++++++ src/compiler/dmd/arrayint.d | 2427 +++++++++++++++++ src/compiler/dmd/arrayreal.d | 234 ++ src/compiler/dmd/arrayshort.d | 2300 ++++++++++++++++ src/compiler/dmd/cast_.d | 184 ++ src/compiler/dmd/cmath2.d | 218 ++ src/compiler/dmd/compiler.d | 36 + src/compiler/dmd/complex.c | 107 + src/compiler/dmd/cover.d | 370 +++ src/compiler/dmd/critical.c | 159 ++ src/compiler/dmd/deh.c | 657 +++++ src/compiler/dmd/deh2.d | 308 +++ src/compiler/dmd/dmain2.d | 304 +++ src/compiler/dmd/invariant_.d | 25 + src/compiler/dmd/lifetime.d | 1051 ++++++++ src/compiler/dmd/llmath.d | 295 +++ src/compiler/dmd/mars.h | 104 + src/compiler/dmd/memory.d | 155 ++ src/compiler/dmd/memset.d | 120 + src/compiler/dmd/minit.asm | 79 + src/compiler/dmd/minit.obj | Bin 0 -> 319 bytes src/compiler/dmd/monitor.c | 208 ++ src/compiler/dmd/obj.d | 27 + src/compiler/dmd/object_.d | 1307 +++++++++ src/compiler/dmd/posix.mak | 176 ++ src/compiler/dmd/qsort.d | 158 ++ src/compiler/dmd/qsort2.d | 72 + src/compiler/dmd/switch_.d | 426 +++ src/compiler/dmd/trace.d | 867 ++++++ src/compiler/dmd/typeinfo/ti_AC.d | 95 + src/compiler/dmd/typeinfo/ti_Acdouble.d | 106 + src/compiler/dmd/typeinfo/ti_Acfloat.d | 104 + src/compiler/dmd/typeinfo/ti_Acreal.d | 107 + src/compiler/dmd/typeinfo/ti_Adouble.d | 116 + src/compiler/dmd/typeinfo/ti_Afloat.d | 115 + src/compiler/dmd/typeinfo/ti_Ag.d | 204 ++ src/compiler/dmd/typeinfo/ti_Aint.d | 118 + src/compiler/dmd/typeinfo/ti_Along.d | 109 + src/compiler/dmd/typeinfo/ti_Areal.d | 117 + src/compiler/dmd/typeinfo/ti_Ashort.d | 132 + src/compiler/dmd/typeinfo/ti_C.d | 74 + src/compiler/dmd/typeinfo/ti_byte.d | 38 + src/compiler/dmd/typeinfo/ti_cdouble.d | 66 + src/compiler/dmd/typeinfo/ti_cfloat.d | 65 + src/compiler/dmd/typeinfo/ti_char.d | 42 + src/compiler/dmd/typeinfo/ti_creal.d | 67 + src/compiler/dmd/typeinfo/ti_dchar.d | 44 + src/compiler/dmd/typeinfo/ti_delegate.d | 39 + src/compiler/dmd/typeinfo/ti_double.d | 64 + src/compiler/dmd/typeinfo/ti_float.d | 64 + src/compiler/dmd/typeinfo/ti_idouble.d | 11 + src/compiler/dmd/typeinfo/ti_ifloat.d | 11 + src/compiler/dmd/typeinfo/ti_int.d | 42 + src/compiler/dmd/typeinfo/ti_ireal.d | 11 + src/compiler/dmd/typeinfo/ti_long.d | 42 + src/compiler/dmd/typeinfo/ti_ptr.d | 46 + src/compiler/dmd/typeinfo/ti_real.d | 64 + src/compiler/dmd/typeinfo/ti_short.d | 38 + src/compiler/dmd/typeinfo/ti_ubyte.d | 43 + src/compiler/dmd/typeinfo/ti_uint.d | 42 + src/compiler/dmd/typeinfo/ti_ulong.d | 42 + src/compiler/dmd/typeinfo/ti_ushort.d | 38 + src/compiler/dmd/typeinfo/ti_void.d | 43 + src/compiler/dmd/typeinfo/ti_wchar.d | 43 + src/compiler/dmd/util/console.d | 49 + src/compiler/dmd/util/cpuid.d | 459 ++++ src/compiler/dmd/util/ctype.d | 106 + src/compiler/dmd/util/string.d | 35 + src/compiler/dmd/util/utf.d | 851 ++++++ src/compiler/dmd/win32.mak | 169 ++ src/compiler/tango-rt-dmd.lib | Bin 0 -> 258048 bytes src/core/bitmanip.d | 286 ++ src/core/exception.d | 251 ++ src/core/memory.d | 444 ++++ src/core/posix.mak | 129 + src/core/runtime.d | 171 ++ src/core/stdc.c | 21 + src/core/thread.d | 3199 ++++++++++++++++++++++ src/core/win32.mak | 125 + src/dmd-posix.mak | 75 + src/dmd-win32.mak | 101 + src/dmd.conf | 2 + src/gc/basic/gc.d | 186 ++ src/gc/basic/gcalloc.d | 213 ++ src/gc/basic/gcbits.d | 205 ++ src/gc/basic/gcstats.d | 38 + src/gc/basic/gcx.d | 2982 +++++++++++++++++++++ src/gc/basic/posix.mak | 100 + src/gc/basic/win32.mak | 97 + src/gc/stub/gc.d | 166 ++ src/gc/stub/posix.mak | 98 + src/gc/stub/win32.mak | 95 + src/sc.ini | 7 + 163 files changed, 49030 insertions(+) create mode 100644 import/bitmanip.di create mode 100644 import/object.di create mode 100644 import/std/c/stdarg.di create mode 100644 import/std/intrinsic.di create mode 100644 import/std/stdarg.di create mode 100644 import/stdc/complex.d create mode 100644 import/stdc/config.d create mode 100644 import/stdc/ctype.d create mode 100644 import/stdc/errno.d create mode 100644 import/stdc/fenv.d create mode 100644 import/stdc/inttypes.d create mode 100644 import/stdc/limits.d create mode 100644 import/stdc/locale.d create mode 100644 import/stdc/math.d create mode 100644 import/stdc/posix/arpa/inet.d create mode 100644 import/stdc/posix/config.d create mode 100644 import/stdc/posix/dirent.d create mode 100644 import/stdc/posix/dlfcn.d create mode 100644 import/stdc/posix/fcntl.d create mode 100644 import/stdc/posix/inttypes.d create mode 100644 import/stdc/posix/net/if_.d create mode 100644 import/stdc/posix/netinet/in_.d create mode 100644 import/stdc/posix/netinet/tcp.d create mode 100644 import/stdc/posix/poll.d create mode 100644 import/stdc/posix/pthread.d create mode 100644 import/stdc/posix/pwd.d create mode 100644 import/stdc/posix/sched.d create mode 100644 import/stdc/posix/semaphore.d create mode 100644 import/stdc/posix/setjmp.d create mode 100644 import/stdc/posix/signal.d create mode 100644 import/stdc/posix/stdio.d create mode 100644 import/stdc/posix/stdlib.d create mode 100644 import/stdc/posix/sys/ipc.d create mode 100644 import/stdc/posix/sys/mman.d create mode 100644 import/stdc/posix/sys/select.d create mode 100644 import/stdc/posix/sys/shm.d create mode 100644 import/stdc/posix/sys/socket.d create mode 100644 import/stdc/posix/sys/stat.d create mode 100644 import/stdc/posix/sys/time.d create mode 100644 import/stdc/posix/sys/types.d create mode 100644 import/stdc/posix/sys/uio.d create mode 100644 import/stdc/posix/sys/wait.d create mode 100644 import/stdc/posix/termios.d create mode 100644 import/stdc/posix/time.d create mode 100644 import/stdc/posix/ucontext.d create mode 100644 import/stdc/posix/unistd.d create mode 100644 import/stdc/posix/utime.d create mode 100644 import/stdc/signal.d create mode 100644 import/stdc/stdarg.d create mode 100644 import/stdc/stddef.d create mode 100644 import/stdc/stdint.d create mode 100644 import/stdc/stdio.d create mode 100644 import/stdc/stdlib.d create mode 100644 import/stdc/string.d create mode 100644 import/stdc/tgmath.d create mode 100644 import/stdc/time.d create mode 100644 import/stdc/wctype.d create mode 100644 import/sys/windows/windows.d create mode 100644 license.txt create mode 100644 src/build-dmd.bat create mode 100644 src/build-dmd.sh create mode 100644 src/compiler/dmd/aApply.d create mode 100644 src/compiler/dmd/aApplyR.d create mode 100644 src/compiler/dmd/aaA.d create mode 100644 src/compiler/dmd/adi.d create mode 100644 src/compiler/dmd/alloca.d create mode 100644 src/compiler/dmd/arraybyte.d create mode 100644 src/compiler/dmd/arraycast.d create mode 100644 src/compiler/dmd/arraycat.d create mode 100644 src/compiler/dmd/arraydouble.d create mode 100644 src/compiler/dmd/arrayfloat.d create mode 100644 src/compiler/dmd/arrayint.d create mode 100644 src/compiler/dmd/arrayreal.d create mode 100644 src/compiler/dmd/arrayshort.d create mode 100644 src/compiler/dmd/cast_.d create mode 100644 src/compiler/dmd/cmath2.d create mode 100644 src/compiler/dmd/compiler.d create mode 100644 src/compiler/dmd/complex.c create mode 100644 src/compiler/dmd/cover.d create mode 100644 src/compiler/dmd/critical.c create mode 100644 src/compiler/dmd/deh.c create mode 100644 src/compiler/dmd/deh2.d create mode 100644 src/compiler/dmd/dmain2.d create mode 100644 src/compiler/dmd/invariant_.d create mode 100644 src/compiler/dmd/lifetime.d create mode 100644 src/compiler/dmd/llmath.d create mode 100644 src/compiler/dmd/mars.h create mode 100644 src/compiler/dmd/memory.d create mode 100644 src/compiler/dmd/memset.d create mode 100644 src/compiler/dmd/minit.asm create mode 100644 src/compiler/dmd/minit.obj create mode 100644 src/compiler/dmd/monitor.c create mode 100644 src/compiler/dmd/obj.d create mode 100644 src/compiler/dmd/object_.d create mode 100644 src/compiler/dmd/posix.mak create mode 100644 src/compiler/dmd/qsort.d create mode 100644 src/compiler/dmd/qsort2.d create mode 100644 src/compiler/dmd/switch_.d create mode 100644 src/compiler/dmd/trace.d create mode 100644 src/compiler/dmd/typeinfo/ti_AC.d create mode 100644 src/compiler/dmd/typeinfo/ti_Acdouble.d create mode 100644 src/compiler/dmd/typeinfo/ti_Acfloat.d create mode 100644 src/compiler/dmd/typeinfo/ti_Acreal.d create mode 100644 src/compiler/dmd/typeinfo/ti_Adouble.d create mode 100644 src/compiler/dmd/typeinfo/ti_Afloat.d create mode 100644 src/compiler/dmd/typeinfo/ti_Ag.d create mode 100644 src/compiler/dmd/typeinfo/ti_Aint.d create mode 100644 src/compiler/dmd/typeinfo/ti_Along.d create mode 100644 src/compiler/dmd/typeinfo/ti_Areal.d create mode 100644 src/compiler/dmd/typeinfo/ti_Ashort.d create mode 100644 src/compiler/dmd/typeinfo/ti_C.d create mode 100644 src/compiler/dmd/typeinfo/ti_byte.d create mode 100644 src/compiler/dmd/typeinfo/ti_cdouble.d create mode 100644 src/compiler/dmd/typeinfo/ti_cfloat.d create mode 100644 src/compiler/dmd/typeinfo/ti_char.d create mode 100644 src/compiler/dmd/typeinfo/ti_creal.d create mode 100644 src/compiler/dmd/typeinfo/ti_dchar.d create mode 100644 src/compiler/dmd/typeinfo/ti_delegate.d create mode 100644 src/compiler/dmd/typeinfo/ti_double.d create mode 100644 src/compiler/dmd/typeinfo/ti_float.d create mode 100644 src/compiler/dmd/typeinfo/ti_idouble.d create mode 100644 src/compiler/dmd/typeinfo/ti_ifloat.d create mode 100644 src/compiler/dmd/typeinfo/ti_int.d create mode 100644 src/compiler/dmd/typeinfo/ti_ireal.d create mode 100644 src/compiler/dmd/typeinfo/ti_long.d create mode 100644 src/compiler/dmd/typeinfo/ti_ptr.d create mode 100644 src/compiler/dmd/typeinfo/ti_real.d create mode 100644 src/compiler/dmd/typeinfo/ti_short.d create mode 100644 src/compiler/dmd/typeinfo/ti_ubyte.d create mode 100644 src/compiler/dmd/typeinfo/ti_uint.d create mode 100644 src/compiler/dmd/typeinfo/ti_ulong.d create mode 100644 src/compiler/dmd/typeinfo/ti_ushort.d create mode 100644 src/compiler/dmd/typeinfo/ti_void.d create mode 100644 src/compiler/dmd/typeinfo/ti_wchar.d create mode 100644 src/compiler/dmd/util/console.d create mode 100644 src/compiler/dmd/util/cpuid.d create mode 100644 src/compiler/dmd/util/ctype.d create mode 100644 src/compiler/dmd/util/string.d create mode 100644 src/compiler/dmd/util/utf.d create mode 100644 src/compiler/dmd/win32.mak create mode 100644 src/compiler/tango-rt-dmd.lib create mode 100644 src/core/bitmanip.d create mode 100644 src/core/exception.d create mode 100644 src/core/memory.d create mode 100644 src/core/posix.mak create mode 100644 src/core/runtime.d create mode 100644 src/core/stdc.c create mode 100644 src/core/thread.d create mode 100644 src/core/win32.mak create mode 100644 src/dmd-posix.mak create mode 100644 src/dmd-win32.mak create mode 100644 src/dmd.conf create mode 100644 src/gc/basic/gc.d create mode 100644 src/gc/basic/gcalloc.d create mode 100644 src/gc/basic/gcbits.d create mode 100644 src/gc/basic/gcstats.d create mode 100644 src/gc/basic/gcx.d create mode 100644 src/gc/basic/posix.mak create mode 100644 src/gc/basic/win32.mak create mode 100644 src/gc/stub/gc.d create mode 100644 src/gc/stub/posix.mak create mode 100644 src/gc/stub/win32.mak create mode 100644 src/sc.ini diff --git a/import/bitmanip.di b/import/bitmanip.di new file mode 100644 index 0000000..ab2c3ec --- /dev/null +++ b/import/bitmanip.di @@ -0,0 +1,262 @@ +/** + * 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 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 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
+ * 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 bitmanip; + + int main() + { + uint array[2]; + + array[0] = 2; + array[1] = 0x100; + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bts(array, 35) = %d\n", bts(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btr(array, 35) = %d\n", btr(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bt(array, 1) = %d\n", bt(array, 1)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + return 0; + } + * --- + * Output: +
+    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
+    
+ */ + 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; +} + + +/** + * 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; + + } +} diff --git a/import/object.di b/import/object.di new file mode 100644 index 0000000..1360687 --- /dev/null +++ b/import/object.di @@ -0,0 +1,179 @@ +module object; + +alias typeof(int.sizeof) size_t; +alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; + +alias size_t hash_t; +alias int equals_t; + +alias char[] string; +alias wchar[] wstring; +alias dchar[] dstring; + +class Object +{ + string toString(); + hash_t toHash(); + int opCmp(Object o); + equals_t opEquals(Object o); + + interface Monitor + { + void lock(); + void unlock(); + } +} + +struct Interface +{ + ClassInfo classinfo; + void*[] vtbl; + ptrdiff_t offset; // offset to Interface 'this' from Object 'this' +} + +class ClassInfo : Object +{ + byte[] init; // class static initializer + string name; // class name + void*[] vtbl; // virtual function pointer table + Interface[] interfaces; + ClassInfo base; + void* destructor; + void(*classInvariant)(Object); + uint flags; + // 1: // is IUnknown or is derived from IUnknown + // 2: // has no possible pointers into GC memory + // 4: // has offTi[] member + // 8: // has constructors + void* deallocator; + OffsetTypeInfo[] offTi; + void* defaultConstructor; + + static ClassInfo find(in char[] classname); + Object create(); +} + +struct OffsetTypeInfo +{ + size_t offset; + TypeInfo ti; +} + +class TypeInfo +{ + hash_t getHash(in void* p); + int equals(in void* p1, in void* p2); + int compare(in void* p1, in void* p2); + size_t tsize(); + void swap(void* p1, void* p2); + TypeInfo next(); + void[] init(); + uint flags(); + // 1: // has possible pointers into GC memory + OffsetTypeInfo[] offTi(); +} + +class TypeInfo_Typedef : TypeInfo +{ + TypeInfo base; + string name; + void[] m_init; +} + +class TypeInfo_Enum : TypeInfo_Typedef +{ +} + +class TypeInfo_Pointer : TypeInfo +{ + TypeInfo m_next; +} + +class TypeInfo_Array : TypeInfo +{ + TypeInfo value; +} + +class TypeInfo_StaticArray : TypeInfo +{ + TypeInfo value; + size_t len; +} + +class TypeInfo_AssociativeArray : TypeInfo +{ + TypeInfo value; + TypeInfo key; +} + +class TypeInfo_Function : TypeInfo +{ + TypeInfo next; +} + +class TypeInfo_Delegate : TypeInfo +{ + TypeInfo next; +} + +class TypeInfo_Class : TypeInfo +{ + ClassInfo info; +} + +class TypeInfo_Interface : TypeInfo +{ + ClassInfo info; +} + +class TypeInfo_Struct : TypeInfo +{ + string name; + void[] m_init; + + uint function(in void*) xtoHash; + equals_t function(in void*,in void*) xopEquals; + int function(in void*,in void*) xopCmp; + string function(in void*) xtoString; + + uint m_flags; + +} + +class TypeInfo_Tuple : TypeInfo +{ + TypeInfo[] elements; +} + +class ModuleInfo +{ + string name; + ModuleInfo[] importedModules; + ClassInfo[] localClasses; + uint flags; + + void function() ctor; + void function() dtor; + void function() unitTest; + + static int opApply( int delegate( inout ModuleInfo ) ); +} + +class Exception : Object +{ + interface TraceInfo + { + int opApply( int delegate( inout char[] ) ); + string toString(); + } + + char[] msg; + char[] file; + size_t line; + TraceInfo info; + Exception next; + + this(char[] msg, Exception next = null); + this(char[] msg, char[] file, size_t line, Exception next = null); + string toString(); +} diff --git a/import/std/c/stdarg.di b/import/std/c/stdarg.di new file mode 100644 index 0000000..29f4f1e --- /dev/null +++ b/import/std/c/stdarg.di @@ -0,0 +1,32 @@ +/** + * These functions are built-in intrinsics to the compiler. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: David Friedman + */ +module std.c.stdarg; + +version( GNU ) +{ + private import gcc.builtins; + alias __builtin_va_list va_list; + alias __builtin_va_end va_end; + alias __builtin_va_copy va_copy; +} + +template va_start(T) +{ + void va_start( out va_list ap, inout T parmn ) + { + + } +} + +template va_arg(T) +{ + T va_arg( inout va_list ap ) + { + return T.init; + } +} diff --git a/import/std/intrinsic.di b/import/std/intrinsic.di new file mode 100644 index 0000000..c5c8110 --- /dev/null +++ b/import/std/intrinsic.di @@ -0,0 +1,176 @@ +/** + * These functions are built-in intrinsics to the compiler. + * + * Intrinsic functions are functions built in to the compiler, usually to take + * advantage of specific CPU features that are inefficient to handle via + * external functions. The compiler's optimizer and code generator are fully + * integrated in with intrinsic functions, bringing to bear their full power on + * them. This can result in some surprising speedups. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Walter Bright + */ +module std.intrinsic; + + +/** + * 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 std.intrinsic; + * + * 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
+ * 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 std.intrinsic; + +int main() +{ + uint array[2]; + + array[0] = 2; + array[1] = 0x100; + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bts(array, 35) = %d\n", bts(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btr(array, 35) = %d\n", btr(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bt(array, 1) = %d\n", bt(array, 1)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + return 0; +} + * --- + * Output: +
+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
+
+ */ +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 ); diff --git a/import/std/stdarg.di b/import/std/stdarg.di new file mode 100644 index 0000000..8fccb13 --- /dev/null +++ b/import/std/stdarg.di @@ -0,0 +1,32 @@ +/** + * These functions are built-in intrinsics to the compiler. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: David Friedman + */ +module std.stdarg; + +version( GNU ) +{ + private import gcc.builtins; + alias __builtin_va_list va_list; + alias __builtin_va_end va_end; + alias __builtin_va_copy va_copy; +} + +template va_start(T) +{ + void va_start( out va_list ap, inout T parmn ) + { + + } +} + +template va_arg(T) +{ + T va_arg( inout va_list ap ) + { + return T.init; + } +} diff --git a/import/stdc/complex.d b/import/stdc/complex.d new file mode 100644 index 0000000..5211c8d --- /dev/null +++ b/import/stdc/complex.d @@ -0,0 +1,99 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.complex; + +extern (C): + +cdouble cacos(cdouble z); +cfloat cacosf(cfloat z); +creal cacosl(creal z); + +cdouble casin(cdouble z); +cfloat casinf(cfloat z); +creal casinl(creal z); + +cdouble catan(cdouble z); +cfloat catanf(cfloat z); +creal catanl(creal z); + +cdouble ccos(cdouble z); +cfloat ccosf(cfloat z); +creal ccosl(creal z); + +cdouble csin(cdouble z); +cfloat csinf(cfloat z); +creal csinl(creal z); + +cdouble ctan(cdouble z); +cfloat ctanf(cfloat z); +creal ctanl(creal z); + +cdouble cacosh(cdouble z); +cfloat cacoshf(cfloat z); +creal cacoshl(creal z); + +cdouble casinh(cdouble z); +cfloat casinhf(cfloat z); +creal casinhl(creal z); + +cdouble catanh(cdouble z); +cfloat catanhf(cfloat z); +creal catanhl(creal z); + +cdouble ccosh(cdouble z); +cfloat ccoshf(cfloat z); +creal ccoshl(creal z); + +cdouble csinh(cdouble z); +cfloat csinhf(cfloat z); +creal csinhl(creal z); + +cdouble ctanh(cdouble z); +cfloat ctanhf(cfloat z); +creal ctanhl(creal z); + +cdouble cexp(cdouble z); +cfloat cexpf(cfloat z); +creal cexpl(creal z); + +cdouble clog(cdouble z); +cfloat clogf(cfloat z); +creal clogl(creal z); + + double cabs(cdouble z); + float cabsf(cfloat z); + real cabsl(creal z); + +cdouble cpow(cdouble x, cdouble y); +cfloat cpowf(cfloat x, cfloat y); +creal cpowl(creal x, creal y); + +cdouble csqrt(cdouble z); +cfloat csqrtf(cfloat z); +creal csqrtl(creal z); + + double carg(cdouble z); + float cargf(cfloat z); + real cargl(creal z); + + double cimag(cdouble z); + float cimagf(cfloat z); + real cimagl(creal z); + +cdouble conj(cdouble z); +cfloat conjf(cfloat z); +creal conjl(creal z); + +cdouble cproj(cdouble z); +cfloat cprojf(cfloat z); +creal cprojl(creal z); + +// double creal(cdouble z); + float crealf(cfloat z); + real creall(creal z); diff --git a/import/stdc/config.d b/import/stdc/config.d new file mode 100644 index 0000000..09859cd --- /dev/null +++ b/import/stdc/config.d @@ -0,0 +1,30 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.config; + +extern (C): + +version( Windows ) +{ + alias int c_long; + alias uint c_ulong; +} +else +{ + static if( (void*).sizeof > int.sizeof ) + { + alias long c_long; + alias ulong c_ulong; + } + else + { + alias int c_long; + alias uint c_ulong; + } +} diff --git a/import/stdc/ctype.d b/import/stdc/ctype.d new file mode 100644 index 0000000..1b9c07b --- /dev/null +++ b/import/stdc/ctype.d @@ -0,0 +1,26 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.ctype; + +extern (C): + +int isalnum(int c); +int isalpha(int c); +int isblank(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int ispunct(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); +int tolower(int c); +int toupper(int c); diff --git a/import/stdc/errno.d b/import/stdc/errno.d new file mode 100644 index 0000000..0d78d1d --- /dev/null +++ b/import/stdc/errno.d @@ -0,0 +1,375 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.errno; + +private +{ + extern (C) int getErrno(); + extern (C) int setErrno(int); +} + +int errno() { return getErrno(); } +int errno( int val ) { return setErrno( val ); } + +extern (C): + +version( Windows ) +{ + const EPERM = 1; // Operation not permitted + const ENOENT = 2; // No such file or directory + const ESRCH = 3; // No such process + const EINTR = 4; // Interrupted system call + const EIO = 5; // I/O error + const ENXIO = 6; // No such device or address + const E2BIG = 7; // Argument list too long + const ENOEXEC = 8; // Exec format error + const EBADF = 9; // Bad file number + const ECHILD = 10; // No child processes + const EAGAIN = 11; // Try again + const ENOMEM = 12; // Out of memory + const EACCES = 13; // Permission denied + const EFAULT = 14; // Bad address + const EBUSY = 16; // Device or resource busy + const EEXIST = 17; // File exists + const EXDEV = 18; // Cross-device link + const ENODEV = 19; // No such device + const ENOTDIR = 20; // Not a directory + const EISDIR = 21; // Is a directory + const EINVAL = 22; // Invalid argument + const ENFILE = 23; // File table overflow + const EMFILE = 24; // Too many open files + const ENOTTY = 25; // Not a typewriter + const EFBIG = 27; // File too large + const ENOSPC = 28; // No space left on device + const ESPIPE = 29; // Illegal seek + const EROFS = 30; // Read-only file system + const EMLINK = 31; // Too many links + const EPIPE = 32; // Broken pipe + const EDOM = 33; // Math argument out of domain of func + const ERANGE = 34; // Math result not representable + const EDEADLK = 36; // Resource deadlock would occur + const ENAMETOOLONG = 38; // File name too long + const ENOLCK = 39; // No record locks available + const ENOSYS = 40; // Function not implemented + const ENOTEMPTY = 41; // Directory not empty + const EILSEQ = 42; // Illegal byte sequence + const EDEADLOCK = EDEADLK; +} +else version( linux ) +{ + const EPERM = 1; // Operation not permitted + const ENOENT = 2; // No such file or directory + const ESRCH = 3; // No such process + const EINTR = 4; // Interrupted system call + const EIO = 5; // I/O error + const ENXIO = 6; // No such device or address + const E2BIG = 7; // Argument list too long + const ENOEXEC = 8; // Exec format error + const EBADF = 9; // Bad file number + const ECHILD = 10; // No child processes + const EAGAIN = 11; // Try again + const ENOMEM = 12; // Out of memory + const EACCES = 13; // Permission denied + const EFAULT = 14; // Bad address + const ENOTBLK = 15; // Block device required + const EBUSY = 16; // Device or resource busy + const EEXIST = 17; // File exists + const EXDEV = 18; // Cross-device link + const ENODEV = 19; // No such device + const ENOTDIR = 20; // Not a directory + const EISDIR = 21; // Is a directory + const EINVAL = 22; // Invalid argument + const ENFILE = 23; // File table overflow + const EMFILE = 24; // Too many open files + const ENOTTY = 25; // Not a typewriter + const ETXTBSY = 26; // Text file busy + const EFBIG = 27; // File too large + const ENOSPC = 28; // No space left on device + const ESPIPE = 29; // Illegal seek + const EROFS = 30; // Read-only file system + const EMLINK = 31; // Too many links + const EPIPE = 32; // Broken pipe + const EDOM = 33; // Math argument out of domain of func + const ERANGE = 34; // Math result not representable + const EDEADLK = 35; // Resource deadlock would occur + const ENAMETOOLONG = 36; // File name too long + const ENOLCK = 37; // No record locks available + const ENOSYS = 38; // Function not implemented + const ENOTEMPTY = 39; // Directory not empty + const ELOOP = 40; // Too many symbolic links encountered + const EWOULDBLOCK = EAGAIN; // Operation would block + const ENOMSG = 42; // No message of desired type + const EIDRM = 43; // Identifier removed + const ECHRNG = 44; // Channel number out of range + const EL2NSYNC = 45; // Level 2 not synchronized + const EL3HLT = 46; // Level 3 halted + const EL3RST = 47; // Level 3 reset + const ELNRNG = 48; // Link number out of range + const EUNATCH = 49; // Protocol driver not attached + const ENOCSI = 50; // No CSI structure available + const EL2HLT = 51; // Level 2 halted + const EBADE = 52; // Invalid exchange + const EBADR = 53; // Invalid request descriptor + const EXFULL = 54; // Exchange full + const ENOANO = 55; // No anode + const EBADRQC = 56; // Invalid request code + const EBADSLT = 57; // Invalid slot + const EDEADLOCK = EDEADLK; + const EBFONT = 59; // Bad font file format + const ENOSTR = 60; // Device not a stream + const ENODATA = 61; // No data available + const ETIME = 62; // Timer expired + const ENOSR = 63; // Out of streams resources + const ENONET = 64; // Machine is not on the network + const ENOPKG = 65; // Package not installed + const EREMOTE = 66; // Object is remote + const ENOLINK = 67; // Link has been severed + const EADV = 68; // Advertise error + const ESRMNT = 69; // Srmount error + const ECOMM = 70; // Communication error on send + const EPROTO = 71; // Protocol error + const EMULTIHOP = 72; // Multihop attempted + const EDOTDOT = 73; // RFS specific error + const EBADMSG = 74; // Not a data message + const EOVERFLOW = 75; // Value too large for defined data type + const ENOTUNIQ = 76; // Name not unique on network + const EBADFD = 77; // File descriptor in bad state + const EREMCHG = 78; // Remote address changed + const ELIBACC = 79; // Can not access a needed shared library + const ELIBBAD = 80; // Accessing a corrupted shared library + const ELIBSCN = 81; // .lib section in a.out corrupted + const ELIBMAX = 82; // Attempting to link in too many shared libraries + const ELIBEXEC = 83; // Cannot exec a shared library directly + const EILSEQ = 84; // Illegal byte sequence + const ERESTART = 85; // Interrupted system call should be restarted + const ESTRPIPE = 86; // Streams pipe error + const EUSERS = 87; // Too many users + const ENOTSOCK = 88; // Socket operation on non-socket + const EDESTADDRREQ = 89; // Destination address required + const EMSGSIZE = 90; // Message too long + const EPROTOTYPE = 91; // Protocol wrong type for socket + const ENOPROTOOPT = 92; // Protocol not available + const EPROTONOSUPPORT = 93; // Protocol not supported + const ESOCKTNOSUPPORT = 94; // Socket type not supported + const EOPNOTSUPP = 95; // Operation not supported on transport endpoint + const EPFNOSUPPORT = 96; // Protocol family not supported + const EAFNOSUPPORT = 97; // Address family not supported by protocol + const EADDRINUSE = 98; // Address already in use + const EADDRNOTAVAIL = 99; // Cannot assign requested address + const ENETDOWN = 100; // Network is down + const ENETUNREACH = 101; // Network is unreachable + const ENETRESET = 102; // Network dropped connection because of reset + const ECONNABORTED = 103; // Software caused connection abort + const ECONNRESET = 104; // Connection reset by peer + const ENOBUFS = 105; // No buffer space available + const EISCONN = 106; // Transport endpoint is already connected + const ENOTCONN = 107; // Transport endpoint is not connected + const ESHUTDOWN = 108; // Cannot send after transport endpoint shutdown + const ETOOMANYREFS = 109; // Too many references: cannot splice + const ETIMEDOUT = 110; // Connection timed out + const ECONNREFUSED = 111; // Connection refused + const EHOSTDOWN = 112; // Host is down + const EHOSTUNREACH = 113; // No route to host + const EALREADY = 114; // Operation already in progress + const EINPROGRESS = 115; // Operation now in progress + const ESTALE = 116; // Stale NFS file handle + const EUCLEAN = 117; // Structure needs cleaning + const ENOTNAM = 118; // Not a XENIX named type file + const ENAVAIL = 119; // No XENIX semaphores available + const EISNAM = 120; // Is a named type file + const EREMOTEIO = 121; // Remote I/O error + const EDQUOT = 122; // Quota exceeded + const ENOMEDIUM = 123; // No medium found + const EMEDIUMTYPE = 124; // Wrong medium type + const ECANCELED = 125; // Operation Canceled + const ENOKEY = 126; // Required key not available + const EKEYEXPIRED = 127; // Key has expired + const EKEYREVOKED = 128; // Key has been revoked + const EKEYREJECTED = 129; // Key was rejected by service + const EOWNERDEAD = 130; // Owner died + const ENOTRECOVERABLE = 131; // State not recoverable +} +else version( darwin ) +{ + const EPERM = 1; // Operation not permitted + const ENOENT = 2; // No such file or directory + const ESRCH = 3; // No such process + const EINTR = 4; // Interrupted system call + const EIO = 5; // Input/output error + const ENXIO = 6; // Device not configured + const E2BIG = 7; // Argument list too long + const ENOEXEC = 8; // Exec format error + const EBADF = 9; // Bad file descriptor + const ECHILD = 10; // No child processes + const EDEADLK = 11; // Resource deadlock avoided + const ENOMEM = 12; // Cannot allocate memory + const EACCES = 13; // Permission denied + const EFAULT = 14; // Bad address + const EBUSY = 16; // Device busy + const EEXIST = 17; // File exists + const EXDEV = 18; // Cross-device link + const ENODEV = 19; // Operation not supported by device + const ENOTDIR = 20; // Not a directory + const EISDIR = 21; // Is a directory + const EINVAL = 22; // Invalid argument + const ENFILE = 23; // Too many open files in system + const EMFILE = 24; // Too many open files + const ENOTTY = 25; // Inappropriate ioctl for device + const ETXTBSY = 26; // Text file busy + const EFBIG = 27; // File too large + const ENOSPC = 28; // No space left on device + const ESPIPE = 29; // Illegal seek + const EROFS = 30; // Read-only file system + const EMLINK = 31; // Too many links + const EPIPE = 32; // Broken pipe + const EDOM = 33; // Numerical argument out of domain + const ERANGE = 34; // Result too large + const EAGAIN = 35; // Resource temporarily unavailable + const EWOULDBLOCK = EAGAIN; // Operation would block + const EINPROGRESS = 36; // Operation now in progress + const EALREADY = 37; // Operation already in progress + const ENOTSOCK = 38; // Socket operation on non-socket + const EDESTADDRREQ = 39; // Destination address required + const EMSGSIZE = 40; // Message too long + const EPROTOTYPE = 41; // Protocol wrong type for socket + const ENOPROTOOPT = 42; // Protocol not available + const EPROTONOSUPPORT = 43; // Protocol not supported + const ENOTSUP = 45; // Operation not supported + const EOPNOTSUPP = ENOTSUP; // Operation not supported on socket + const EAFNOSUPPORT = 47; // Address family not supported by protocol family + const EADDRINUSE = 48; // Address already in use + const EADDRNOTAVAIL = 49; // Can't assign requested address + const ENETDOWN = 50; // Network is down + const ENETUNREACH = 51; // Network is unreachable + const ENETRESET = 52; // Network dropped connection on reset + const ECONNABORTED = 53; // Software caused connection abort + const ECONNRESET = 54; // Connection reset by peer + const ENOBUFS = 55; // No buffer space available + const EISCONN = 56; // Socket is already connected + const ENOTCONN = 57; // Socket is not connected + const ETIMEDOUT = 60; // Operation timed out + const ECONNREFUSED = 61; // Connection refused + const ELOOP = 62; // Too many levels of symbolic links + const ENAMETOOLONG = 63; // File name too long + const EHOSTUNREACH = 65; // No route to host + const ENOTEMPTY = 66; // Directory not empty + const EDQUOT = 69; // Disc quota exceeded + const ESTALE = 70; // Stale NFS file handle + const ENOLCK = 77; // No locks available + const ENOSYS = 78; // Function not implemented + const EOVERFLOW = 84; // Value too large to be stored in data type + const ECANCELED = 89; // Operation canceled + const EIDRM = 90; // Identifier removed + const ENOMSG = 91; // No message of desired type + const EILSEQ = 92; // Illegal byte sequence + const EBADMSG = 94; // Bad message + const EMULTIHOP = 95; // Reserved + const ENODATA = 96; // No message available on STREAM + const ENOLINK = 97; // Reserved + const ENOSR = 98; // No STREAM resources + const ENOSTR = 99; // Not a STREAM + const EPROTO = 100; // Protocol error + const ETIME = 101; // STREAM ioctl timeout + const ELAST = 101; // Must be equal largest errno +} +else version( freebsd ) +{ + const EPERM = 1; // Operation not permitted + const ENOENT = 2; // No such file or directory + const ESRCH = 3; // No such process + const EINTR = 4; // Interrupted system call + const EIO = 5; // Input/output error + const ENXIO = 6; // Device not configured + const E2BIG = 7; // Argument list too long + const ENOEXEC = 8; // Exec format error + const EBADF = 9; // Bad file descriptor + const ECHILD = 10; // No child processes + const EDEADLK = 11; // Resource deadlock avoided + const ENOMEM = 12; // Cannot allocate memory + const EACCES = 13; // Permission denied + const EFAULT = 14; // Bad address + const ENOTBLK = 15; // Block device required + const EBUSY = 16; // Device busy + const EEXIST = 17; // File exists + const EXDEV = 18; // Cross-device link + const ENODEV = 19; // Operation not supported by device + const ENOTDIR = 20; // Not a directory + const EISDIR = 21; // Is a directory + const EINVAL = 22; // Invalid argument + const ENFILE = 23; // Too many open files in system + const EMFILE = 24; // Too many open files + const ENOTTY = 25; // Inappropriate ioctl for device + const ETXTBSY = 26; // Text file busy + const EFBIG = 27; // File too large + const ENOSPC = 28; // No space left on device + const ESPIPE = 29; // Illegal seek + const EROFS = 30; // Read-only file system + const EMLINK = 31; // Too many links + const EPIPE = 32; // Broken pipe + const EDOM = 33; // Numerical argument out of domain + const ERANGE = 34; // Result too large + const EAGAIN = 35; // Resource temporarily unavailable + const EWOULDBLOCK = EAGAIN; // Operation would block + const EINPROGRESS = 36; // Operation now in progress + const EALREADY = 37; // Operation already in progress + const ENOTSOCK = 38; // Socket operation on non-socket + const EDESTADDRREQ = 39; // Destination address required + const EMSGSIZE = 40; // Message too long + const EPROTOTYPE = 41; // Protocol wrong type for socket + const ENOPROTOOPT = 42; // Protocol not available + const EPROTONOSUPPORT = 43; // Protocol not supported + const ENOTSUP = 45; // Operation not supported + const EOPNOTSUPP = ENOTSUP; // Operation not supported on socket + const EAFNOSUPPORT = 47; // Address family not supported by protocol family + const EADDRINUSE = 48; // Address already in use + const EADDRNOTAVAIL = 49; // Can't assign requested address + const ENETDOWN = 50; // Network is down + const ENETUNREACH = 51; // Network is unreachable + const ENETRESET = 52; // Network dropped connection on reset + const ECONNABORTED = 53; // Software caused connection abort + const ECONNRESET = 54; // Connection reset by peer + const ENOBUFS = 55; // No buffer space available + const EISCONN = 56; // Socket is already connected + const ENOTCONN = 57; // Socket is not connected + const ESHUTDOWN = 58; // Can't send after socket shutdown + const ETOOMANYREFS = 59; // Too many refrences; can't splice + const ETIMEDOUT = 60; // Operation timed out + const ECONNREFUSED = 61; // Connection refused + const ELOOP = 62; // Too many levels of symbolic links + const ENAMETOOLONG = 63; // File name too long + const EHOSTUNREACH = 65; // No route to host + const ENOTEMPTY = 66; // Directory not empty + const EPROCLIM = 67; // Too many processes + const EUSERS = 68; // Too many users + const EDQUOT = 69; // Disc quota exceeded + const ESTALE = 70; // Stale NFS file handle + const EREMOTE = 71; // Too many levels of remote in path + const EBADRPC = 72; // RPC struct is bad + const ERPCMISMATCH = 73; // RPC version wrong + const EPROGUNAVAIL = 74; // RPC prog. not avail + const EPROGMISMATCH = 75; // Program version wrong + const EPROCUNAVAIL = 76; // Bad procedure for program + const ENOLCK = 77; // No locks available + const ENOSYS = 78; // Function not implemented + const EFTYPE = 79; // Inappropriate file type or format + const EAUTH = 80; // Authentication error + const ENEEDAUTH = 81; // Need authenticator + const EIDRM = 82; // Itendifier removed + const ENOMSG = 83; // No message of desired type + const EOVERFLOW = 84; // Value too large to be stored in data type + const ECANCELED = 85; // Operation canceled + const EILSEQ = 86; // Illegal byte sequence + const ENOATTR = 87; // Attribute not found + const EDOOFUS = 88; // Programming error + const EBADMSG = 89; // Bad message + const EMULTIHOP = 90; // Multihop attempted + const ENOLINK = 91; // Link has been severed + const EPROTO = 92; // Protocol error + const ELAST = 92; // Must be equal largest errno +} diff --git a/import/stdc/fenv.d b/import/stdc/fenv.d new file mode 100644 index 0000000..8b2dd8c --- /dev/null +++ b/import/stdc/fenv.d @@ -0,0 +1,132 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly, Walter Bright + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.fenv; + +extern (C): + +version( Windows ) +{ + struct fenv_t + { + ushort status; + ushort control; + ushort round; + ushort[2] reserved; + } + + alias int fexcept_t; +} +else version( linux ) +{ + struct fenv_t + { + ushort __control_word; + ushort __unused1; + ushort __status_word; + ushort __unused2; + ushort __tags; + ushort __unused3; + uint __eip; + ushort __cs_selector; + ushort __opcode; + uint __data_offset; + ushort __data_selector; + ushort __unused5; + } + + alias int fexcept_t; +} +else version ( darwin ) +{ + version ( BigEndian ) + { + alias uint fenv_t; + alias uint fexcept_t; + } + version ( LittleEndian ) + { + struct fenv_t + { + ushort __control; + ushort __status; + uint __mxcsr; + byte[8] __reserved; + } + + alias ushort fexcept_t; + } +} +else version ( freebsd ) +{ + struct fenv_t + { + ushort __control; + ushort __mxcsr_hi; + ushort __status; + ushort __mxcsr_lo; + uint __tag; + byte[16] __other; + } + + alias ushort fexcept_t; +} +else +{ + static assert( false ); +} + +enum +{ + FE_INVALID = 1, + FE_DENORMAL = 2, // non-standard + FE_DIVBYZERO = 4, + FE_OVERFLOW = 8, + FE_UNDERFLOW = 0x10, + FE_INEXACT = 0x20, + FE_ALL_EXCEPT = 0x3F, + FE_TONEAREST = 0, + FE_UPWARD = 0x800, + FE_DOWNWARD = 0x400, + FE_TOWARDZERO = 0xC00, +} + +version( Windows ) +{ + private extern fenv_t _FE_DFL_ENV; + fenv_t* FE_DFL_ENV = &_FE_DFL_ENV; +} +else version( linux ) +{ + fenv_t* FE_DFL_ENV = cast(fenv_t*)(-1); +} +else version( darwin ) +{ + private extern fenv_t _FE_DFL_ENV; + fenv_t* FE_DFL_ENV = &_FE_DFL_ENV; +} +else +{ + static assert( false ); +} + +void feraiseexcept(int excepts); +void feclearexcept(int excepts); + +int fetestexcept(int excepts); +int feholdexcept(fenv_t* envp); + +void fegetexceptflag(fexcept_t* flagp, int excepts); +void fesetexceptflag(in fexcept_t* flagp, int excepts); + +int fegetround(); +int fesetround(int round); + +void fegetenv(fenv_t* envp); +void fesetenv(in fenv_t* envp); +void feupdateenv(in fenv_t* envp); diff --git a/import/stdc/inttypes.d b/import/stdc/inttypes.d new file mode 100644 index 0000000..7acaa74 --- /dev/null +++ b/import/stdc/inttypes.d @@ -0,0 +1,252 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.inttypes; + +public import stdc.stddef; +public import stdc.stdint; + +extern (C): + +struct imaxdiv_t +{ + intmax_t quot, + rem; +} + +version( VerboseC ) +{ + const char* PRId8 = "hhd"; + const char* PRId16 = "hd"; + const char* PRId32 = "ld"; + const char* PRId64 = "lld"; + + const char* PRIdLEAST8 = "hhd"; + const char* PRIdLEAST16 = "hd"; + const char* PRIdLEAST32 = "ld"; + const char* PRIdLEAST64 = "lld"; + + const char* PRIdFAST8 = "hhd"; + const char* PRIdFAST16 = "d"; + const char* PRIdFAST32 = "ld"; + const char* PRIdFAST64 = "lld"; + + const char* PRIi8 = "hhi"; + const char* PRIi16 = "hi"; + const char* PRIi32 = "li"; + const char* PRIi64 = "lli"; + + const char* PRIiLEAST8 = "hhi"; + const char* PRIiLEAST16 = "hi"; + const char* PRIiLEAST32 = "li"; + const char* PRIiLEAST64 = "lli"; + + const char* PRIiFAST8 = "hhi"; + const char* PRIiFAST16 = "i"; + const char* PRIiFAST32 = "li"; + const char* PRIiFAST64 = "lli"; + + const char* PRIo8 = "hho"; + const char* PRIo16 = "ho"; + const char* PRIo32 = "lo"; + const char* PRIo64 = "llo"; + + const char* PRIoLEAST8 = "hho"; + const char* PRIoLEAST16 = "ho"; + const char* PRIoLEAST32 = "lo"; + const char* PRIoLEAST64 = "llo"; + + const char* PRIoFAST8 = "hho"; + const char* PRIoFAST16 = "o"; + const char* PRIoFAST32 = "lo"; + const char* PRIoFAST64 = "llo"; + + const char* PRIu8 = "hhu"; + const char* PRIu16 = "hu"; + const char* PRIu32 = "lu"; + const char* PRIu64 = "llu"; + + const char* PRIuLEAST8 = "hhu"; + const char* PRIuLEAST16 = "hu"; + const char* PRIuLEAST32 = "lu"; + const char* PRIuLEAST64 = "llu"; + + const char* PRIuFAST8 = "hhu"; + const char* PRIuFAST16 = "u"; + const char* PRIuFAST32 = "lu"; + const char* PRIuFAST64 = "llu"; + + const char* PRIx8 = "hhx"; + const char* PRIx16 = "hx"; + const char* PRIx32 = "lx"; + const char* PRIx64 = "llx"; + + const char* PRIxLEAST8 = "hhx"; + const char* PRIxLEAST16 = "hx"; + const char* PRIxLEAST32 = "lx"; + const char* PRIxLEAST64 = "llx"; + + const char* PRIxFAST8 = "hhx"; + const char* PRIxFAST16 = "x"; + const char* PRIxFAST32 = "lx"; + const char* PRIxFAST64 = "llx"; + + const char* PRIX8 = "hhX"; + const char* PRIX16 = "hX"; + const char* PRIX32 = "lX"; + const char* PRIX64 = "llX"; + + const char* PRIXLEAST8 = "hhX"; + const char* PRIXLEAST16 = "hX"; + const char* PRIXLEAST32 = "lX"; + const char* PRIXLEAST64 = "llX"; + + const char* PRIXFAST8 = "hhX"; + const char* PRIXFAST16 = "X"; + const char* PRIXFAST32 = "lX"; + const char* PRIXFAST64 = "llX"; + + const char* SCNd8 = "hhd"; + const char* SCNd16 = "hd"; + const char* SCNd32 = "ld"; + const char* SCNd64 = "lld"; + + const char* SCNdLEAST8 = "hhd"; + const char* SCNdLEAST16 = "hd"; + const char* SCNdLEAST32 = "ld"; + const char* SCNdLEAST64 = "lld"; + + const char* SCNdFAST8 = "hhd"; + const char* SCNdFAST16 = "d"; + const char* SCNdFAST32 = "ld"; + const char* SCNdFAST64 = "lld"; + + const char* SCNi8 = "hhd"; + const char* SCNi16 = "hi"; + const char* SCNi32 = "li"; + const char* SCNi64 = "lli"; + + const char* SCNiLEAST8 = "hhd"; + const char* SCNiLEAST16 = "hi"; + const char* SCNiLEAST32 = "li"; + const char* SCNiLEAST64 = "lli"; + + const char* SCNiFAST8 = "hhd"; + const char* SCNiFAST16 = "i"; + const char* SCNiFAST32 = "li"; + const char* SCNiFAST64 = "lli"; + + const char* SCNo8 = "hhd"; + const char* SCNo16 = "ho"; + const char* SCNo32 = "lo"; + const char* SCNo64 = "llo"; + + const char* SCNoLEAST8 = "hhd"; + const char* SCNoLEAST16 = "ho"; + const char* SCNoLEAST32 = "lo"; + const char* SCNoLEAST64 = "llo"; + + const char* SCNoFAST8 = "hhd"; + const char* SCNoFAST16 = "o"; + const char* SCNoFAST32 = "lo"; + const char* SCNoFAST64 = "llo"; + + const char* SCNu8 = "hhd"; + const char* SCNu16 = "hu"; + const char* SCNu32 = "lu"; + const char* SCNu64 = "llu"; + + const char* SCNuLEAST8 = "hhd"; + const char* SCNuLEAST16 = "hu"; + const char* SCNuLEAST32 = "lu"; + const char* SCNuLEAST64 = "llu"; + + const char* SCNuFAST8 = "hhd"; + const char* SCNuFAST16 = "u"; + const char* SCNuFAST32 = "lu"; + const char* SCNuFAST64 = "llu"; + + const char* SCNx8 = "hhd"; + const char* SCNx16 = "hx"; + const char* SCNx32 = "lx"; + const char* SCNx64 = "llx"; + + const char* SCNxLEAST8 = "hhd"; + const char* SCNxLEAST16 = "hx"; + const char* SCNxLEAST32 = "lx"; + const char* SCNxLEAST64 = "llx"; + + const char* SCNxFAST8 = "hhd"; + const char* SCNxFAST16 = "x"; + const char* SCNxFAST32 = "lx"; + const char* SCNxFAST64 = "llx"; + + version( X86_64 ) + { + const char* PRIdMAX = PRId64; + const char* PRIiMAX = PRIi64; + const char* PRIoMAX = PRIo64; + const char* PRIuMAX = PRIu64; + const char* PRIxMAX = PRIx64; + const char* PRIXMAX = PRIX64; + + const char* SCNdMAX = SCNd64; + const char* SCNiMAX = SCNi64; + const char* SCNoMAX = SCNo64; + const char* SCNuMAX = SCNu64; + const char* SCNxMAX = SCNx64; + + const char* PRIdPTR = PRId64; + const char* PRIiPTR = PRIi64; + const char* PRIoPTR = PRIo64; + const char* PRIuPTR = PRIu64; + const char* PRIxPTR = PRIx64; + const char* PRIXPTR = PRIX64; + + const char* SCNdPTR = SCNd64; + const char* SCNiPTR = SCNi64; + const char* SCNoPTR = SCNo64; + const char* SCNuPTR = SCNu64; + const char* SCNxPTR = SCNx64; + } + else + { + const char* PRIdMAX = PRId32; + const char* PRIiMAX = PRIi32; + const char* PRIoMAX = PRIo32; + const char* PRIuMAX = PRIu32; + const char* PRIxMAX = PRIx32; + const char* PRIXMAX = PRIX32; + + const char* SCNdMAX = SCNd32; + const char* SCNiMAX = SCNi32; + const char* SCNoMAX = SCNo32; + const char* SCNuMAX = SCNu32; + const char* SCNxMAX = SCNx32; + + const char* PRIdPTR = PRId32; + const char* PRIiPTR = PRIi32; + const char* PRIoPTR = PRIo32; + const char* PRIuPTR = PRIu32; + const char* PRIxPTR = PRIx32; + const char* PRIXPTR = PRIX32; + + const char* SCNdPTR = SCNd32; + const char* SCNiPTR = SCNi32; + const char* SCNoPTR = SCNo32; + const char* SCNuPTR = SCNu32; + const char* SCNxPTR = SCNx32; + } +} + +intmax_t imaxabs(intmax_t j); +imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom); +intmax_t strtoimax(in char* nptr, char** endptr, int base); +uintmax_t strtoumax(in char* nptr, char** endptr, int base); +intmax_t wcstoimax(in wchar_t* nptr, wchar_t** endptr, int base); +uintmax_t wcstoumax(in wchar_t* nptr, wchar_t** endptr, int base); diff --git a/import/stdc/limits.d b/import/stdc/limits.d new file mode 100644 index 0000000..106d1c7 --- /dev/null +++ b/import/stdc/limits.d @@ -0,0 +1,33 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.limits; + +private import stdc.config; + +extern (C): + +const CHAR_BIT = 8; +const SCHAR_MIN = byte.min; +const SCHAR_MAX = byte.max; +const UCHAR_MAX = ubyte.min; +const CHAR_MIN = char.max; +const CHAR_MAX = char.max; +const MB_LEN_MAX = 2; +const SHRT_MIN = short.min; +const SHRT_MAX = short.max; +const USHRT_MAX = ushort.max; +const INT_MIN = int.min; +const INT_MAX = int.max; +const UINT_MAX = uint.max; +const LONG_MIN = c_long.min; +const LONG_MAX = c_long.max; +const ULONG_MAX = c_ulong.max; +const LLONG_MIN = long.min; +const LLONG_MAX = long.max; +const ULLONG_MAX = ulong.max; diff --git a/import/stdc/locale.d b/import/stdc/locale.d new file mode 100644 index 0000000..c81092b --- /dev/null +++ b/import/stdc/locale.d @@ -0,0 +1,55 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.locale; + +extern (C): + +struct lconv +{ + char* decimal_point; + char* thousands_sep; + char* grouping; + char* int_curr_symbol; + char* currency_symbol; + char* mon_decimal_point; + char* mon_thousands_sep; + char* mon_grouping; + char* positive_sign; + char* negative_sign; + byte int_frac_digits; + byte frac_digits; + byte p_cs_precedes; + byte p_sep_by_space; + byte n_cs_precedes; + byte n_sep_by_space; + byte p_sign_posn; + byte n_sign_posn; + byte int_p_cs_precedes; + byte int_p_sep_by_space; + byte int_n_cs_precedes; + byte int_n_sep_by_space; + byte int_p_sign_posn; + byte int_n_sign_posn; +} + +const LC_CTYPE = 0; +const LC_NUMERIC = 1; +const LC_TIME = 2; +const LC_COLLATE = 3; +const LC_MONETARY = 4; +const LC_ALL = 6; +const LC_PAPER = 7; +const LC_NAME = 8; +const LC_ADDRESS = 9; +const LC_TELEPHONE = 10; +const LC_MEASUREMENT = 11; +const LC_IDENTIFICATION = 12; + +char* setlocale(int category, in char* locale); +lconv* localeconv(); diff --git a/import/stdc/math.d b/import/stdc/math.d new file mode 100644 index 0000000..3baa33a --- /dev/null +++ b/import/stdc/math.d @@ -0,0 +1,691 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly, Walter Bright + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.math; + +private import stdc.config; + +extern (C): + +alias float float_t; +alias double double_t; + +const double HUGE_VAL = double.infinity; +const double HUGE_VALF = float.infinity; +const double HUGE_VALL = real.infinity; + +const float INFINITY = float.infinity; +const float NAN = float.nan; + +const int FP_ILOGB0 = int.min; +const int FP_ILOGBNAN = int.min; + +const int MATH_ERRNO = 1; +const int MATH_ERREXCEPT = 2; +const int math_errhandling = MATH_ERRNO | MATH_ERREXCEPT; + +version( none ) +{ + // + // these functions are all macros in C + // + + //int fpclassify(real-floating x); + int fpclassify(float x); + int fpclassify(double x); + int fpclassify(real x); + + //int isfinite(real-floating x); + int isfinite(float x); + int isfinite(double x); + int isfinite(real x); + + //int isinf(real-floating x); + int isinf(float x); + int isinf(double x); + int isinf(real x); + + //int isnan(real-floating x); + int isnan(float x); + int isnan(double x); + int isnan(real x); + + //int isnormal(real-floating x); + int isnormal(float x); + int isnormal(double x); + int isnormal(real x); + + //int signbit(real-floating x); + int signbit(float x); + int signbit(double x); + int signbit(real x); + + //int isgreater(real-floating x, real-floating y); + int isgreater(float x, float y); + int isgreater(double x, double y); + int isgreater(real x, real y); + + //int isgreaterequal(real-floating x, real-floating y); + int isgreaterequal(float x, float y); + int isgreaterequal(double x, double y); + int isgreaterequal(real x, real y); + + //int isless(real-floating x, real-floating y); + int isless(float x, float y); + int isless(double x, double y); + int isless(real x, real y); + + //int islessequal(real-floating x, real-floating y); + int islessequal(float x, float y); + int islessequal(double x, double y); + int islessequal(real x, real y); + + //int islessgreater(real-floating x, real-floating y); + int islessgreater(float x, float y); + int islessgreater(double x, double y); + int islessgreater(real x, real y); + + //int isunordered(real-floating x, real-floating y); + int isunordered(float x, float y); + int isunordered(double x, double y); + int isunordered(real x, real y); +} + +version( DigitalMars ) version( Windows ) + version = DigitalMarsWin32; + +version( DigitalMarsWin32 ) +{ + enum + { + FP_NANS = 0, + FP_NANQ = 1, + FP_INFINITE = 2, + FP_NORMAL = 3, + FP_SUBNORMAL = 4, + FP_ZERO = 5, + FP_NAN = FP_NANQ, + FP_EMPTY = 6, + FP_UNSUPPORTED = 7, + } + + enum + { + FP_FAST_FMA = 0, + FP_FAST_FMAF = 0, + FP_FAST_FMAL = 0, + } + + uint __fpclassify_f(float x); + uint __fpclassify_d(double x); + uint __fpclassify_ld(real x); + + extern (D) + { + //int fpclassify(real-floating x); + int fpclassify(float x) { return __fpclassify_f(x); } + int fpclassify(double x) { return __fpclassify_d(x); } + int fpclassify(real x) + { + return (real.sizeof == double.sizeof) + ? __fpclassify_d(x) + : __fpclassify_ld(x); + } + + //int isfinite(real-floating x); + int isfinite(float x) { return fpclassify(x) >= FP_NORMAL; } + int isfinite(double x) { return fpclassify(x) >= FP_NORMAL; } + int isfinite(real x) { return fpclassify(x) >= FP_NORMAL; } + + //int isinf(real-floating x); + int isinf(float x) { return fpclassify(x) == FP_INFINITE; } + int isinf(double x) { return fpclassify(x) == FP_INFINITE; } + int isinf(real x) { return fpclassify(x) == FP_INFINITE; } + + //int isnan(real-floating x); + int isnan(float x) { return fpclassify(x) <= FP_NANQ; } + int isnan(double x) { return fpclassify(x) <= FP_NANQ; } + int isnan(real x) { return fpclassify(x) <= FP_NANQ; } + + //int isnormal(real-floating x); + int isnormal(float x) { return fpclassify(x) == FP_NORMAL; } + int isnormal(double x) { return fpclassify(x) == FP_NORMAL; } + int isnormal(real x) { return fpclassify(x) == FP_NORMAL; } + + //int signbit(real-floating x); + int signbit(float x) { return (cast(short*)&(x))[1] & 0x8000; } + int signbit(double x) { return (cast(short*)&(x))[3] & 0x8000; } + int signbit(real x) + { + return (real.sizeof == double.sizeof) + ? (cast(short*)&(x))[3] & 0x8000 + : (cast(short*)&(x))[4] & 0x8000; + } + } +} +else version( linux ) +{ + enum + { + FP_NAN, + FP_INFINITE, + FP_ZERO, + FP_SUBNORMAL, + FP_NORMAL, + } + + enum + { + FP_FAST_FMA = 0, + FP_FAST_FMAF = 0, + FP_FAST_FMAL = 0, + } + + int __fpclassifyf(float x); + int __fpclassify(double x); + int __fpclassifyl(real x); + + int __finitef(float x); + int __finite(double x); + int __finitel(real x); + + int __isinff(float x); + int __isinf(double x); + int __isinfl(real x); + + int __isnanf(float x); + int __isnan(double x); + int __isnanl(real x); + + int __signbitf(float x); + int __signbit(double x); + int __signbitl(real x); + + extern (D) + { + //int fpclassify(real-floating x); + int fpclassify(float x) { return __fpclassifyf(x); } + int fpclassify(double x) { return __fpclassify(x); } + int fpclassify(real x) + { + return (real.sizeof == double.sizeof) + ? __fpclassify(x) + : __fpclassifyl(x); + } + + //int isfinite(real-floating x); + int isfinite(float x) { return __finitef(x); } + int isfinite(double x) { return __finite(x); } + int isfinite(real x) + { + return (real.sizeof == double.sizeof) + ? __finite(x) + : __finitel(x); + } + + //int isinf(real-floating x); + int isinf(float x) { return __isinff(x); } + int isinf(double x) { return __isinf(x); } + int isinf(real x) + { + return (real.sizeof == double.sizeof) + ? __isinf(x) + : __isinfl(x); + } + + //int isnan(real-floating x); + int isnan(float x) { return __isnanf(x); } + int isnan(double x) { return __isnan(x); } + int isnan(real x) + { + return (real.sizeof == double.sizeof) + ? __isnan(x) + : __isnanl(x); + } + + //int isnormal(real-floating x); + int isnormal(float x) { return fpclassify(x) == FP_NORMAL; } + int isnormal(double x) { return fpclassify(x) == FP_NORMAL; } + int isnormal(real x) { return fpclassify(x) == FP_NORMAL; } + + //int signbit(real-floating x); + int signbit(float x) { return __signbitf(x); } + int signbit(double x) { return __signbit(x); } + int signbit(real x) + { + return (real.sizeof == double.sizeof) + ? __signbit(x) + : __signbitl(x); + } + } +} +else version( darwin ) +{ + enum + { + FP_NAN = 1, + FP_INFINITE = 2, + FP_ZERO = 3, + FP_NORMAL = 4, + FP_SUBNORMAL = 5, + FP_SUPERNORMAL = 6 + } + + enum + { + FP_FAST_FMA = 0, + FP_FAST_FMAF = 0, + FP_FAST_FMAL = 0, + } + + int __fpclassifyf(float x); + int __fpclassifyd(double x); + int __fpclassify(real x); + + int __isfinitef(float x); + int __isfinited(double x); + int __isfinite(real x); + + int __isinff(float x); + int __isinfd(double x); + int __isinf(real x); + + int __isnanf(float x); + int __isnand(double x); + int __isnan(real x); + + int __signbitf(float x); + int __signbitd(double x); + int __signbitl(real x); + + extern (D) + { + //int fpclassify(real-floating x); + int fpclassify(float x) { return __fpclassifyf(x); } + int fpclassify(double x) { return __fpclassifyd(x); } + int fpclassify(real x) + { + return (real.sizeof == double.sizeof) + ? __fpclassifyd(x) + : __fpclassify(x); + } + + //int isfinite(real-floating x); + int isfinite(float x) { return __isfinitef(x); } + int isfinite(double x) { return __isfinited(x); } + int isfinite(real x) + { + return (real.sizeof == double.sizeof) + ? __isfinited(x) + : __isfinite(x); + } + + //int isinf(real-floating x); + int isinf(float x) { return __isinff(x); } + int isinf(double x) { return __isinfd(x); } + int isinf(real x) + { + return (real.sizeof == double.sizeof) + ? __isinfd(x) + : __isinf(x); + } + + //int isnan(real-floating x); + int isnan(float x) { return __isnanf(x); } + int isnan(double x) { return __isnand(x); } + int isnan(real x) + { + return (real.sizeof == double.sizeof) + ? __isnand(x) + : __isnan(x); + } + + //int isnormal(real-floating x); + int isnormal(float x) { return fpclassify(x) == FP_NORMAL; } + int isnormal(double x) { return fpclassify(x) == FP_NORMAL; } + int isnormal(real x) { return fpclassify(x) == FP_NORMAL; } + + //int signbit(real-floating x); + int signbit(float x) { return __signbitf(x); } + int signbit(double x) { return __signbitd(x); } + int signbit(real x) + { + return (real.sizeof == double.sizeof) + ? __signbitd(x) + : __signbitl(x); + } + } +} +else version( freebsd ) +{ + enum + { + FP_INFINITE = 0x01, + FP_NAN = 0x02, + FP_NORMAL = 0x04, + FP_SUBNORMAL = 0x08, + FP_ZERO = 0x10 + } + + enum + { + FP_FAST_FMA = 0, + FP_FAST_FMAF = 0, + FP_FAST_FMAL = 0, + } + + int __fpclassifyd(double); + int __fpclassifyf(float); + int __fpclassifyl(real); + int __isfinitef(float); + int __isfinite(double); + int __isfinitel(real); + int __isinff(float); + int __isinfl(real); + int __isnanl(real); + int __isnormalf(float); + int __isnormal(double); + int __isnormall(real); + int __signbit(double); + int __signbitf(float); + int __signbitl(real); + + extern (D) + { + //int fpclassify(real-floating x); + int fpclassify(float x) { return __fpclassifyf(x); } + int fpclassify(double x) { return __fpclassifyd(x); } + int fpclassify(real x) { return __fpclassifyl(x); } + + //int isfinite(real-floating x); + int isfinite(float x) { return __isfinitef(x); } + int isfinite(double x) { return __isfinite(x); } + int isfinite(double x) { return __isfinitel(x); } + + //int isinf(real-floating x); + int isinf(float x) { return __isinff(x); } + int isinf(double x) { return __isinfl(x); } + int isinf(real x) { return __isinfl(x); } + + //int isnan(real-floating x); + int isnan(float x) { return __isnanl(x); } + int isnan(double x) { return __isnanl(x); } + int isnan(real x) { return __isnanl(x); } + + //int isnormal(real-floating x); + int isnormal(float x) { return __isnormalf(x); } + int isnormal(double x) { return __isnormal(x); } + int isnormal(real x) { return __isnormall(x); } + + //int signbit(real-floating x); + int signbit(float x) { return __signbitf(x); } + int signbit(double x) { return __signbit(x); } + int signbit(double x) { return __signbit(x); } + } +} + +extern (D) +{ + //int isgreater(real-floating x, real-floating y); + int isgreater(float x, float y) { return !(x !> y); } + int isgreater(double x, double y) { return !(x !> y); } + int isgreater(real x, real y) { return !(x !> y); } + + //int isgreaterequal(real-floating x, real-floating y); + int isgreaterequal(float x, float y) { return !(x !>= y); } + int isgreaterequal(double x, double y) { return !(x !>= y); } + int isgreaterequal(real x, real y) { return !(x !>= y); } + + //int isless(real-floating x, real-floating y); + int isless(float x, float y) { return !(x !< y); } + int isless(double x, double y) { return !(x !< y); } + int isless(real x, real y) { return !(x !< y); } + + //int islessequal(real-floating x, real-floating y); + int islessequal(float x, float y) { return !(x !<= y); } + int islessequal(double x, double y) { return !(x !<= y); } + int islessequal(real x, real y) { return !(x !<= y); } + + //int islessgreater(real-floating x, real-floating y); + int islessgreater(float x, float y) { return !(x !<> y); } + int islessgreater(double x, double y) { return !(x !<> y); } + int islessgreater(real x, real y) { return !(x !<> y); } + + //int isunordered(real-floating x, real-floating y); + int isunordered(float x, float y) { return (x !<>= y); } + int isunordered(double x, double y) { return (x !<>= y); } + int isunordered(real x, real y) { return (x !<>= y); } +} + +double acos(double x); +float acosf(float x); +real acosl(real x); + +double asin(double x); +float asinf(float x); +real asinl(real x); + +double atan(double x); +float atanf(float x); +real atanl(real x); + +double atan2(double y, double x); +float atan2f(float y, float x); +real atan2l(real y, real x); + +double cos(double x); +float cosf(float x); +real cosl(real x); + +double sin(double x); +float sinf(float x); +real sinl(real x); + +double tan(double x); +float tanf(float x); +real tanl(real x); + +double acosh(double x); +float acoshf(float x); +real acoshl(real x); + +double asinh(double x); +float asinhf(float x); +real asinhl(real x); + +double atanh(double x); +float atanhf(float x); +real atanhl(real x); + +double cosh(double x); +float coshf(float x); +real coshl(real x); + +double sinh(double x); +float sinhf(float x); +real sinhl(real x); + +double tanh(double x); +float tanhf(float x); +real tanhl(real x); + +double exp(double x); +float expf(float x); +real expl(real x); + +double exp2(double x); +float exp2f(float x); +real exp2l(real x); + +double expm1(double x); +float expm1f(float x); +real expm1l(real x); + +double frexp(double value, int* exp); +float frexpf(float value, int* exp); +real frexpl(real value, int* exp); + +int ilogb(double x); +int ilogbf(float x); +int ilogbl(real x); + +double ldexp(double x, int exp); +float ldexpf(float x, int exp); +real ldexpl(real x, int exp); + +double log(double x); +float logf(float x); +real logl(real x); + +double log10(double x); +float log10f(float x); +real log10l(real x); + +double log1p(double x); +float log1pf(float x); +real log1pl(real x); + +double log2(double x); +float log2f(float x); +real log2l(real x); + +double logb(double x); +float logbf(float x); +real logbl(real x); + +double modf(double value, double* iptr); +float modff(float value, float* iptr); +real modfl(real value, real *iptr); + +double scalbn(double x, int n); +float scalbnf(float x, int n); +real scalbnl(real x, int n); + +double scalbln(double x, c_long n); +float scalblnf(float x, c_long n); +real scalblnl(real x, c_long n); + +double cbrt(double x); +float cbrtf(float x); +real cbrtl(real x); + +double fabs(double x); +float fabsf(float x); +real fabsl(real x); + +double hypot(double x, double y); +float hypotf(float x, float y); +real hypotl(real x, real y); + +double pow(double x, double y); +float powf(float x, float y); +real powl(real x, real y); + +double sqrt(double x); +float sqrtf(float x); +real sqrtl(real x); + +double erf(double x); +float erff(float x); +real erfl(real x); + +double erfc(double x); +float erfcf(float x); +real erfcl(real x); + +double lgamma(double x); +float lgammaf(float x); +real lgammal(real x); + +double tgamma(double x); +float tgammaf(float x); +real tgammal(real x); + +double ceil(double x); +float ceilf(float x); +real ceill(real x); + +double floor(double x); +float floorf(float x); +real floorl(real x); + +double nearbyint(double x); +float nearbyintf(float x); +real nearbyintl(real x); + +double rint(double x); +float rintf(float x); +real rintl(real x); + +c_long lrint(double x); +c_long lrintf(float x); +c_long lrintl(real x); + +long llrint(double x); +long llrintf(float x); +long llrintl(real x); + +double round(double x); +float roundf(float x); +real roundl(real x); + +c_long lround(double x); +c_long lroundf(float x); +c_long lroundl(real x); + +long llround(double x); +long llroundf(float x); +long llroundl(real x); + +double trunc(double x); +float truncf(float x); +real truncl(real x); + +double fmod(double x, double y); +float fmodf(float x, float y); +real fmodl(real x, real y); + +double remainder(double x, double y); +float remainderf(float x, float y); +real remainderl(real x, real y); + +double remquo(double x, double y, int* quo); +float remquof(float x, float y, int* quo); +real remquol(real x, real y, int* quo); + +double copysign(double x, double y); +float copysignf(float x, float y); +real copysignl(real x, real y); + +double nan(in char* tagp); +float nanf(in char* tagp); +real nanl(in char* tagp); + +double nextafter(double x, double y); +float nextafterf(float x, float y); +real nextafterl(real x, real y); + +double nexttoward(double x, real y); +float nexttowardf(float x, real y); +real nexttowardl(real x, real y); + +double fdim(double x, double y); +float fdimf(float x, float y); +real fdiml(real x, real y); + +double fmax(double x, double y); +float fmaxf(float x, float y); +real fmaxl(real x, real y); + +double fmin(double x, double y); +float fminf(float x, float y); +real fminl(real x, real y); + +double fma(double x, double y, double z); +float fmaf(float x, float y, float z); +real fmal(real x, real y, real z); diff --git a/import/stdc/posix/arpa/inet.d b/import/stdc/posix/arpa/inet.d new file mode 100644 index 0000000..f4ab250 --- /dev/null +++ b/import/stdc/posix/arpa/inet.d @@ -0,0 +1,127 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.arpa.inet; + +private import stdc.posix.config; +public import stdc.inttypes : uint32_t, uint16_t; +public import stdc.posix.sys.socket : socklen_t; + +extern (C): + +// +// Required +// +/* +in_port_t // from stdc.posix.netinet.in_ +in_addr_t // from stdc.posix.netinet.in_ + +struct in_addr // from stdc.posix.netinet.in_ +INET_ADDRSTRLEN // from stdc.posix.netinet.in_ + +uint32_t // from stdc.inttypes +uint16_t // from stdc.inttypes + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +in_addr_t inet_addr(in char*); +char* inet_ntoa(in_addr); +// per spec: const char* inet_ntop(int, const void*, char*, socklen_t); +char* inet_ntop(int, in void*, char*, socklen_t); +int inet_pton(int, in char*, void*); +*/ + +version( linux ) +{ + alias uint16_t in_port_t; + alias uint32_t in_addr_t; + + struct in_addr + { + in_addr_t s_addr; + } + + const INET_ADDRSTRLEN = 16; + + uint32_t htonl(uint32_t); + uint16_t htons(uint16_t); + uint32_t ntohl(uint32_t); + uint16_t ntohs(uint16_t); + + in_addr_t inet_addr(in char*); + char* inet_ntoa(in_addr); + char* inet_ntop(int, in void*, char*, socklen_t); + int inet_pton(int, in char*, void*); +} +else version( darwin ) +{ + alias uint16_t in_port_t; // TODO: verify + alias uint32_t in_addr_t; // TODO: verify + + struct in_addr + { + in_addr_t s_addr; + } + + const INET_ADDRSTRLEN = 16; + + uint32_t htonl(uint32_t); + uint16_t htons(uint16_t); + uint32_t ntohl(uint32_t); + uint16_t ntohs(uint16_t); + + in_addr_t inet_addr(in char*); + char* inet_ntoa(in_addr); + char* inet_ntop(int, in void*, char*, socklen_t); + int inet_pton(int, in char*, void*); +} +else version( freebsd ) +{ + alias uint16_t in_port_t; // TODO: verify + alias uint32_t in_addr_t; // TODO: verify + + struct in_addr + { + in_addr_t s_addr; + } + + const INET_ADDRSTRLEN = 16; + + uint32_t htonl(uint32_t); + uint16_t htons(uint16_t); + uint32_t ntohl(uint32_t); + uint16_t ntohs(uint16_t); + + in_addr_t inet_addr(in char*); + char* inet_ntoa(in_addr); + char* inet_ntop(int, in void*, char*, socklen_t); + int inet_pton(int, in char*, void*); +} + +// +// IPV6 (IP6) +// +/* +INET6_ADDRSTRLEN // from stdc.posix.netinet.in_ +*/ + +version( linux ) +{ + const INET6_ADDRSTRLEN = 46; +} +else version( darwin ) +{ + const INET6_ADDRSTRLEN = 46; +} +else version( freebsd ) +{ + const INET6_ADDRSTRLEN = 46; +} diff --git a/import/stdc/posix/config.d b/import/stdc/posix/config.d new file mode 100644 index 0000000..c3a4485 --- /dev/null +++ b/import/stdc/posix/config.d @@ -0,0 +1,27 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.config; + +public import stdc.config; + +extern (C): + +version( linux ) +{ + version( none /* X86_64 */ ) + { + const bool __USE_LARGEFILE64 = true; + } + else + { + const bool __USE_LARGEFILE64 = false; + } + const bool __USE_FILE_OFFSET64 = __USE_LARGEFILE64; + const bool __REDIRECT = false; +} diff --git a/import/stdc/posix/dirent.d b/import/stdc/posix/dirent.d new file mode 100644 index 0000000..c15aaf2 --- /dev/null +++ b/import/stdc/posix/dirent.d @@ -0,0 +1,198 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.dirent; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for ino_t + +extern (C): + +// +// Required +// +/* +DIR + +struct dirent +{ + char[] d_name; +} + +int closedir(DIR*); +DIR* opendir(in char*); +dirent* readdir(DIR*); +void rewinddir(DIR*); +*/ + +version( linux ) +{ + // NOTE: The following constants are non-standard Linux definitions + // for dirent.d_type. + enum + { + DT_UNKNOWN = 0, + DT_FIFO = 1, + DT_CHR = 2, + DT_DIR = 4, + DT_BLK = 6, + DT_REG = 8, + DT_LNK = 10, + DT_SOCK = 12, + DT_WHT = 14 + } + + struct dirent + { + ino_t d_ino; + off_t d_off; + ushort d_reclen; + ubyte d_type; + char[256] d_name; + } + + struct DIR + { + // Managed by OS + } + + static if( __USE_LARGEFILE64 ) + { + dirent* readdir64(DIR*); + alias readdir64 readdir; + } + else + { + dirent* readdir(DIR*); + } +} +else version( darwin ) +{ + enum + { + DT_UNKNOWN = 0, + DT_FIFO = 1, + DT_CHR = 2, + DT_DIR = 4, + DT_BLK = 6, + DT_REG = 8, + DT_LNK = 10, + DT_SOCK = 12, + DT_WHT = 14 + } + + align(4) + struct dirent + { + ino_t d_ino; + ushort d_reclen; + ubyte d_type; + ubyte d_namlen; + char[256] d_name; + } + + struct DIR + { + // Managed by OS + } + + dirent* readdir(DIR*); +} +else version( freebsd ) +{ + enum + { + DT_UNKNOWN = 0, + DT_FIFO = 1, + DT_CHR = 2, + DT_DIR = 4, + DT_BLK = 6, + DT_REG = 8, + DT_LNK = 10, + DT_SOCK = 12, + DT_WHT = 14 + } + + align(4) + struct dirent + { + uint d_fileno; + ushort d_reclen; + ubyte d_type; + ubyte d_namelen; + char[256] d_name; + } + + struct _telldir; + struct DIR + { + int dd_fd; + c_long dd_loc; + c_long dd_size; + char* dd_buf; + int dd_len; + c_long dd_seek; + c_long dd_rewind; + int dd_flags; + void* dd_lock; + _telldir* dd_td; + } + + dirent* readdir(DIR*); +} +else +{ + dirent* readdir(DIR*); +} + +int closedir(DIR*); +DIR* opendir(in char*); +//dirent* readdir(DIR*); +void rewinddir(DIR*); + +// +// Thread-Safe Functions (TSF) +// +/* +int readdir_r(DIR*, dirent*, dirent**); +*/ + +version( linux ) +{ + static if( __USE_LARGEFILE64 ) + { + int readdir_r64(DIR*, dirent*, dirent**); + alias readdir_r64 readdir_r; + } + else + { + int readdir_r(DIR*, dirent*, dirent**); + } +} +else version( darwin ) +{ + int readdir_r(DIR*, dirent*, dirent**); +} +else version( freebsd ) +{ + int readdir_r(DIR*, dirent*, dirent**); +} + +// +// XOpen (XSI) +// +/* +void seekdir(DIR*, c_long); +c_long telldir(DIR*); +*/ + +version( linux ) +{ + void seekdir(DIR*, c_long); + c_long telldir(DIR*); +} diff --git a/import/stdc/posix/dlfcn.d b/import/stdc/posix/dlfcn.d new file mode 100644 index 0000000..2858413 --- /dev/null +++ b/import/stdc/posix/dlfcn.d @@ -0,0 +1,65 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.dlfcn; + +private import stdc.posix.config; + +extern (C): + +// +// XOpen (XSI) +// +/* +RTLD_LAZY +RTLD_NOW +RTLD_GLOBAL +RTLD_LOCAL + +int dlclose(void*); +char* dlerror(); +void* dlopen(in char*, int); +void* dlsym(void*, in char*); +*/ + +version( linux ) +{ + const RTLD_LAZY = 0x00001; + const RTLD_NOW = 0x00002; + const RTLD_GLOBAL = 0x00100; + const RTLD_LOCAL = 0x00000; + + int dlclose(void*); + char* dlerror(); + void* dlopen(in char*, int); + void* dlsym(void*, in char*); +} +else version( darwin ) +{ + const RTLD_LAZY = 0x00001; + const RTLD_NOW = 0x00002; + const RTLD_GLOBAL = 0x00100; + const RTLD_LOCAL = 0x00000; + + int dlclose(void*); + char* dlerror(); + void* dlopen(in char*, int); + void* dlsym(void*, in char*); +} +else version( freebsd ) +{ + const RTLD_LAZY = 1; + const RTLD_NOW = 2; + const RTLD_GLOBAL = 0x100; + const RTLD_LOCAL = 0; + + int dlclose(void*); + char* dlerror(); + void* dlopen(in char*, int); + void* dlsym(void*, in char*); +} diff --git a/import/stdc/posix/fcntl.d b/import/stdc/posix/fcntl.d new file mode 100644 index 0000000..f66d1a1 --- /dev/null +++ b/import/stdc/posix/fcntl.d @@ -0,0 +1,248 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.fcntl; + +private import stdc.posix.config; +private import stdc.stdint; +public import stdc.stddef; // for size_t +public import stdc.posix.sys.types; // for off_t, mode_t +public import stdc.posix.sys.stat; // for S_IFMT, etc. + +extern (C): + +// +// Required +// +/* +F_DUPFD +F_GETFD +F_SETFD +F_GETFL +F_SETFL +F_GETLK +F_SETLK +F_SETLKW +F_GETOWN +F_SETOWN + +FD_CLOEXEC + +F_RDLCK +F_UNLCK +F_WRLCK + +O_CREAT +O_EXCL +O_NOCTTY +O_TRUNC + +O_APPEND +O_DSYNC +O_NONBLOCK +O_RSYNC +O_SYNC + +O_ACCMODE +O_RDONLY +O_RDWR +O_WRONLY + +struct flock +{ + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +} + +int creat(in char*, mode_t); +int fcntl(int, int, ...); +int open(in char*, int, ...); +*/ +version( linux ) +{ + const F_DUPFD = 0; + const F_GETFD = 1; + const F_SETFD = 2; + const F_GETFL = 3; + const F_SETFL = 4; + static if( __USE_FILE_OFFSET64 ) + { + const F_GETLK = 12; + const F_SETLK = 13; + const F_SETLKW = 14; + } + else + { + const F_GETLK = 5; + const F_SETLK = 6; + const F_SETLKW = 7; + } + const F_GETOWN = 9; + const F_SETOWN = 8; + + const FD_CLOEXEC = 1; + + const F_RDLCK = 0; + const F_UNLCK = 2; + const F_WRLCK = 1; + + const O_CREAT = 0100; + const O_EXCL = 0200; + const O_NOCTTY = 0400; + const O_TRUNC = 01000; + + const O_APPEND = 02000; + const O_NONBLOCK = 04000; + const O_SYNC = 010000; + const O_DSYNC = O_SYNC; + const O_RSYNC = O_SYNC; + + const O_ACCMODE = 0003; + const O_RDONLY = 00; + const O_WRONLY = 01; + const O_RDWR = 02; + + struct flock + { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; + } + + static if( __USE_LARGEFILE64 ) + { + int creat64(in char*, mode_t); + alias creat64 creat; + + int open64(in char*, int, ...); + alias open64 open; + } + else + { + int creat(in char*, mode_t); + int open(in char*, int, ...); + } +} +else version( darwin ) +{ + const F_DUPFD = 0; + const F_GETFD = 1; + const F_SETFD = 2; + const F_GETFL = 3; + const F_SETFL = 4; + const F_GETOWN = 5; + const F_SETOWN = 6; + const F_GETLK = 7; + const F_SETLK = 8; + const F_SETLKW = 9; + + const FD_CLOEXEC = 1; + + const F_RDLCK = 1; + const F_UNLCK = 2; + const F_WRLCK = 3; + + const O_CREAT = 0x0200; + const O_EXCL = 0x0800; + const O_NOCTTY = 0; + const O_TRUNC = 0x0400; + + const O_RDONLY = 0x0000; + const O_WRONLY = 0x0001; + const O_RDWR = 0x0002; + const O_ACCMODE = 0x0003; + + const O_NONBLOCK = 0x0004; + const O_APPEND = 0x0008; + const O_SYNC = 0x0080; + //const O_DSYNC + //const O_RSYNC + + struct flock + { + off_t l_start; + off_t l_len; + pid_t l_pid; + short l_type; + short l_whence; + } + + int creat(in char*, mode_t); + int open(in char*, int, ...); +} +else version( freebsd ) +{ + const F_DUPFD = 0; + const F_GETFD = 1; + const F_SETFD = 2; + const F_GETFL = 3; + const F_SETFL = 4; + const F_GETOWN = 5; + const F_SETOWN = 6; + const F_GETLK = 7; + const F_SETLK = 8; + const F_SETLKW = 9; + + const FD_CLOEXEC = 1; + + const F_RDLCK = 1; + const F_UNLCK = 2; + const F_WRLCK = 3; + + const O_CREAT = 0x0200; + const O_EXCL = 0x0800; + const O_NOCTTY = 0; + const O_TRUNC = 0x0400; + + const O_RDONLY = 0x0000; + const O_WRONLY = 0x0001; + const O_RDWR = 0x0002; + const O_ACCMODE = 0x0003; + + const O_NONBLOCK = 0x0004; + const O_APPEND = 0x0008; + const O_SYNC = 0x0080; + //const O_DSYNC + //const O_RSYNC + + struct flock + { + off_t l_start; + off_t l_len; + pid_t l_pid; + short l_type; + short l_whence; + } + + int creat(in char*, mode_t); + int open(in char*, int, ...); +} + +//int creat(in char*, mode_t); +int fcntl(int, int, ...); +//int open(in char*, int, ...); + +// +// Advisory Information (ADV) +// +/* +POSIX_FADV_NORMAL +POSIX_FADV_SEQUENTIAL +POSIX_FADV_RANDOM +POSIX_FADV_WILLNEED +POSIX_FADV_DONTNEED +POSIX_FADV_NOREUSE + +int posix_fadvise(int, off_t, off_t, int); +int posix_fallocate(int, off_t, off_t); +*/ diff --git a/import/stdc/posix/inttypes.d b/import/stdc/posix/inttypes.d new file mode 100644 index 0000000..7925e7f --- /dev/null +++ b/import/stdc/posix/inttypes.d @@ -0,0 +1,30 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.inttypes; + +private import stdc.posix.config; +public import stdc.inttypes; + +// +// Required +// +/* +intmax_t imaxabs(intmax_t); +imaxdiv_t imaxdiv(intmax_t, intmax_t); +intmax_t strtoimax(in char*, char**, int); +uintmax_t strtoumax(in char *, char**, int); +intmax_t wcstoimax(in wchar_t*, wchar_t**, int); +uintmax_t wcstoumax(in wchar_t*, wchar_t**, int); +*/ +intmax_t imaxabs(intmax_t); +imaxdiv_t imaxdiv(intmax_t, intmax_t); +intmax_t strtoimax(in char*, char**, int); +uintmax_t strtoumax(in char *, char**, int); +intmax_t wcstoimax(in wchar_t*, wchar_t**, int); +uintmax_t wcstoumax(in wchar_t*, wchar_t**, int); diff --git a/import/stdc/posix/net/if_.d b/import/stdc/posix/net/if_.d new file mode 100644 index 0000000..2724c14 --- /dev/null +++ b/import/stdc/posix/net/if_.d @@ -0,0 +1,77 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.net.if_; + +private import stdc.posix.config; + +extern (C): + +// +// Required +// +/* +struct if_nameindex // renamed to if_nameindex_t +{ + uint if_index; + char* if_name; +} + +IF_NAMESIZE + +uint if_nametoindex(in char*); +char* if_indextoname(uint, char*); +if_nameindex_t* if_nameindex(); +void if_freenameindex(if_nameindex_t*); +*/ + +version( linux ) +{ + struct if_nameindex_t + { + uint if_index; + char* if_name; + } + + const IF_NAMESIZE = 16; + + uint if_nametoindex(in char*); + char* if_indextoname(uint, char*); + if_nameindex_t* if_nameindex(); + void if_freenameindex(if_nameindex_t*); +} +else version( darwin ) +{ + struct if_nameindex_t + { + uint if_index; + char* if_name; + } + + const IF_NAMESIZE = 16; + + uint if_nametoindex(in char*); + char* if_indextoname(uint, char*); + if_nameindex_t* if_nameindex(); + void if_freenameindex(if_nameindex_t*); +} +else version( freebsd ) +{ + struct if_nameindex_t + { + uint if_index; + char* if_name; + } + + const IF_NAMESIZE = 16; + + uint if_nametoindex(in char*); + char* if_indextoname(uint, char*); + if_nameindex_t* if_nameindex(); + void if_freenameindex(if_nameindex_t*); +} diff --git a/import/stdc/posix/netinet/in_.d b/import/stdc/posix/netinet/in_.d new file mode 100644 index 0000000..237ead4 --- /dev/null +++ b/import/stdc/posix/netinet/in_.d @@ -0,0 +1,327 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.netinet.in_; + +private import stdc.posix.config; +public import stdc.inttypes : uint32_t, uint16_t, uint8_t; +public import stdc.posix.arpa.inet; +public import stdc.posix.sys.socket; // for sa_family_t + +extern (C): + +// +// Required +// +/* +NOTE: The following must must be defined in stdc.posix.arpa.inet to break + a circular import: in_port_t, in_addr_t, struct in_addr, INET_ADDRSTRLEN. + +in_port_t +in_addr_t + +sa_family_t // from stdc.posix.sys.socket +uint8_t // from stdc.inttypes +uint32_t // from stdc.inttypes + +struct in_addr +{ + in_addr_t s_addr; +} + +struct sockaddr_in +{ + sa_family_t sin_family; + in_port_t sin_port; + in_addr sin_addr; +} + +IPPROTO_IP +IPPROTO_ICMP +IPPROTO_TCP +IPPROTO_UDP + +INADDR_ANY +INADDR_BROADCAST + +INET_ADDRSTRLEN + +htonl() // from stdc.posix.arpa.inet +htons() // from stdc.posix.arpa.inet +ntohl() // from stdc.posix.arpa.inet +ntohs() // from stdc.posix.arpa.inet +*/ + +version( linux ) +{ + private const __SOCK_SIZE__ = 16; + + struct sockaddr_in + { + sa_family_t sin_family; + in_port_t sin_port; + in_addr sin_addr; + + /* Pad to size of `struct sockaddr'. */ + ubyte[__SOCK_SIZE__ - sa_family_t.sizeof - + in_port_t.sizeof - in_addr.sizeof] __pad; + } + + enum + { + IPPROTO_IP = 0, + IPPROTO_ICMP = 1, + IPPROTO_TCP = 6, + IPPROTO_UDP = 17 + } + + const uint INADDR_ANY = 0x00000000; + const uint INADDR_BROADCAST = 0xffffffff; +} +else version( darwin ) +{ + private const __SOCK_SIZE__ = 16; + + struct sockaddr_in + { + ubyte sin_len; + sa_family_t sin_family; + in_port_t sin_port; + in_addr sin_addr; + ubyte[8] sin_zero; + } + + enum + { + IPPROTO_IP = 0, + IPPROTO_ICMP = 1, + IPPROTO_TCP = 6, + IPPROTO_UDP = 17 + } + + const uint INADDR_ANY = 0x00000000; + const uint INADDR_BROADCAST = 0xffffffff; +} +else version( freebsd ) +{ + private const __SOCK_SIZE__ = 16; + + struct sockaddr_in + { + ubyte sin_len; + sa_family_t sin_family; + in_port_t sin_port; + in_addr sin_addr; + ubyte[8] sin_zero; + } + + enum + { + IPPROTO_IP = 0, + IPPROTO_ICMP = 1, + IPPROTO_TCP = 6, + IPPROTO_UDP = 17 + } + + const uint INADDR_ANY = 0x00000000; + const uint INADDR_BROADCAST = 0xffffffff; +} + + +// +// IPV6 (IP6) +// +/* +NOTE: The following must must be defined in stdc.posix.arpa.inet to break + a circular import: INET6_ADDRSTRLEN. + +struct in6_addr +{ + uint8_t[16] s6_addr; +} + +struct sockaddr_in6 +{ + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + in6_addr sin6_addr; + uint32_t sin6_scope_id; +} + +extern in6_addr in6addr_any; +extern in6_addr in6addr_loopback; + +struct ipv6_mreq +{ + in6_addr ipv6mr_multiaddr; + uint ipv6mr_interface; +} + +IPPROTO_IPV6 + +INET6_ADDRSTRLEN + +IPV6_JOIN_GROUP +IPV6_LEAVE_GROUP +IPV6_MULTICAST_HOPS +IPV6_MULTICAST_IF +IPV6_MULTICAST_LOOP +IPV6_UNICAST_HOPS +IPV6_V6ONLY + +// macros +int IN6_IS_ADDR_UNSPECIFIED(in6_addr*) +int IN6_IS_ADDR_LOOPBACK(in6_addr*) +int IN6_IS_ADDR_MULTICAST(in6_addr*) +int IN6_IS_ADDR_LINKLOCAL(in6_addr*) +int IN6_IS_ADDR_SITELOCAL(in6_addr*) +int IN6_IS_ADDR_V4MAPPED(in6_addr*) +int IN6_IS_ADDR_V4COMPAT(in6_addr*) +int IN6_IS_ADDR_MC_NODELOCAL(in6_addr*) +int IN6_IS_ADDR_MC_LINKLOCAL(in6_addr*) +int IN6_IS_ADDR_MC_SITELOCAL(in6_addr*) +int IN6_IS_ADDR_MC_ORGLOCAL(in6_addr*) +int IN6_IS_ADDR_MC_GLOBAL(in6_addr*) +*/ + +version ( linux ) +{ + struct in6_addr + { + union + { + uint8_t[16] s6_addr; + uint16_t[8] s6_addr16; + uint32_t[4] s6_addr32; + } + } + + struct sockaddr_in6 + { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + in6_addr sin6_addr; + uint32_t sin6_scope_id; + } + + extern in6_addr in6addr_any; + extern in6_addr in6addr_loopback; + + struct ipv6_mreq + { + in6_addr ipv6mr_multiaddr; + uint ipv6mr_interface; + } + + enum : uint + { + IPPROTO_IPV6 = 41, + + INET6_ADDRSTRLEN = 46, + + IPV6_JOIN_GROUP = 20, + IPV6_LEAVE_GROUP = 21, + IPV6_MULTICAST_HOPS = 18, + IPV6_MULTICAST_IF = 17, + IPV6_MULTICAST_LOOP = 19, + IPV6_UNICAST_HOPS = 16, + IPV6_V6ONLY = 26 + } + + // macros + extern (D) int IN6_IS_ADDR_UNSPECIFIED( in6_addr* addr ) + { + return (cast(uint32_t*) addr)[0] == 0 && + (cast(uint32_t*) addr)[1] == 0 && + (cast(uint32_t*) addr)[2] == 0 && + (cast(uint32_t*) addr)[3] == 0; + } + + extern (D) int IN6_IS_ADDR_LOOPBACK( in6_addr* addr ) + { + return (cast(uint32_t*) addr)[0] == 0 && + (cast(uint32_t*) addr)[1] == 0 && + (cast(uint32_t*) addr)[2] == 0 && + (cast(uint32_t*) addr)[3] == htonl( 1 ); + } + + extern (D) int IN6_IS_ADDR_MULTICAST( in6_addr* addr ) + { + return (cast(uint8_t*) addr)[0] == 0xff; + } + + extern (D) int IN6_IS_ADDR_LINKLOCAL( in6_addr* addr ) + { + return ((cast(uint32_t*) addr)[0] & htonl( 0xffc00000 )) == htonl( 0xfe800000 ); + } + + extern (D) int IN6_IS_ADDR_SITELOCAL( in6_addr* addr ) + { + return ((cast(uint32_t*) addr)[0] & htonl( 0xffc00000 )) == htonl( 0xfec00000 ); + } + + extern (D) int IN6_IS_ADDR_V4MAPPED( in6_addr* addr ) + { + return (cast(uint32_t*) addr)[0] == 0 && + (cast(uint32_t*) addr)[1] == 0 && + (cast(uint32_t*) addr)[2] == htonl( 0xffff ); + } + + extern (D) int IN6_IS_ADDR_V4COMPAT( in6_addr* addr ) + { + return (cast(uint32_t*) addr)[0] == 0 && + (cast(uint32_t*) addr)[1] == 0 && + (cast(uint32_t*) addr)[2] == 0 && + ntohl( (cast(uint32_t*) addr)[3] ) > 1; + } + + extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in6_addr* addr ) + { + return IN6_IS_ADDR_MULTICAST( addr ) && + ((cast(uint8_t*) addr)[1] & 0xf) == 0x1; + } + + extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in6_addr* addr ) + { + return IN6_IS_ADDR_MULTICAST( addr ) && + ((cast(uint8_t*) addr)[1] & 0xf) == 0x2; + } + + extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in6_addr* addr ) + { + return IN6_IS_ADDR_MULTICAST(addr) && + ((cast(uint8_t*) addr)[1] & 0xf) == 0x5; + } + + extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in6_addr* addr ) + { + return IN6_IS_ADDR_MULTICAST( addr) && + ((cast(uint8_t*) addr)[1] & 0xf) == 0x8; + } + + extern (D) int IN6_IS_ADDR_MC_GLOBAL( in6_addr* addr ) + { + return IN6_IS_ADDR_MULTICAST( addr ) && + ((cast(uint8_t*) addr)[1] & 0xf) == 0xe; + } +} + + +// +// Raw Sockets (RS) +// +/* +IPPROTO_RAW +*/ + +version (linux ) +{ + const uint IPPROTO_RAW = 255; +} diff --git a/import/stdc/posix/netinet/tcp.d b/import/stdc/posix/netinet/tcp.d new file mode 100644 index 0000000..4c21625 --- /dev/null +++ b/import/stdc/posix/netinet/tcp.d @@ -0,0 +1,33 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.netinet.tcp; + +private import stdc.posix.config; + +extern (C): + +// +// Required +// +/* +TCP_NODELAY +*/ + +version( linux ) +{ + const TCP_NODELAY = 1; +} +else version( darwin ) +{ + const TCP_NODELAY = 1; +} +else version( freebsd ) +{ + const TCP_NODELAY = 1; +} diff --git a/import/stdc/posix/poll.d b/import/stdc/posix/poll.d new file mode 100644 index 0000000..382d182 --- /dev/null +++ b/import/stdc/posix/poll.d @@ -0,0 +1,133 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.poll; + +private import stdc.posix.config; + +extern (C): + +// +// XOpen (XSI) +// +/* +struct pollfd +{ + int fd; + short events; + short revents; +} + +nfds_t + +POLLIN +POLLRDNORM +POLLRDBAND +POLLPRI +POLLOUT +POLLWRNORM +POLLWRBAND +POLLERR +POLLHUP +POLLNVAL + +int poll(pollfd[], nfds_t, int); +*/ + +version( linux ) +{ + struct pollfd + { + int fd; + short events; + short revents; + } + + alias c_ulong nfds_t; + + const POLLIN = 0x001; + const POLLRDNORM = 0x040; + const POLLRDBAND = 0x080; + const POLLPRI = 0x002; + const POLLOUT = 0x004; + const POLLWRNORM = 0x100; + const POLLWRBAND = 0x200; + const POLLERR = 0x008; + const POLLHUP = 0x010; + const POLLNVAL = 0x020; + + int poll(pollfd*, nfds_t, int); +} +else version( darwin ) +{ + struct pollfd + { + int fd; + short events; + short revents; + }; + + alias uint nfds_t; + + enum + { + POLLIN = 0x0001, + POLLPRI = 0x0002, + POLLOUT = 0x0004, + POLLRDNORM = 0x0040, + POLLWRNORM = POLLOUT, + POLLRDBAND = 0x0080, + POLLWRBAND = 0x0100, + POLLEXTEND = 0x0200, + POLLATTRIB = 0x0400, + POLLNLINK = 0x0800, + POLLWRITE = 0x1000, + POLLERR = 0x0008, + POLLHUP = 0x0010, + POLLNVAL = 0x0020, + + POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND| + POLLWRBAND|POLLERR|POLLHUP|POLLNVAL) + } + + int poll(pollfd*, nfds_t, int); +} +else version( freebsd ) +{ + struct pollfd + { + int fd; + short events; + short revents; + }; + + alias uint nfds_t; + + enum + { + POLLIN = 0x0001, + POLLPRI = 0x0002, + POLLOUT = 0x0004, + POLLRDNORM = 0x0040, + POLLWRNORM = POLLOUT, + POLLRDBAND = 0x0080, + POLLWRBAND = 0x0100, + //POLLEXTEND = 0x0200, + //POLLATTRIB = 0x0400, + //POLLNLINK = 0x0800, + //POLLWRITE = 0x1000, + POLLERR = 0x0008, + POLLHUP = 0x0010, + POLLNVAL = 0x0020, + + POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND| + POLLWRBAND|POLLERR|POLLHUP|POLLNVAL) + } + + int poll(pollfd*, nfds_t, int); +} diff --git a/import/stdc/posix/pthread.d b/import/stdc/posix/pthread.d new file mode 100644 index 0000000..2be0412 --- /dev/null +++ b/import/stdc/posix/pthread.d @@ -0,0 +1,534 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.pthread; + +private import stdc.posix.config; +public import stdc.posix.sys.types; +public import stdc.posix.sched; +public import stdc.posix.time; + +extern (C): + +// +// Required +// +/* +PTHREAD_CANCEL_ASYNCHRONOUS +PTHREAD_CANCEL_ENABLE +PTHREAD_CANCEL_DEFERRED +PTHREAD_CANCEL_DISABLE +PTHREAD_CANCELED +PTHREAD_COND_INITIALIZER +PTHREAD_CREATE_DETACHED +PTHREAD_CREATE_JOINABLE +PTHREAD_EXPLICIT_SCHED +PTHREAD_INHERIT_SCHED +PTHREAD_MUTEX_INITIALIZER +PTHREAD_ONCE_INIT +PTHREAD_PROCESS_SHARED +PTHREAD_PROCESS_PRIVATE + +int pthread_atfork(void function(), void function(), void function()); +int pthread_attr_destroy(pthread_attr_t*); +int pthread_attr_getdetachstate(in pthread_attr_t*, int*); +int pthread_attr_getschedparam(in pthread_attr_t*, sched_param*); +int pthread_attr_init(pthread_attr_t*); +int pthread_attr_setdetachstate(pthread_attr_t*, int); +int pthread_attr_setschedparam(in pthread_attr_t*, sched_param*); +int pthread_cancel(pthread_t); +void pthread_cleanup_push(void function(void*), void*); +void pthread_cleanup_pop(int); +int pthread_cond_broadcast(pthread_cond_t*); +int pthread_cond_destroy(pthread_cond_t*); +int pthread_cond_init(in pthread_cond_t*, pthread_condattr_t*); +int pthread_cond_signal(pthread_cond_t*); +int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, in timespec*); +int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*); +int pthread_condattr_destroy(pthread_condattr_t*); +int pthread_condattr_init(pthread_condattr_t*); +int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*); +int pthread_detach(pthread_t); +int pthread_equal(pthread_t, pthread_t); +void pthread_exit(void*); +void* pthread_getspecific(pthread_key_t); +int pthread_join(pthread_t, void**); +int pthread_key_create(pthread_key_t*, void function(void*)); +int pthread_key_delete(pthread_key_t); +int pthread_mutex_destroy(pthread_mutex_t*); +int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*); +int pthread_mutex_lock(pthread_mutex_t*); +int pthread_mutex_trylock(pthread_mutex_t*); +int pthread_mutex_unlock(pthread_mutex_t*); +int pthread_mutexattr_destroy(pthread_mutexattr_t*); +int pthread_mutexattr_init(pthread_mutexattr_t*); +int pthread_once(pthread_once_t*, void function()); +int pthread_rwlock_destroy(pthread_rwlock_t*); +int pthread_rwlock_init(in pthread_rwlock_t*, pthread_rwlockattr_t*); +int pthread_rwlock_rdlock(pthread_rwlock_t*); +int pthread_rwlock_tryrdlock(pthread_rwlock_t*); +int pthread_rwlock_trywrlock(pthread_rwlock_t*); +int pthread_rwlock_unlock(pthread_rwlock_t*); +int pthread_rwlock_wrlock(pthread_rwlock_t*); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t*); +int pthread_rwlockattr_init(pthread_rwlockattr_t*); +pthread_t pthread_self(); +int pthread_setcancelstate(int, int*); +int pthread_setcanceltype(int, int*); +int pthread_setspecific(pthread_key_t, in void*); +void pthread_testcancel(); +*/ +version( linux ) +{ + enum + { + PTHREAD_CANCEL_ENABLE, + PTHREAD_CANCEL_DISABLE + } + + enum + { + PTHREAD_CANCEL_DEFERRED, + PTHREAD_CANCEL_ASYNCHRONOUS + } + + const PTHREAD_CANCELED = cast(void*) -1; + + //const pthread_mutex_t PTHREAD_COND_INITIALIZER = { __LOCK_ALT_INITIALIZER, 0, "", 0 }; + + enum + { + PTHREAD_CREATE_JOINABLE, + PTHREAD_CREATE_DETACHED + } + + enum + { + PTHREAD_INHERIT_SCHED, + PTHREAD_EXPLICIT_SCHED + } + + //const pthread_mutex_t PTHREAD_MUTEX_INITIALIZER = { 0, 0, null, PTHREAD_MUTEX_NORMAL, { 0, 0 } }; + + const PTHREAD_ONCE_INIT = 0; + + enum + { + PTHREAD_PROCESS_PRIVATE, + PTHREAD_PROCESS_SHARED + } +} +else version( darwin ) +{ + enum + { + PTHREAD_CANCEL_ENABLE = 1, + PTHREAD_CANCEL_DISABLE = 0 + } + + enum + { + PTHREAD_CANCEL_DEFERRED = 2, + PTHREAD_CANCEL_ASYNCHRONOUS = 0 + } + + const PTHREAD_CANCELED = cast(void*) -1; + + //const pthread_mutex_t PTHREAD_COND_INITIALIZER = { __LOCK_ALT_INITIALIZER, 0, "", 0 }; + + enum + { + PTHREAD_CREATE_JOINABLE = 1, + PTHREAD_CREATE_DETACHED = 2 + } + + enum + { + PTHREAD_INHERIT_SCHED = 1, + PTHREAD_EXPLICIT_SCHED = 2 + } + + //const pthread_mutex_t PTHREAD_MUTEX_INITIALIZER = { 0, 0, null, PTHREAD_MUTEX_NORMAL, { 0, 0 } }; + + const PTHREAD_ONCE_INIT = 0; + + enum + { + PTHREAD_PROCESS_PRIVATE = 2, + PTHREAD_PROCESS_SHARED = 1 + } +} + +int pthread_atfork(void function(), void function(), void function()); +int pthread_attr_destroy(pthread_attr_t*); +int pthread_attr_getdetachstate(in pthread_attr_t*, int*); +int pthread_attr_getschedparam(in pthread_attr_t*, sched_param*); +int pthread_attr_init(pthread_attr_t*); +int pthread_attr_setdetachstate(pthread_attr_t*, int); +int pthread_attr_setschedparam(in pthread_attr_t*, sched_param*); +int pthread_cancel(pthread_t); + +version( linux ) +{ + alias void function(void*) _pthread_cleanup_routine; + + struct _pthread_cleanup_buffer + { + _pthread_cleanup_routine __routine; + void* __arg; + int __canceltype; + _pthread_cleanup_buffer* __prev; + } + + void _pthread_cleanup_push(_pthread_cleanup_buffer*, _pthread_cleanup_routine, void*); + void _pthread_cleanup_pop(_pthread_cleanup_buffer*, int); + + struct pthread_cleanup + { + _pthread_cleanup_buffer buffer = void; + + void push()( _pthread_cleanup_routine routine, void* arg ) + { + _pthread_cleanup_push( &buffer, routine, arg ); + } + + void pop()( int execute ) + { + _pthread_cleanup_pop( &buffer, execute ); + } + } +} +else version( darwin ) +{ + alias void function(void*) _pthread_cleanup_routine; + + struct _pthread_cleanup_buffer + { + _pthread_cleanup_routine __routine; + void* __arg; + _pthread_cleanup_buffer* __next; + } + + struct pthread_cleanup + { + _pthread_cleanup_buffer buffer = void; + + void push()( _pthread_cleanup_routine routine, void* arg ) + { + pthread_t self = pthread_self(); + buffer.__routine = routine; + buffer.__arg = arg; + buffer.__next = cast(_pthread_cleanup_buffer*) self.__cleanup_stack; + self.__cleanup_stack = cast(pthread_handler_rec*) &buffer; + } + + void pop()( int execute ) + { + pthread_t self = pthread_self(); + self.__cleanup_stack = cast(pthread_handler_rec*) buffer.__next; + if( execute ) + { + buffer.__routine( buffer.__arg ); + } + } + } +} +else +{ + void pthread_cleanup_push(void function(void*), void*); + void pthread_cleanup_pop(int); +} + +int pthread_cond_broadcast(pthread_cond_t*); +int pthread_cond_destroy(pthread_cond_t*); +int pthread_cond_init(in pthread_cond_t*, pthread_condattr_t*); +int pthread_cond_signal(pthread_cond_t*); +int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, in timespec*); +int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*); +int pthread_condattr_destroy(pthread_condattr_t*); +int pthread_condattr_init(pthread_condattr_t*); +int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*); +int pthread_detach(pthread_t); +int pthread_equal(pthread_t, pthread_t); +void pthread_exit(void*); +void* pthread_getspecific(pthread_key_t); +int pthread_join(pthread_t, void**); +int pthread_key_create(pthread_key_t*, void function(void*)); +int pthread_key_delete(pthread_key_t); +int pthread_mutex_destroy(pthread_mutex_t*); +int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*); +int pthread_mutex_lock(pthread_mutex_t*); +int pthread_mutex_trylock(pthread_mutex_t*); +int pthread_mutex_unlock(pthread_mutex_t*); +int pthread_mutexattr_destroy(pthread_mutexattr_t*); +int pthread_mutexattr_init(pthread_mutexattr_t*); +int pthread_once(pthread_once_t*, void function()); +int pthread_rwlock_destroy(pthread_rwlock_t*); +int pthread_rwlock_init(in pthread_rwlock_t*, pthread_rwlockattr_t*); +int pthread_rwlock_rdlock(pthread_rwlock_t*); +int pthread_rwlock_tryrdlock(pthread_rwlock_t*); +int pthread_rwlock_trywrlock(pthread_rwlock_t*); +int pthread_rwlock_unlock(pthread_rwlock_t*); +int pthread_rwlock_wrlock(pthread_rwlock_t*); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t*); +int pthread_rwlockattr_init(pthread_rwlockattr_t*); +pthread_t pthread_self(); +int pthread_setcancelstate(int, int*); +int pthread_setcanceltype(int, int*); +int pthread_setspecific(pthread_key_t, in void*); +void pthread_testcancel(); + +// +// Barrier (BAR) +// +/* +PTHREAD_BARRIER_SERIAL_THREAD + +int pthread_barrier_destroy(pthread_barrier_t*); +int pthread_barrier_init(pthread_barrier_t*, in pthread_barrierattr_t*, uint); +int pthread_barrier_wait(pthread_barrier_t*); +int pthread_barrierattr_destroy(pthread_barrierattr_t*); +int pthread_barrierattr_getpshared(in pthread_barrierattr_t*, int*); (BAR|TSH) +int pthread_barrierattr_init(pthread_barrierattr_t*); +int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); (BAR|TSH) +*/ + +version( linux ) +{ + const PTHREAD_BARRIER_SERIAL_THREAD = -1; + + int pthread_barrier_destroy(pthread_barrier_t*); + int pthread_barrier_init(pthread_barrier_t*, in pthread_barrierattr_t*, uint); + int pthread_barrier_wait(pthread_barrier_t*); + int pthread_barrierattr_destroy(pthread_barrierattr_t*); + int pthread_barrierattr_getpshared(in pthread_barrierattr_t*, int*); + int pthread_barrierattr_init(pthread_barrierattr_t*); + int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); +} + +// +// Clock (CS) +// +/* +int pthread_condattr_getclock(in pthread_condattr_t*, clockid_t*); +int pthread_condattr_setclock(pthread_condattr_t*, clockid_t); +*/ + +// +// Spinlock (SPI) +// +/* +int pthread_spin_destroy(pthread_spinlock_t*); +int pthread_spin_init(pthread_spinlock_t*, int); +int pthread_spin_lock(pthread_spinlock_t*); +int pthread_spin_trylock(pthread_spinlock_t*); +int pthread_spin_unlock(pthread_spinlock_t*); +*/ + +version( linux ) +{ + int pthread_spin_destroy(pthread_spinlock_t*); + int pthread_spin_init(pthread_spinlock_t*, int); + int pthread_spin_lock(pthread_spinlock_t*); + int pthread_spin_trylock(pthread_spinlock_t*); + int pthread_spin_unlock(pthread_spinlock_t*); +} + +// +// XOpen (XSI) +// +/* +PTHREAD_MUTEX_DEFAULT +PTHREAD_MUTEX_ERRORCHECK +PTHREAD_MUTEX_NORMAL +PTHREAD_MUTEX_RECURSIVE + +int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); +int pthread_attr_setguardsize(pthread_attr_t*, size_t); +int pthread_getconcurrency(); +int pthread_mutexattr_gettype(in pthread_mutexattr_t*, int*); +int pthread_mutexattr_settype(pthread_mutexattr_t*, int); +int pthread_setconcurrency(int); +*/ + +version( linux ) +{ + const PTHREAD_MUTEX_NORMAL = 0; + const PTHREAD_MUTEX_RECURSIVE = 1; + const PTHREAD_MUTEX_ERRORCHECK = 2; + const PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL; + + int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); + int pthread_attr_setguardsize(pthread_attr_t*, size_t); + int pthread_getconcurrency(); + int pthread_mutexattr_gettype(in pthread_mutexattr_t*, int*); + int pthread_mutexattr_settype(pthread_mutexattr_t*, int); + int pthread_setconcurrency(int); +} +else version( darwin ) +{ + const PTHREAD_MUTEX_NORMAL = 0; + const PTHREAD_MUTEX_ERRORCHECK = 1; + const PTHREAD_MUTEX_RECURSIVE = 2; + const PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL; + + int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); + int pthread_attr_setguardsize(pthread_attr_t*, size_t); + int pthread_getconcurrency(); + int pthread_mutexattr_gettype(in pthread_mutexattr_t*, int*); + int pthread_mutexattr_settype(pthread_mutexattr_t*, int); + int pthread_setconcurrency(int); +} + +// +// CPU Time (TCT) +// +/* +int pthread_getcpuclockid(pthread_t, clockid_t*); +*/ + +version( linux ) +{ + int pthread_getcpuclockid(pthread_t, clockid_t*); +} + +// +// Timeouts (TMO) +// +/* +int pthread_mutex_timedlock(pthread_mutex_t*, timespec*); +int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); +int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); +*/ + +version( linux ) +{ + int pthread_mutex_timedlock(pthread_mutex_t*, timespec*); + int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); + int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); +} +else version( darwin ) +{ + int pthread_mutex_timedlock(pthread_mutex_t*, timespec*); + int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); + int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); +} + +// +// Priority (TPI|TPP) +// +/* +PTHREAD_PRIO_INHERIT (TPI) +PTHREAD_PRIO_NONE (TPP|TPI) +PTHREAD_PRIO_PROTECT (TPI) + +int pthread_mutex_getprioceiling(in pthread_mutex_t*, int*); (TPP) +int pthread_mutex_setprioceiling(pthread_mutex_t*, int, int*); (TPP) +int pthread_mutexattr_getprioceiling(pthread_mutexattr_t*, int*); (TPP) +int pthread_mutexattr_getprotocol(in pthread_mutexattr_t*, int*); (TPI|TPP) +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t*, int); (TPP) +int pthread_mutexattr_setprotocol(pthread_mutexattr_t*, int); (TPI|TPP) +*/ + +// +// Scheduling (TPS) +// +/* +PTHREAD_SCOPE_PROCESS +PTHREAD_SCOPE_SYSTEM + +int pthread_attr_getinheritsched(in pthread_attr_t*, int*); +int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); +int pthread_attr_getscope(in pthread_attr_t*, int*); +int pthread_attr_setinheritsched(pthread_attr_t*, int); +int pthread_attr_setschedpolicy(pthread_attr_t*, int); +int pthread_attr_setscope(pthread_attr_t*, int); +int pthread_getschedparam(pthread_t, int*, sched_param*); +int pthread_setschedparam(pthread_t, int, in sched_param*); +int pthread_setschedprio(pthread_t, int); +*/ + +version( linux ) +{ + enum + { + PTHREAD_SCOPE_SYSTEM, + PTHREAD_SCOPE_PROCESS + } + + int pthread_attr_getinheritsched(in pthread_attr_t*, int*); + int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); + int pthread_attr_getscope(in pthread_attr_t*, int*); + int pthread_attr_setinheritsched(pthread_attr_t*, int); + int pthread_attr_setschedpolicy(pthread_attr_t*, int); + int pthread_attr_setscope(pthread_attr_t*, int); + int pthread_getschedparam(pthread_t, int*, sched_param*); + int pthread_setschedparam(pthread_t, int, in sched_param*); + //int pthread_setschedprio(pthread_t, int); +} +else version( darwin ) +{ + enum + { + PTHREAD_SCOPE_SYSTEM = 1, + PTHREAD_SCOPE_PROCESS = 2 + } + + int pthread_attr_getinheritsched(in pthread_attr_t*, int*); + int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); + int pthread_attr_getscope(in pthread_attr_t*, int*); + int pthread_attr_setinheritsched(pthread_attr_t*, int); + int pthread_attr_setschedpolicy(pthread_attr_t*, int); + int pthread_attr_setscope(pthread_attr_t*, int); + int pthread_getschedparam(pthread_t, int*, sched_param*); + int pthread_setschedparam(pthread_t, int, in sched_param*); + //int pthread_setschedprio(pthread_t, int); +} + +// +// Stack (TSA|TSS) +// +/* +int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); (TSA|TSS) +int pthread_attr_getstackaddr(in pthread_attr_t*, void**); (TSA) +int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); (TSS) +int pthread_attr_setstack(pthread_attr_t*, void*, size_t); (TSA|TSS) +int pthread_attr_setstackaddr(pthread_attr_t*, void*); (TSA) +int pthread_attr_setstacksize(pthread_attr_t*, size_t); (TSS) +*/ + +version( linux ) +{ + int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); + int pthread_attr_getstackaddr(in pthread_attr_t*, void**); + int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); + int pthread_attr_setstack(pthread_attr_t*, void*, size_t); + int pthread_attr_setstackaddr(pthread_attr_t*, void*); + int pthread_attr_setstacksize(pthread_attr_t*, size_t); +} +else version( darwin ) +{ + int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); + int pthread_attr_getstackaddr(in pthread_attr_t*, void**); + int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); + int pthread_attr_setstack(pthread_attr_t*, void*, size_t); + int pthread_attr_setstackaddr(pthread_attr_t*, void*); + int pthread_attr_setstacksize(pthread_attr_t*, size_t); +} + +// +// Shared Synchronization (TSH) +// +/* +int pthread_condattr_getpshared(in pthread_condattr_t*, int*); +int pthread_condattr_setpshared(pthread_condattr_t*, int); +int pthread_mutexattr_getpshared(in pthread_mutexattr_t*, int*); +int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int); +int pthread_rwlockattr_getpshared(in pthread_rwlockattr_t*, int*); +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); +*/ diff --git a/import/stdc/posix/pwd.d b/import/stdc/posix/pwd.d new file mode 100644 index 0000000..900380a --- /dev/null +++ b/import/stdc/posix/pwd.d @@ -0,0 +1,132 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.pwd; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for gid_t, uid_t + +extern (C): + +// +// Required +// +/* +struct passwd +{ + char* pw_name; + uid_t pw_uid; + gid_t pw_gid; + char* pw_dir; + char* pw_shell; +} + +passwd* getpwnam(in char*); +passwd* getpwuid(uid_t); +*/ + +version( linux ) +{ + struct passwd + { + char* pw_name; + char* pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + char* pw_gecos; + char* pw_dir; + char* pw_shell; + } +} +else version( darwin ) +{ + struct passwd + { + char* pw_name; + char* pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + time_t pw_change; + char* pw_class; + char* pw_gecos; + char* pw_dir; + char* pw_shell; + time_t pw_expire; + } +} +else version( freebsd ) +{ + struct passwd + { + char* pw_name; /* user name */ + char* pw_passwd; /* encrypted password */ + uid_t pw_uid; /* user uid */ + gid_t pw_gid; /* user gid */ + time_t pw_change; /* password change time */ + char* pw_class; /* user access class */ + char* pw_gecos; /* Honeywell login info */ + char* pw_dir; /* home directory */ + char* pw_shell; /* default shell */ + time_t pw_expire; /* account expiration */ + int pw_fields; /* internal: fields filled in */ + } +} + +passwd* getpwnam(in char*); +passwd* getpwuid(uid_t); + +// +// Thread-Safe Functions (TSF) +// +/* +int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); +int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); +*/ + +version( linux ) +{ + int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); + int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); +} +else version( darwin ) +{ + int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); + int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); +} +else version( freebsd ) +{ + int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); + int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); +} +// +// XOpen (XSI) +// +/* +void endpwent(); +passwd* getpwent(); +void setpwent(); +*/ + +version( linux ) +{ + void endpwent(); + passwd* getpwent(); + void setpwent(); +} +else version ( darwin ) +{ + void endpwent(); + passwd* getpwent(); + void setpwent(); +} +else version ( freebsd ) +{ + void endpwent(); + passwd* getpwent(); + void setpwent(); +} diff --git a/import/stdc/posix/sched.d b/import/stdc/posix/sched.d new file mode 100644 index 0000000..b78475f --- /dev/null +++ b/import/stdc/posix/sched.d @@ -0,0 +1,132 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sched; + +private import stdc.posix.config; +public import stdc.posix.time; +public import stdc.posix.sys.types; + +extern (C): + +// +// Required +// +/* +struct sched_param +{ + int sched_priority (THR) + int sched_ss_low_priority (SS|TSP) + struct timespec sched_ss_repl_period (SS|TSP) + struct timespec sched_ss_init_budget (SS|TSP) + int sched_ss_max_repl (SS|TSP) +} + +SCHED_FIFO +SCHED_RR +SCHED_SPORADIC (SS|TSP) +SCHED_OTHER + +int sched_getparam(pid_t, sched_param*); +int sched_getscheduler(pid_t); +int sched_setparam(pid_t, in sched_param*); +int sched_setscheduler(pid_t, int, in sched_param*); +*/ + +version( linux ) +{ + struct sched_param + { + int sched_priority; + } + + const SCHED_OTHER = 0; + const SCHED_FIFO = 1; + const SCHED_RR = 2; + //SCHED_SPORADIC (SS|TSP) +} +else version( darwin ) +{ + const SCHED_OTHER = 1; + const SCHED_FIFO = 4; + const SCHED_RR = 2; + // SCHED_SPORADIC seems to be unavailable + + private const __SCHED_PARAM_SIZE__ = 4; + + struct sched_param + { + int sched_priority; + byte[__SCHED_PARAM_SIZE__] opaque; + } +} +else version( freebsd ) +{ + struct sched_param + { + int sched_priority; + } + + const SCHED_FIFO = 1; + const SCHED_OTHER = 2; + const SCHED_RR = 3; + //SCHED_SPORADIC (SS|TSP) +} + +int sched_getparam(pid_t, sched_param*); +int sched_getscheduler(pid_t); +int sched_setparam(pid_t, in sched_param*); +int sched_setscheduler(pid_t, int, in sched_param*); + +// +// Thread (THR) +// +/* +int sched_yield(); +*/ + +version( linux ) +{ + int sched_yield(); +} +else version( darwin ) +{ + int sched_yield(); +} +else version( freebsd ) +{ + int sched_yield(); +} + +// +// Scheduling (TPS) +// +/* +int sched_get_priority_max(int); +int sched_get_priority_min(int); +int sched_rr_get_interval(pid_t, timespec*); +*/ + +version( linux ) +{ + int sched_get_priority_max(int); + int sched_get_priority_min(int); + int sched_rr_get_interval(pid_t, timespec*); +} +else version( darwin ) +{ + int sched_get_priority_min(int); + int sched_get_priority_max(int); + //int sched_rr_get_interval(pid_t, timespec*); // FIXME: unavailable? +} +else version( freebsd ) +{ + int sched_get_priority_min(int); + int sched_get_priority_max(int); + int sched_rr_get_interval(pid_t, timespec*); +} diff --git a/import/stdc/posix/semaphore.d b/import/stdc/posix/semaphore.d new file mode 100644 index 0000000..b68f111 --- /dev/null +++ b/import/stdc/posix/semaphore.d @@ -0,0 +1,112 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.semaphore; + +private import stdc.posix.config; +private import stdc.posix.time; + +extern (C): + +// +// Required +// +/* +sem_t +SEM_FAILED + +int sem_close(sem_t*); +int sem_destroy(sem_t*); +int sem_getvalue(sem_t*, int*); +int sem_init(sem_t*, int, uint); +sem_t* sem_open(in char*, int, ...); +int sem_post(sem_t*); +int sem_trywait(sem_t*); +int sem_unlink(in char*); +int sem_wait(sem_t*); +*/ + +version( linux ) +{ + private alias int __atomic_lock_t; + + private struct _pthread_fastlock + { + c_long __status; + __atomic_lock_t __spinlock; + } + + struct sem_t + { + _pthread_fastlock __sem_lock; + int __sem_value; + void* __sem_waiting; + } + + const SEM_FAILED = cast(sem_t*) null; +} +else version( darwin ) +{ + alias int sem_t; + + const SEM_FAILED = cast(sem_t*) null; +} +else version( freebsd ) +{ + const uint SEM_MAGIC = 0x09fa4012; + const SEM_USER = 0; + struct sem_t + { + uint magic; + pthread_mutex_t lock; + pthread_cond_t gtzero; + uint count; + uint nwaiters; + int semid; + int syssem; + struct _entry + { + sem* le_next; + sem** le_prev; + } + _entry entry; + sem_t** backpointer; + } + + const SEM_FAILED = cast(sem_t*) null; +} + +int sem_close(sem_t*); +int sem_destroy(sem_t*); +int sem_getvalue(sem_t*, int*); +int sem_init(sem_t*, int, uint); +sem_t* sem_open(in char*, int, ...); +int sem_post(sem_t*); +int sem_trywait(sem_t*); +int sem_unlink(in char*); +int sem_wait(sem_t*); + +// +// Timeouts (TMO) +// +/* +int sem_timedwait(sem_t*, in timespec*); +*/ + +version( linux ) +{ + int sem_timedwait(sem_t*, in timespec*); +} +else version( darwin ) +{ + int sem_timedwait(sem_t*, in timespec*); +} +else version( freebsd ) +{ + int sem_timedwait(sem_t*, in timespec*); +} diff --git a/import/stdc/posix/setjmp.d b/import/stdc/posix/setjmp.d new file mode 100644 index 0000000..93c6c2e --- /dev/null +++ b/import/stdc/posix/setjmp.d @@ -0,0 +1,103 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.setjmp; + +private import stdc.posix.config; +private import stdc.posix.signal; // for sigset_t + +extern (C): + +// +// Required +// +/* +jmp_buf + +int setjmp(jmp_buf); +void longjmp(jmp_buf, int); +*/ + +version( linux ) +{ + version( X86_64 ) + { + //const JB_BX = 0; + //const JB_BP = 1; + //const JB_12 = 2; + //const JB_13 = 3; + //const JB_14 = 4; + //const JB_15 = 5; + //const JB_SP = 6; + //const JB_PC = 7; + //const JB_SIZE = 64; + + alias long[8] __jmp_buf; + } + else version( X86 ) + { + //const JB_BX = 0; + //const JB_SI = 1; + //const JB_DI = 2; + //const JB_BP = 3; + //const JB_SP = 4; + //const JB_PC = 5; + //const JB_SIZE = 24; + + alias int[6] __jmp_buf; + } + else version ( SPARC ) + { + alias int[3] __jmp_buf; + } + + struct __jmp_buf_tag + { + __jmp_buf __jmpbuf; + int __mask_was_saved; + sigset_t __saved_mask; + } + + alias __jmp_buf_tag[1] jmp_buf; + + alias _setjmp setjmp; // see XOpen block + void longjmp(jmp_buf, int); +} + +// +// C Extension (CX) +// +/* +sigjmp_buf + +int sigsetjmp(sigjmp_buf, int); +void siglongjmp(sigjmp_buf, int); +*/ + +version( linux ) +{ + alias jmp_buf sigjmp_buf; + + int __sigsetjmp(sigjmp_buf, int); + alias __sigsetjmp sigsetjmp; + void siglongjmp(sigjmp_buf, int); +} + +// +// XOpen (XSI) +// +/* +int _setjmp(jmp_buf); +void _longjmp(jmp_buf, int); +*/ + +version( linux ) +{ + int _setjmp(jmp_buf); + void _longjmp(jmp_buf, int); +} diff --git a/import/stdc/posix/signal.d b/import/stdc/posix/signal.d new file mode 100644 index 0000000..dc1f88a --- /dev/null +++ b/import/stdc/posix/signal.d @@ -0,0 +1,824 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.signal; + +private import stdc.posix.config; +public import stdc.signal; +public import stdc.stddef; // for size_t +public import stdc.posix.sys.types; // for pid_t +//public import stdc.posix.time; // for timespec, now defined here + +extern (C): + +private alias void function(int) sigfn_t; +private alias void function(int, siginfo_t*, void*) sigactfn_t; + +// +// Required +// +/* +SIG_DFL (defined in stdc.signal) +SIG_ERR (defined in stdc.signal) +SIG_IGN (defined in stdc.signal) + +sig_atomic_t (defined in stdc.signal) + +SIGEV_NONE +SIGEV_SIGNAL +SIGEV_THREAD + +union sigval +{ + int sival_int; + void* sival_ptr; +} + +SIGRTMIN +SIGRTMAX + +SIGABRT (defined in stdc.signal) +SIGALRM +SIGBUS +SIGCHLD +SIGCONT +SIGFPE (defined in stdc.signal) +SIGHUP +SIGILL (defined in stdc.signal) +SIGINT (defined in stdc.signal) +SIGKILL +SIGPIPE +SIGQUIT +SIGSEGV (defined in stdc.signal) +SIGSTOP +SIGTERM (defined in stdc.signal) +SIGTSTP +SIGTTIN +SIGTTOU +SIGUSR1 +SIGUSR2 +SIGURG + +struct sigaction_t +{ + sigfn_t sa_handler; + sigset_t sa_mask; + sigactfn_t sa_sigaction; +} + +sigfn_t signal(int sig, sigfn_t func); (defined in stdc.signal) +int raise(int sig); (defined in stdc.signal) +*/ + +//SIG_DFL (defined in stdc.signal) +//SIG_ERR (defined in stdc.signal) +//SIG_IGN (defined in stdc.signal) + +//sig_atomic_t (defined in stdc.signal) + +enum +{ + SIGEV_SIGNAL, + SIGEV_NONE, + SIGEV_THREAD +} + +union sigval +{ + int sival_int; + void* sival_ptr; +} + +private extern (C) int __libc_current_sigrtmin(); +private extern (C) int __libc_current_sigrtmax(); + +alias __libc_current_sigrtmin SIGRTMIN; +alias __libc_current_sigrtmax SIGRTMAX; + +version( linux ) +{ + //SIGABRT (defined in stdc.signal) + const SIGALRM = 14; + const SIGBUS = 7; + const SIGCHLD = 17; + const SIGCONT = 18; + //SIGFPE (defined in stdc.signal) + const SIGHUP = 1; + //SIGILL (defined in stdc.signal) + //SIGINT (defined in stdc.signal) + const SIGKILL = 9; + const SIGPIPE = 13; + const SIGQUIT = 3; + //SIGSEGV (defined in stdc.signal) + const SIGSTOP = 19; + //SIGTERM (defined in stdc.signal) + const SIGTSTP = 20; + const SIGTTIN = 21; + const SIGTTOU = 22; + const SIGUSR1 = 10; + const SIGUSR2 = 12; + const SIGURG = 23; +} +else version( darwin ) +{ + //SIGABRT (defined in stdc.signal) + const SIGALRM = 14; + const SIGBUS = 10; + const SIGCHLD = 20; + const SIGCONT = 19; + //SIGFPE (defined in stdc.signal) + const SIGHUP = 1; + //SIGILL (defined in stdc.signal) + //SIGINT (defined in stdc.signal) + const SIGKILL = 9; + const SIGPIPE = 13; + const SIGQUIT = 3; + //SIGSEGV (defined in stdc.signal) + const SIGSTOP = 17; + //SIGTERM (defined in stdc.signal) + const SIGTSTP = 18; + const SIGTTIN = 21; + const SIGTTOU = 22; + const SIGUSR1 = 30; + const SIGUSR2 = 31; + const SIGURG = 16; +} +else version( freebsd ) +{ + //SIGABRT (defined in stdc.signal) + const SIGALRM = 14; + const SIGBUS = 10; + const SIGCHLD = 20; + const SIGCONT = 19; + //SIGFPE (defined in stdc.signal) + const SIGHUP = 1; + //SIGILL (defined in stdc.signal) + //SIGINT (defined in stdc.signal) + const SIGKILL = 9; + const SIGPIPE = 13; + const SIGQUIT = 3; + //SIGSEGV (defined in stdc.signal) + const SIGSTOP = 17; + //SIGTERM (defined in stdc.signal) + const SIGTSTP = 18; + const SIGTTIN = 21; + const SIGTTOU = 22; + const SIGUSR1 = 30; + const SIGUSR2 = 31; + const SIGURG = 16; +} + +struct sigaction_t +{ + static if( true /* __USE_POSIX199309 */ ) + { + union + { + sigfn_t sa_handler; + sigactfn_t sa_sigaction; + } + } + else + { + sigfn_t sa_handler; + } + sigset_t sa_mask; + int sa_flags; + + version( darwin ) {} else { + void function() sa_restorer; + } +} + +// +// C Extension (CX) +// +/* +SIG_HOLD + +sigset_t +pid_t (defined in sys.types) + +SIGABRT (defined in stdc.signal) +SIGFPE (defined in stdc.signal) +SIGILL (defined in stdc.signal) +SIGINT (defined in stdc.signal) +SIGSEGV (defined in stdc.signal) +SIGTERM (defined in stdc.signal) + +SA_NOCLDSTOP (CX|XSI) +SIG_BLOCK +SIG_UNBLOCK +SIG_SETMASK + +struct siginfo_t +{ + int si_signo; + int si_code; + + version( XSI ) + { + int si_errno; + pid_t si_pid; + uid_t si_uid; + void* si_addr; + int si_status; + c_long si_band; + } + version( RTS ) + { + sigval si_value; + } +} + +SI_USER +SI_QUEUE +SI_TIMER +SI_ASYNCIO +SI_MESGQ + +int kill(pid_t, int); +int sigaction(int, in sigaction_t*, sigaction_t*); +int sigaddset(sigset_t*, int); +int sigdelset(sigset_t*, int); +int sigemptyset(sigset_t*); +int sigfillset(sigset_t*); +int sigismember(in sigset_t*, int); +int sigpending(sigset_t*); +int sigprocmask(int, in sigset_t*, sigset_t*); +int sigsuspend(in sigset_t*); +int sigwait(in sigset_t*, int*); +*/ + +version( linux ) +{ + const SIG_HOLD = cast(sigfn_t) 1; + + private const _SIGSET_NWORDS = 1024 / (8 * c_ulong.sizeof); + + struct sigset_t + { + c_ulong[_SIGSET_NWORDS] __val; + } + + // pid_t (defined in sys.types) + + //SIGABRT (defined in stdc.signal) + //SIGFPE (defined in stdc.signal) + //SIGILL (defined in stdc.signal) + //SIGINT (defined in stdc.signal) + //SIGSEGV (defined in stdc.signal) + //SIGTERM (defined in stdc.signal) + + const SA_NOCLDSTOP = 1; // (CX|XSI) + + const SIG_BLOCK = 0; + const SIG_UNBLOCK = 1; + const SIG_SETMASK = 2; + + private const __SI_MAX_SIZE = 128; + + static if( false /* __WORDSIZE == 64 */ ) + { + private const __SI_PAD_SIZE = ((__SI_MAX_SIZE / int.sizeof) - 4); + } + else + { + private const __SI_PAD_SIZE = ((__SI_MAX_SIZE / int.sizeof) - 3); + } + + struct siginfo_t + { + int si_signo; // Signal number + int si_errno; // If non-zero, an errno value associated with + // this signal, as defined in + int si_code; // Signal code + + union _sifields_t + { + int _pad[__SI_PAD_SIZE]; + + // kill() + struct _kill_t + { + pid_t si_pid; // Sending process ID + uid_t si_uid; // Real user ID of sending process + } _kill_t _kill; + + // POSIX.1b timers. + struct _timer_t + { + int si_tid; // Timer ID + int si_overrun; // Overrun count + sigval si_sigval; // Signal value + } _timer_t _timer; + + // POSIX.1b signals + struct _rt_t + { + pid_t si_pid; // Sending process ID + uid_t si_uid; // Real user ID of sending process + sigval si_sigval; // Signal value + } _rt_t _rt; + + // SIGCHLD + struct _sigchild_t + { + pid_t si_pid; // Which child + uid_t si_uid; // Real user ID of sending process + int si_status; // Exit value or signal + clock_t si_utime; + clock_t si_stime; + } _sigchild_t _sigchld; + + // SIGILL, SIGFPE, SIGSEGV, SIGBUS + struct _sigfault_t + { + void* si_addr; // Faulting insn/memory ref + } _sigfault_t _sigfault; + + // SIGPOLL + struct _sigpoll_t + { + c_long si_band; // Band event for SIGPOLL + int si_fd; + } _sigpoll_t _sigpoll; + } _sifields_t _sifields; + } + + enum + { + SI_ASYNCNL = -60, + SI_TKILL = -6, + SI_SIGIO, + SI_ASYNCIO, + SI_MESGQ, + SI_TIMER, + SI_QUEUE, + SI_USER, + SI_KERNEL = 0x80 + } + + int kill(pid_t, int); + int sigaction(int, in sigaction_t*, sigaction_t*); + int sigaddset(sigset_t*, int); + int sigdelset(sigset_t*, int); + int sigemptyset(sigset_t*); + int sigfillset(sigset_t*); + int sigismember(in sigset_t*, int); + int sigpending(sigset_t*); + int sigprocmask(int, in sigset_t*, sigset_t*); + int sigsuspend(in sigset_t*); + int sigwait(in sigset_t*, int*); +} +else version( darwin ) +{ + //SIG_HOLD + + alias uint sigset_t; + // pid_t (defined in sys.types) + + //SIGABRT (defined in stdc.signal) + //SIGFPE (defined in stdc.signal) + //SIGILL (defined in stdc.signal) + //SIGINT (defined in stdc.signal) + //SIGSEGV (defined in stdc.signal) + //SIGTERM (defined in stdc.signal) + + //SA_NOCLDSTOP (CX|XSI) + + //SIG_BLOCK + //SIG_UNBLOCK + //SIG_SETMASK + + struct siginfo_t + { + int si_signo; + int si_errno; + int si_code; + pid_t si_pid; + uid_t si_uid; + int si_status; + void* si_addr; + sigval si_value; + int si_band; + uint pad[7]; + } + + //SI_USER + //SI_QUEUE + //SI_TIMER + //SI_ASYNCIO + //SI_MESGQ + + int kill(pid_t, int); + int sigaction(int, in sigaction_t*, sigaction_t*); + int sigaddset(sigset_t*, int); + int sigdelset(sigset_t*, int); + int sigemptyset(sigset_t*); + int sigfillset(sigset_t*); + int sigismember(in sigset_t*, int); + int sigpending(sigset_t*); + int sigprocmask(int, in sigset_t*, sigset_t*); + int sigsuspend(in sigset_t*); + int sigwait(in sigset_t*, int*); +} +else version( freebsd ) +{ + union sigval + { + int sival_int; + void* sival_ptr; + int sigval_int; + void* sigval_ptr; + } + + struct sigset_t + { + uint __bits[4]; + } + + struct siginfo_t + { + int si_signo; + int si_errno; + int si_code; + pid_t si_pid; + uid_t si_uid; + int si_status; + void* si_addr; + sigval si_value; + union __reason + { + struct __fault + { + int _trapno; + } + __fault _fault; + struct __timer + { + int _timerid; + int _overrun; + } + __timer _timer; + struct __mesgq + { + int _mqd; + } + __mesgq _mesgq; + struct __poll + { + c_long _band; + } + __poll _poll; + struct ___spare___ + { + c_long __spare1__; + int[7] __spare2__; + } + ___spare___ __spare__; + } + __reason _reason; + } + + int kill(pid_t, int); + int sigaction(int, in sigaction_t*, sigaction_t); + int sigaddset(sigset_t*, int); + int sigdelset(sigset_t*, int); + int sigemptyset(sigset_t *); + int sigfillset(sigset_t *); + int sigismember(in sigset_t *, int); + int sigpending(sigset_t *); + int sigprocmask(int, in sigset_t*, sigset_t*); + int sigsuspend(in sigset_t *); + int sigwait(in sigset_t*, int*); +} + + +// +// XOpen (XSI) +// +/* +SIGPOLL +SIGPROF +SIGSYS +SIGTRAP +SIGVTALRM +SIGXCPU +SIGXFSZ + +SA_ONSTACK +SA_RESETHAND +SA_RESTART +SA_SIGINFO +SA_NOCLDWAIT +SA_NODEFER +SS_ONSTACK +SS_DISABLE +MINSIGSTKSZ +SIGSTKSZ + +ucontext_t // from ucontext +mcontext_t // from ucontext + +struct stack_t +{ + void* ss_sp; + size_t ss_size; + int ss_flags; +} + +struct sigstack +{ + int ss_onstack; + void* ss_sp; +} + +ILL_ILLOPC +ILL_ILLOPN +ILL_ILLADR +ILL_ILLTRP +ILL_PRVOPC +ILL_PRVREG +ILL_COPROC +ILL_BADSTK + +FPE_INTDIV +FPE_INTOVF +FPE_FLTDIV +FPE_FLTOVF +FPE_FLTUND +FPE_FLTRES +FPE_FLTINV +FPE_FLTSUB + +SEGV_MAPERR +SEGV_ACCERR + +BUS_ADRALN +BUS_ADRERR +BUS_OBJERR + +TRAP_BRKPT +TRAP_TRACE + +CLD_EXITED +CLD_KILLED +CLD_DUMPED +CLD_TRAPPED +CLD_STOPPED +CLD_CONTINUED + +POLL_IN +POLL_OUT +POLL_MSG +POLL_ERR +POLL_PRI +POLL_HUP + +sigfn_t bsd_signal(int sig, sigfn_t func); +sigfn_t sigset(int sig, sigfn_t func); + +int killpg(pid_t, int); +int sigaltstack(in stack_t*, stack_t*); +int sighold(int); +int sigignore(int); +int siginterrupt(int, int); +int sigpause(int); +int sigrelse(int); +*/ + +version( linux ) +{ + const SIGPOLL = 29; + const SIGPROF = 27; + const SIGSYS = 31; + const SIGTRAP = 5; + const SIGVTALRM = 26; + const SIGXCPU = 24; + const SIGXFSZ = 25; + + const SA_ONSTACK = 0x08000000; + const SA_RESETHAND = 0x80000000; + const SA_RESTART = 0x10000000; + const SA_SIGINFO = 4; + const SA_NOCLDWAIT = 2; + const SA_NODEFER = 0x40000000; + const SS_ONSTACK = 1; + const SS_DISABLE = 2; + const MINSIGSTKSZ = 2048; + const SIGSTKSZ = 8192; + + //ucontext_t (defined in stdc.posix.ucontext) + //mcontext_t (defined in stdc.posix.ucontext) + + struct stack_t + { + void* ss_sp; + int ss_flags; + size_t ss_size; + } + + struct sigstack + { + void* ss_sp; + int ss_onstack; + } + + enum + { + ILL_ILLOPC = 1, + ILL_ILLOPN, + ILL_ILLADR, + ILL_ILLTRP, + ILL_PRVOPC, + ILL_PRVREG, + ILL_COPROC, + ILL_BADSTK + } + + enum + { + FPE_INTDIV = 1, + FPE_INTOVF, + FPE_FLTDIV, + FPE_FLTOVF, + FPE_FLTUND, + FPE_FLTRES, + FPE_FLTINV, + FPE_FLTSUB + } + + enum + { + SEGV_MAPERR = 1, + SEGV_ACCERR + } + + enum + { + BUS_ADRALN = 1, + BUS_ADRERR, + BUS_OBJERR + } + + enum + { + TRAP_BRKPT = 1, + TRAP_TRACE + } + + enum + { + CLD_EXITED = 1, + CLD_KILLED, + CLD_DUMPED, + CLD_TRAPPED, + CLD_STOPPED, + CLD_CONTINUED + } + + enum + { + POLL_IN = 1, + POLL_OUT, + POLL_MSG, + POLL_ERR, + POLL_PRI, + POLL_HUP + } + + sigfn_t bsd_signal(int sig, sigfn_t func); + sigfn_t sigset(int sig, sigfn_t func); + + int killpg(pid_t, int); + int sigaltstack(in stack_t*, stack_t*); + int sighold(int); + int sigignore(int); + int siginterrupt(int, int); + int sigpause(int); + int sigrelse(int); +} + +// +// Timer (TMR) +// +/* +NOTE: This should actually be defined in stdc.posix.time. + It is defined here instead to break a circular import. + +struct timespec +{ + time_t tv_sec; + int tv_nsec; +} +*/ + +version( linux ) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version( darwin ) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version( freebsd ) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} + +// +// Realtime Signals (RTS) +// +/* +struct sigevent +{ + int sigev_notify; + int sigev_signo; + sigval sigev_value; + void(*)(sigval) sigev_notify_function; + pthread_attr_t* sigev_notify_attributes; +} + +int sigqueue(pid_t, int, in sigval); +int sigtimedwait(in sigset_t*, siginfo_t*, in timespec*); +int sigwaitinfo(in sigset_t*, siginfo_t*); +*/ + +version( linux ) +{ + private const __SIGEV_MAX_SIZE = 64; + + static if( false /* __WORDSIZE == 64 */ ) + { + private const __SIGEV_PAD_SIZE = ((__SIGEV_MAX_SIZE / int.sizeof) - 4); + } + else + { + private const __SIGEV_PAD_SIZE = ((__SIGEV_MAX_SIZE / int.sizeof) - 3); + } + + struct sigevent + { + sigval sigev_value; + int sigev_signo; + int sigev_notify; + + union _sigev_un_t + { + int[__SIGEV_PAD_SIZE] _pad; + pid_t _tid; + + struct _sigev_thread_t + { + void function(sigval) _function; + void* _attribute; + } _sigev_thread_t _sigev_thread; + } _sigev_un_t _sigev_un; + } + + int sigqueue(pid_t, int, in sigval); + int sigtimedwait(in sigset_t*, siginfo_t*, in timespec*); + int sigwaitinfo(in sigset_t*, siginfo_t*); +} + +// +// Threads (THR) +// +/* +int pthread_kill(pthread_t, int); +int pthread_sigmask(int, in sigset_t*, sigset_t*); +*/ + +version( linux ) +{ + int pthread_kill(pthread_t, int); + int pthread_sigmask(int, in sigset_t*, sigset_t*); +} +else version( darwin ) +{ + int pthread_kill(pthread_t, int); + int pthread_sigmask(int, in sigset_t*, sigset_t*); +} +else version( freebsd ) +{ + int pthread_kill(pthread_t, int); + int pthread_sigmask(int, in sigset_t*, sigset_t*); +} diff --git a/import/stdc/posix/stdio.d b/import/stdc/posix/stdio.d new file mode 100644 index 0000000..aa55ccf --- /dev/null +++ b/import/stdc/posix/stdio.d @@ -0,0 +1,214 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.stdio; + +private import stdc.posix.config; +public import stdc.stdio; +public import stdc.posix.sys.types; // for off_t + +extern (C): + +// +// Required (defined in stdc.stdio) +// +/* +BUFSIZ +_IOFBF +_IOLBF +_IONBF +L_tmpnam +SEEK_CUR +SEEK_END +SEEK_SET +FILENAME_MAX +FOPEN_MAX +TMP_MAX +EOF +NULL +stderr +stdin +stdout +FILE +fpos_t +size_t + +void clearerr(FILE*); +int fclose(FILE*); +int feof(FILE*); +int ferror(FILE*); +int fflush(FILE*); +int fgetc(FILE*); +int fgetpos(FILE*, fpos_t *); +char* fgets(char*, int, FILE*); +FILE* fopen(in char*, in char*); +int fprintf(FILE*, in char*, ...); +int fputc(int, FILE*); +int fputs(in char*, FILE*); +size_t fread(void *, size_t, size_t, FILE*); +FILE* freopen(in char*, in char*, FILE*); +int fscanf(FILE*, in char*, ...); +int fseek(FILE*, c_long, int); +int fsetpos(FILE*, in fpos_t*); +c_long ftell(FILE*); +size_t fwrite(in void *, size_t, size_t, FILE*); +int getc(FILE*); +int getchar(); +char* gets(char*); +void perror(in char*); +int printf(in char*, ...); +int putc(int, FILE*); +int putchar(int); +int puts(in char*); +int remove(in char*); +int rename(in char*, in char*); +void rewind(FILE*); +int scanf(in char*, ...); +void setbuf(FILE*, char*); +int setvbuf(FILE*, char*, int, size_t); +int snprintf(char*, size_t, in char*, ...); +int sprintf(char*, in char*, ...); +int sscanf(in char*, in char*, int ...); +FILE* tmpfile(); +char* tmpnam(char*); +int ungetc(int, FILE*); +int vfprintf(FILE*, in char*, va_list); +int vfscanf(FILE*, in char*, va_list); +int vprintf(in char*, va_list); +int vscanf(in char*, va_list); +int vsnprintf(char*, size_t, in char*, va_list); +int vsprintf(char*, in char*, va_list); +int vsscanf(in char*, in char*, va_list arg); +*/ + +version( linux ) +{ + static if( __USE_LARGEFILE64 ) + { + int fgetpos64(FILE*, fpos_t *); + alias fgetpos64 fgetpos; + + FILE* fopen64(in char*, in char*); + alias fopen64 fopen; + + FILE* freopen64(in char*, in char*, FILE*); + alias freopen64 freopen; + + int fseek64(FILE*, c_long, int); + alias fseek64 fseek; + + int fsetpos64(FILE*, in fpos_t*); + alias fsetpos64 fsetpos; + + FILE* tmpfile64(); + alias tmpfile64 tmpfile; + } + else + { + int fgetpos(FILE*, fpos_t *); + FILE* fopen(in char*, in char*); + FILE* freopen(in char*, in char*, FILE*); + int fseek(FILE*, c_long, int); + int fsetpos(FILE*, in fpos_t*); + FILE* tmpfile(); + } +} + +// +// C Extension (CX) +// +/* +L_ctermid + +char* ctermid(char*); +FILE* fdopen(int, in char*); +int fileno(FILE*); +int fseeko(FILE*, off_t, int); +off_t ftello(FILE*); +char* gets(char*); +FILE* popen(in char*, in char*); +*/ + +version( linux ) +{ + const L_ctermid = 9; + + static if( __USE_FILE_OFFSET64 ) + { + int fseeko64(FILE*, off_t, int); + alias fseeko64 fseeko; + } + else + { + int fseeko(FILE*, off_t, int); + } + + static if( __USE_LARGEFILE64 ) + { + off_t ftello64(FILE*); + alias ftello64 ftello; + } + else + { + off_t ftello(FILE*); + } +} +else +{ + int fseeko(FILE*, off_t, int); + off_t ftello(FILE*); +} + +char* ctermid(char*); +FILE* fdopen(int, in char*); +int fileno(FILE*); +//int fseeko(FILE*, off_t, int); +//off_t ftello(FILE*); +char* gets(char*); +FILE* popen(in char*, in char*); + +// +// Thread-Safe Functions (TSF) +// +/* +void flockfile(FILE*); +int ftrylockfile(FILE*); +void funlockfile(FILE*); +int getc_unlocked(FILE*); +int getchar_unlocked(); +int putc_unlocked(int, FILE*); +int putchar_unlocked(int); +*/ + +version( linux ) +{ + void flockfile(FILE*); + int ftrylockfile(FILE*); + void funlockfile(FILE*); + int getc_unlocked(FILE*); + int getchar_unlocked(); + int putc_unlocked(int, FILE*); + int putchar_unlocked(int); +} + +// +// XOpen (XSI) +// +/* +P_tmpdir +va_list (defined in stdc.stdarg) + +char* tempnam(in char*, in char*); +*/ + +version( linux ) +{ + const P_tmpdir = "/tmp"; + + char* tempnam(in char*, in char*); +} diff --git a/import/stdc/posix/stdlib.d b/import/stdc/posix/stdlib.d new file mode 100644 index 0000000..d9c7c62 --- /dev/null +++ b/import/stdc/posix/stdlib.d @@ -0,0 +1,298 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.stdlib; + +private import stdc.posix.config; +public import stdc.stdlib; +public import stdc.posix.sys.wait; + +extern (C): + +// +// Required (defined in stdc.stdlib) +// +/* +EXIT_FAILURE +EXIT_SUCCESS +NULL +RAND_MAX +MB_CUR_MAX +div_t +ldiv_t +lldiv_t +size_t +wchar_t + +void _Exit(int); +void abort(); +int abs(int); +int atexit(void function()); +double atof(in char*); +int atoi(in char*); +c_long atol(in char*); +long atoll(in char*); +void* bsearch(in void*, in void*, size_t, size_t, int function(in void*, in void*)); +void* calloc(size_t, size_t); +div_t div(int, int); +void exit(int); +void free(void*); +char* getenv(in char*); +c_long labs(c_long); +ldiv_t ldiv(c_long, c_long); +long llabs(long); +lldiv_t lldiv(long, long); +void* malloc(size_t); +int mblen(in char*, size_t); +size_t mbstowcs(wchar_t*, in char*, size_t); +int mbtowc(wchar_t*, in char*, size_t); +void qsort(void*, size_t, size_t, int function(in void*, in void*)); +int rand(); +void* realloc(void*, size_t); +void srand(uint); +double strtod(in char*, char**); +float strtof(in char*, char**); +c_long strtol(in char*, char**, int); +real strtold(in char*, char**); +long strtoll(in char*, char**, int); +c_ulong strtoul(in char*, char**, int); +ulong strtoull(in char*, char**, int); +int system(in char*); +size_t wcstombs(char*, in wchar_t*, size_t); +int wctomb(char*, wchar_t); +*/ + +// +// Advisory Information (ADV) +// +/* +int posix_memalign(void**, size_t, size_t); +*/ + +version( linux ) +{ + int posix_memalign(void**, size_t, size_t); +} + +// +// C Extension (CX) +// +/* +int setenv(in char*, in char*, int); +int unsetenv(in char*); +*/ + +version( linux ) +{ + int setenv(in char*, in char*, int); + int unsetenv(in char*); + + void* valloc(size_t); // LEGACY non-standard +} +else version( darwin ) +{ + int setenv(in char*, in char*, int); + int unsetenv(in char*); + + void* valloc(size_t); // LEGACY non-standard +} + +// +// Thread-Safe Functions (TSF) +// +/* +int rand_r(uint*); +*/ + +version( linux ) +{ + int rand_r(uint*); +} +else version( darwin ) +{ + int rand_r(uint*); +} +else version( freebsd ) +{ + int rand_r(uint*); +} + +// +// XOpen (XSI) +// +/* +WNOHANG (defined in stdc.posix.sys.wait) +WUNTRACED (defined in stdc.posix.sys.wait) +WEXITSTATUS (defined in stdc.posix.sys.wait) +WIFEXITED (defined in stdc.posix.sys.wait) +WIFSIGNALED (defined in stdc.posix.sys.wait) +WIFSTOPPED (defined in stdc.posix.sys.wait) +WSTOPSIG (defined in stdc.posix.sys.wait) +WTERMSIG (defined in stdc.posix.sys.wait) + +c_long a64l(in char*); +double drand48(); +char* ecvt(double, int, int *, int *); // LEGACY +double erand48(ushort[3]); +char* fcvt(double, int, int *, int *); // LEGACY +char* gcvt(double, int, char*); // LEGACY +// per spec: int getsubopt(char** char* const*, char**); +int getsubopt(char**, in char**, char**); +int grantpt(int); +char* initstate(uint, char*, size_t); +c_long jrand48(ushort[3]); +char* l64a(c_long); +void lcong48(ushort[7]); +c_long lrand48(); +char* mktemp(char*); // LEGACY +int mkstemp(char*); +c_long mrand48(); +c_long nrand48(ushort[3]); +int posix_openpt(int); +char* ptsname(int); +int putenv(char*); +c_long random(); +char* realpath(in char*, char*); +ushort seed48(ushort[3]); +void setkey(in char*); +char* setstate(in char*); +void srand48(c_long); +void srandom(uint); +int unlockpt(int); +*/ + +version( linux ) +{ + //WNOHANG (defined in stdc.posix.sys.wait) + //WUNTRACED (defined in stdc.posix.sys.wait) + //WEXITSTATUS (defined in stdc.posix.sys.wait) + //WIFEXITED (defined in stdc.posix.sys.wait) + //WIFSIGNALED (defined in stdc.posix.sys.wait) + //WIFSTOPPED (defined in stdc.posix.sys.wait) + //WSTOPSIG (defined in stdc.posix.sys.wait) + //WTERMSIG (defined in stdc.posix.sys.wait) + + c_long a64l(in char*); + double drand48(); + char* ecvt(double, int, int *, int *); // LEGACY + double erand48(ushort[3]); + char* fcvt(double, int, int *, int *); // LEGACY + char* gcvt(double, int, char*); // LEGACY + int getsubopt(char**, in char**, char**); + int grantpt(int); + char* initstate(uint, char*, size_t); + c_long jrand48(ushort[3]); + char* l64a(c_long); + void lcong48(ushort[7]); + c_long lrand48(); + char* mktemp(char*); // LEGACY + //int mkstemp(char*); + c_long mrand48(); + c_long nrand48(ushort[3]); + int posix_openpt(int); + char* ptsname(int); + int putenv(char*); + c_long random(); + char* realpath(in char*, char*); + ushort seed48(ushort[3]); + void setkey(in char*); + char* setstate(in char*); + void srand48(c_long); + void srandom(uint); + int unlockpt(int); + + static if( __USE_LARGEFILE64 ) + { + int mkstemp64(char*); + alias mkstemp64 mkstemp; + } + else + { + int mkstemp(char*); + } +} +else version( darwin ) +{ + //WNOHANG (defined in stdc.posix.sys.wait) + //WUNTRACED (defined in stdc.posix.sys.wait) + //WEXITSTATUS (defined in stdc.posix.sys.wait) + //WIFEXITED (defined in stdc.posix.sys.wait) + //WIFSIGNALED (defined in stdc.posix.sys.wait) + //WIFSTOPPED (defined in stdc.posix.sys.wait) + //WSTOPSIG (defined in stdc.posix.sys.wait) + //WTERMSIG (defined in stdc.posix.sys.wait) + + c_long a64l(in char*); + double drand48(); + char* ecvt(double, int, int *, int *); // LEGACY + double erand48(ushort[3]); + char* fcvt(double, int, int *, int *); // LEGACY + char* gcvt(double, int, char*); // LEGACY + int getsubopt(char**, in char**, char**); + int grantpt(int); + char* initstate(uint, char*, size_t); + c_long jrand48(ushort[3]); + char* l64a(c_long); + void lcong48(ushort[7]); + c_long lrand48(); + char* mktemp(char*); // LEGACY + int mkstemp(char*); + c_long mrand48(); + c_long nrand48(ushort[3]); + int posix_openpt(int); + char* ptsname(int); + int putenv(char*); + c_long random(); + char* realpath(in char*, char*); + ushort seed48(ushort[3]); + void setkey(in char*); + char* setstate(in char*); + void srand48(c_long); + void srandom(uint); + int unlockpt(int); +} +else version( freebsd ) +{ + //WNOHANG (defined in stdc.posix.sys.wait) + //WUNTRACED (defined in stdc.posix.sys.wait) + //WEXITSTATUS (defined in stdc.posix.sys.wait) + //WIFEXITED (defined in stdc.posix.sys.wait) + //WIFSIGNALED (defined in stdc.posix.sys.wait) + //WIFSTOPPED (defined in stdc.posix.sys.wait) + //WSTOPSIG (defined in stdc.posix.sys.wait) + //WTERMSIG (defined in stdc.posix.sys.wait) + + c_long a64l(in char*); + double drand48(); + //char* ecvt(double, int, int *, int *); // LEGACY + double erand48(ushort[3]); + //char* fcvt(double, int, int *, int *); // LEGACY + //char* gcvt(double, int, char*); // LEGACY + int getsubopt(char**, in char**, char**); + int grantpt(int); + char* initstate(uint, char*, size_t); + c_long jrand48(ushort[3]); + char* l64a(c_long); + void lcong48(ushort[7]); + c_long lrand48(); + char* mktemp(char*); // LEGACY + int mkstemp(char*); + c_long mrand48(); + c_long nrand48(ushort[3]); + int posix_openpt(int); + char* ptsname(int); + int putenv(char*); + c_long random(); + char* realpath(in char*, char*); + ushort seed48(ushort[3]); + void setkey(in char*); + char* setstate(in char*); + void srand48(c_long); + void srandom(uint); + int unlockpt(int); +} diff --git a/import/stdc/posix/sys/ipc.d b/import/stdc/posix/sys/ipc.d new file mode 100644 index 0000000..7bb1f96 --- /dev/null +++ b/import/stdc/posix/sys/ipc.d @@ -0,0 +1,99 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.ipc; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for uid_t, gid_t, mode_t, key_t + +extern (C): + +// +// XOpen (XSI) +// +/* +struct ipc_perm +{ + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; +} + +IPC_CREAT +IPC_EXCL +IPC_NOWAIT + +IPC_PRIVATE + +IPC_RMID +IPC_SET +IPC_STAT + +key_t ftok(in char*, int); +*/ + +version( linux ) +{ + struct ipc_perm + { + key_t __key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + ushort mode; + ushort __pad1; + ushort __seq; + ushort __pad2; + c_ulong __unused1; + c_ulong __unused2; + } + + const IPC_CREAT = 01000; + const IPC_EXCL = 02000; + const IPC_NOWAIT = 04000; + + const key_t IPC_PRIVATE = 0; + + const IPC_RMID = 0; + const IPC_SET = 1; + const IPC_STAT = 2; + + key_t ftok(in char*, int); +} +else version( darwin ) +{ + +} +else version( freebsd ) +{ + struct ipc_perm + { + ushort cuid; + ushort cguid; + ushort uid; + ushort gid; + ushort mode; + ushort seq; + key_t key; + } + + const IPC_CREAT = 01000; + const IPC_EXCL = 02000; + const IPC_NOWAIT = 04000; + + const key_t IPC_PRIVATE = 0; + + const IPC_RMID = 0; + const IPC_SET = 1; + const IPC_STAT = 2; + + key_t ftok(in char*, int); +} diff --git a/import/stdc/posix/sys/mman.d b/import/stdc/posix/sys/mman.d new file mode 100644 index 0000000..f23e16a --- /dev/null +++ b/import/stdc/posix/sys/mman.d @@ -0,0 +1,308 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.mman; + +private import stdc.posix.config; +public import stdc.stddef; // for size_t +public import stdc.posix.sys.types; // for off_t, mode_t + +extern (C): + +// +// Advisory Information (ADV) +// +/* +int posix_madvise(void*, size_t, int); +*/ + +// +// Advisory Information and either Memory Mapped Files or Shared Memory Objects (MC1) +// +/* +POSIX_MADV_NORMAL +POSIX_MADV_SEQUENTIAL +POSIX_MADV_RANDOM +POSIX_MADV_WILLNEED +POSIX_MADV_DONTNEED +*/ + +version( linux ) +{ + const POSIX_MADV_NORMAL = 0; + const POSIX_MADV_RANDOM = 1; + const POSIX_MADV_SEQUENTIAL = 2; + const POSIX_MADV_WILLNEED = 3; + const POSIX_MADV_DONTNEED = 4; +} +else version( darwin ) +{ + const POSIX_MADV_NORMAL = 0; + const POSIX_MADV_RANDOM = 1; + const POSIX_MADV_SEQUENTIAL = 2; + const POSIX_MADV_WILLNEED = 3; + const POSIX_MADV_DONTNEED = 4; +} +else version( freebsd ) +{ + const POSIX_MADV_NORMAL = 0; + const POSIX_MADV_RANDOM = 1; + const POSIX_MADV_SEQUENTIAL = 2; + const POSIX_MADV_WILLNEED = 3; + const POSIX_MADV_DONTNEED = 4; +} + +// +// Memory Mapped Files, Shared Memory Objects, or Memory Protection (MC2) +// +/* +PROT_READ +PROT_WRITE +PROT_EXEC +PROT_NONE +*/ + +version( linux ) +{ + const PROT_NONE = 0x0; + const PROT_READ = 0x1; + const PROT_WRITE = 0x2; + const PROT_EXEC = 0x4; +} +else version( darwin ) +{ + const PROT_NONE = 0x00; + const PROT_READ = 0x01; + const PROT_WRITE = 0x02; + const PROT_EXEC = 0x04; +} +else version( freebsd ) +{ + const PROT_NONE = 0x00; + const PROT_READ = 0x01; + const PROT_WRITE = 0x02; + const PROT_EXEC = 0x04; +} + +// +// Memory Mapped Files, Shared Memory Objects, or Typed Memory Objects (MC3) +// +/* +void* mmap(void*, size_t, int, int, int, off_t); +int munmap(void*, size_t); +*/ + +version( linux ) +{ + //void* mmap(void*, size_t, int, int, int, off_t); + int munmap(void*, size_t); + + static if( __USE_LARGEFILE64 ) + { + void* mmap64(void*, size_t, int, int, int, off_t); + alias mmap64 mmap; + } + else + { + void* mmap(void*, size_t, int, int, int, off_t); + } +} +else version( darwin ) +{ + void* mmap(void*, size_t, int, int, int, off_t); + int munmap(void*, size_t); +} +else version( freebsd ) +{ + void* mmap(void*, size_t, int, int, int, off_t); + int munmap(void*, size_t); +} + +// +// Memory Mapped Files (MF) +// +/* +MAP_SHARED (MF|SHM) +MAP_PRIVATE (MF|SHM) +MAP_FIXED (MF|SHM) +MAP_FAILED (MF|SHM) + +MS_ASYNC (MF|SIO) +MS_SYNC (MF|SIO) +MS_INVALIDATE (MF|SIO) + +int msync(void*, size_t, int); (MF|SIO) +*/ + +version( linux ) +{ + const MAP_SHARED = 0x01; + const MAP_PRIVATE = 0x02; + const MAP_FIXED = 0x10; + const MAP_ANON = 0x20; // non-standard + + const MAP_FAILED = cast(void*) -1; + + enum + { + MS_ASYNC = 1, + MS_SYNC = 4, + MS_INVALIDATE = 2 + } + + int msync(void*, size_t, int); +} +else version( darwin ) +{ + const MAP_SHARED = 0x0001; + const MAP_PRIVATE = 0x0002; + const MAP_FIXED = 0x0010; + const MAP_ANON = 0x1000; // non-standard + + const MAP_FAILED = cast(void*)-1; + + const MS_ASYNC = 0x0001; + const MS_INVALIDATE = 0x0002; + const MS_SYNC = 0x0010; + + int msync(void*, size_t, int); +} +else version( darwin ) +{ + const MAP_SHARED = 0x0001; + const MAP_PRIVATE = 0x0002; + const MAP_FIXED = 0x0010; + const MAP_ANON = 0x1000; // non-standard + + const MAP_FAILED = cast(void*)-1; + + const MS_SYNC = 0x0000; + const MS_ASYNC = 0x0001; + const MS_INVALIDATE = 0x0002; + + int msync(void*, size_t, int); +} + +// +// Process Memory Locking (ML) +// +/* +MCL_CURRENT +MCL_FUTURE + +int mlockall(int); +int munlockall(); +*/ + +version( linux ) +{ + const MCL_CURRENT = 1; + const MCL_FUTURE = 2; + + int mlockall(int); + int munlockall(); + +} +else version( darwin ) +{ + const MCL_CURRENT = 0x0001; + const MCL_FUTURE = 0x0002; + + int mlockall(int); + int munlockall(); +} +else version( freebsd ) +{ + const MCL_CURRENT = 0x0001; + const MCL_FUTURE = 0x0002; + + int mlockall(int); + int munlockall(); +} + +// +// Range Memory Locking (MLR) +// +/* +int mlock(in void*, size_t); +int munlock(in void*, size_t); +*/ + +version( linux ) +{ + int mlock(in void*, size_t); + int munlock(in void*, size_t); +} +else version( darwin ) +{ + int mlock(in void*, size_t); + int munlock(in void*, size_t); +} +else version( freebsd ) +{ + int mlock(in void*, size_t); + int munlock(in void*, size_t); +} + +// +// Memory Protection (MPR) +// +/* +int mprotect(void*, size_t, int); +*/ + +version( darwin ) +{ + int mprotect(void*, size_t, int); +} +else version( freebsd ) +{ + int mprotect(void*, size_t, int); +} + +// +// Shared Memory Objects (SHM) +// +/* +int shm_open(in char*, int, mode_t); +int shm_unlink(in char*); +*/ + +version( linux ) +{ + int shm_open(in char*, int, mode_t); + int shm_unlink(in char*); +} +else version( darwin ) +{ + int shm_open(in char*, int, mode_t); + int shm_unlink(in char*); +} +else version( freebsd ) +{ + int shm_open(in char*, int, mode_t); + int shm_unlink(in char*); +} + +// +// Typed Memory Objects (TYM) +// +/* +POSIX_TYPED_MEM_ALLOCATE +POSIX_TYPED_MEM_ALLOCATE_CONTIG +POSIX_TYPED_MEM_MAP_ALLOCATABLE + +struct posix_typed_mem_info +{ + size_t posix_tmi_length; +} + +int posix_mem_offset(in void*, size_t, off_t *, size_t *, int *); +int posix_typed_mem_get_info(int, struct posix_typed_mem_info *); +int posix_typed_mem_open(in char*, int, int); +*/ diff --git a/import/stdc/posix/sys/select.d b/import/stdc/posix/sys/select.d new file mode 100644 index 0000000..b3ed541 --- /dev/null +++ b/import/stdc/posix/sys/select.d @@ -0,0 +1,150 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.select; + +private import stdc.posix.config; +public import stdc.time; // for timespec +public import stdc.posix.sys.time; // for timeval +public import stdc.posix.sys.types; // for time_t +public import stdc.posix.signal; // for sigset_t + +extern (C): + +// +// Required +// +/* +NOTE: This module requires timeval from stdc.posix.sys.time, but timeval + is supposedly an XOpen extension. As a result, this header will not + compile on platforms that are not XSI-compliant. This must be resolved + on a per-platform basis. + +fd_set + +void FD_CLR(int fd, fd_set* fdset); +int FD_ISSET(int fd, fd_set* fdset); +void FD_SET(int fd, fd_set* fdset); +void FD_ZERO(fd_set* fdset); + +FD_SETSIZE + +int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*); +int select(int, fd_set*, fd_set*, fd_set*, timeval*); +*/ + +version( linux ) +{ + private + { + alias c_long __fd_mask; + const __NFDBITS = 8 * __fd_mask.sizeof; + + extern (D) int __FDELT( int d ) + { + return d / __NFDBITS; + } + + extern (D) int __FDMASK( int d ) + { + return cast(__fd_mask) 1 << ( d % __NFDBITS ); + } + } + + const FD_SETSIZE = 1024; + + struct fd_set + { + __fd_mask[FD_SETSIZE / __NFDBITS] fds_bits; + } + + extern (D) void FD_CLR( int fd, fd_set* fdset ) + { + fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd ); + } + + extern (D) int FD_ISSET( int fd, fd_set* fdset ) + { + return fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd ); + } + + extern (D) void FD_SET( int fd, fd_set* fdset ) + { + fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd ); + } + + extern (D) void FD_ZERO( fd_set* fdset ) + { + fdset.fds_bits[0 .. $] = 0; + } + + /+ + + GNU ASM Implementation + + + # define __FD_ZERO(fdsp) \ + do { \ + int __d0, __d1; \ + __asm__ __volatile__ ("cld; rep; stosl" \ + : "=c" (__d0), "=D" (__d1) \ + : "a" (0), "0" (sizeof (fd_set) \ + / sizeof (__fd_mask)), \ + "1" (&__FDS_BITS (fdsp)[0]) \ + : "memory"); \ + } while (0) + + # define __FD_SET(fd, fdsp) \ + __asm__ __volatile__ ("btsl %1,%0" \ + : "=m" (__FDS_BITS (fdsp)[__FDELT (fd)]) \ + : "r" (((int) (fd)) % __NFDBITS) \ + : "cc","memory") + # define __FD_CLR(fd, fdsp) \ + __asm__ __volatile__ ("btrl %1,%0" \ + : "=m" (__FDS_BITS (fdsp)[__FDELT (fd)]) \ + : "r" (((int) (fd)) % __NFDBITS) \ + : "cc","memory") + # define __FD_ISSET(fd, fdsp) \ + (__extension__ \ + ({register char __result; \ + __asm__ __volatile__ ("btl %1,%2 ; setcb %b0" \ + : "=q" (__result) \ + : "r" (((int) (fd)) % __NFDBITS), \ + "m" (__FDS_BITS (fdsp)[__FDELT (fd)]) \ + : "cc"); \ + __result; })) + +/ + + int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*); + int select(int, fd_set*, fd_set*, fd_set*, timeval*); +} +else version( darwin ) +{ + private + { + const uint __DARWIN_NBBY = 8; /* bits in a byte */ + const uint __DARWIN_NFDBITS = (int.sizeof * __DARWIN_NBBY); /* bits per mask */ + } + + const FD_SETSIZE = 1024; + + struct fd_set + { + int fds_bits[(((FD_SETSIZE) + ((__DARWIN_NFDBITS) - 1)) / (__DARWIN_NFDBITS))]; + } +} +else version( freebsd ) +{ + private + { + const uint FD_SETSIZE = 1024; + const uint _NFDBITS = c_ulong.sizeof * 8; + } + struct fd_set + { + c_ulong fds_bits[((FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS)]; + } +} diff --git a/import/stdc/posix/sys/shm.d b/import/stdc/posix/sys/shm.d new file mode 100644 index 0000000..212c11e --- /dev/null +++ b/import/stdc/posix/sys/shm.d @@ -0,0 +1,111 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.shm; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for pid_t, time_t, key_t, size_t +public import stdc.posix.sys.ipc; + +extern (C): + +// +// XOpen (XSI) +// +/* +SHM_RDONLY +SHM_RND + +SHMLBA + +shmatt_t + +struct shmid_ds +{ + ipc_perm shm_perm; + size_t shm_segsz; + pid_t shm_lpid; + pid_t shm_cpid; + shmatt_t shm_nattch; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; +} + +void* shmat(int, in void*, int); +int shmctl(int, int, shmid_ds*); +int shmdt(in void*); +int shmget(key_t, size_t, int); +*/ + +version( linux ) +{ + const SHM_RDONLY = 010000; + const SHM_RND = 020000; + + int __getpagesize(); + alias __getpagesize SHMLBA; + + alias c_ulong shmatt_t; + + struct shmid_ds + { + ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + c_ulong __unused1; + time_t shm_dtime; + c_ulong __unused2; + time_t shm_ctime; + c_ulong __unused3; + pid_t shm_cpid; + pid_t shm_lpid; + shmatt_t shm_nattch; + c_ulong __unused4; + c_ulong __unused5; + } + + void* shmat(int, in void*, int); + int shmctl(int, int, shmid_ds*); + int shmdt(in void*); + int shmget(key_t, size_t, int); +} +else version( freebsd ) +{ + const SHM_RDONLY = 010000; + const SHM_RND = 020000; + const SHMLBA = 1 << 12; // PAGE_SIZE = (1<= 2) || __STDC_VERSION__ >= 199901L */ ) + { + ubyte[1] __cmsg_data; + } + } + + enum : uint + { + SCM_RIGHTS = 0x01 + } + + static if( false /* (!is( __STRICT_ANSI__ ) && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L */ ) + { + extern (D) ubyte[1] CMSG_DATA( cmsghdr* cmsg ) { return cmsg.__cmsg_data; } + } + else + { + extern (D) ubyte* CMSG_DATA( cmsghdr* cmsg ) { return cast(ubyte*)( cmsg + 1 ); } + } + + private cmsghdr* __cmsg_nxthdr(msghdr*, cmsghdr*); + alias __cmsg_nxthdr CMSG_NXTHDR; + + extern (D) size_t CMSG_FIRSTHDR( msghdr* mhdr ) + { + return cast(size_t)( mhdr.msg_controllen >= cmsghdr.sizeof + ? cast(cmsghdr*) mhdr.msg_control + : cast(cmsghdr*) null ); + } + + struct linger + { + int l_onoff; + int l_linger; + } + + enum + { + SOCK_DGRAM = 2, + SOCK_SEQPACKET = 5, + SOCK_STREAM = 1 + } + + enum + { + SOL_SOCKET = 1 + } + + enum + { + SO_ACCEPTCONN = 30, + SO_BROADCAST = 6, + SO_DEBUG = 1, + SO_DONTROUTE = 5, + SO_ERROR = 4, + SO_KEEPALIVE = 9, + SO_LINGER = 13, + SO_OOBINLINE = 10, + SO_RCVBUF = 8, + SO_RCVLOWAT = 18, + SO_RCVTIMEO = 20, + SO_REUSEADDR = 2, + SO_SNDBUF = 7, + SO_SNDLOWAT = 19, + SO_SNDTIMEO = 21, + SO_TYPE = 3 + } + + enum + { + SOMAXCONN = 128 + } + + enum : uint + { + MSG_CTRUNC = 0x08, + MSG_DONTROUTE = 0x04, + MSG_EOR = 0x80, + MSG_OOB = 0x01, + MSG_PEEK = 0x02, + MSG_TRUNC = 0x20, + MSG_WAITALL = 0x100 + } + + enum + { + AF_INET = 2, + AF_UNIX = 1, + AF_UNSPEC = 0 + } + + enum + { + SHUT_RD, + SHUT_WR, + SHUT_RDWR + } + + int accept(int, sockaddr*, socklen_t*); + int bind(int, in sockaddr*, socklen_t); + int connect(int, in sockaddr*, socklen_t); + int getpeername(int, sockaddr*, socklen_t*); + int getsockname(int, sockaddr*, socklen_t*); + int getsockopt(int, int, int, void*, socklen_t*); + int listen(int, int); + ssize_t recv(int, void*, size_t, int); + ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*); + ssize_t recvmsg(int, msghdr*, int); + ssize_t send(int, in void*, size_t, int); + ssize_t sendmsg(int, in msghdr*, int); + ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); + int setsockopt(int, int, int, in void*, socklen_t); + int shutdown(int, int); + int socket(int, int, int); + int sockatmark(int); + int socketpair(int, int, int, int[2]); +} +else version( darwin ) +{ + alias uint socklen_t; + alias ubyte sa_family_t; + + struct sockaddr + { + ubyte sa_len; + sa_family_t sa_family; + byte[14] sa_data; + } + + private enum : size_t + { + _SS_PAD1 = long.sizeof - ubyte.sizeof - sa_family_t.sizeof, + _SS_PAD2 = 128 - ubyte.sizeof - sa_family_t.sizeof - _SS_PAD1 - long.sizeof + } + + struct sockaddr_storage + { + ubyte ss_len; + sa_family_t ss_family; + byte[_SS_PAD1] __ss_pad1; + long __ss_align; + byte[_SS_PAD2] __ss_pad2; + } + + struct msghdr + { + void* msg_name; + socklen_t msg_namelen; + iovec* msg_iov; + int msg_iovlen; + void* msg_control; + socklen_t msg_controllen; + int msg_flags; + } + + struct cmsghdr + { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; + } + + enum : uint + { + SCM_RIGHTS = 0x01 + } + + /+ + CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + \ + ALIGN(sizeof(struct cmsghdr))) + CMSG_NXTHDR(mhdr, cmsg) \ + (((unsigned char *)(cmsg) + ALIGN((cmsg)->cmsg_len) + \ + ALIGN(sizeof(struct cmsghdr)) > \ + (unsigned char *)(mhdr)->msg_control +(mhdr)->msg_controllen) ? \ + (struct cmsghdr *)0 /* NULL */ : \ + (struct cmsghdr *)((unsigned char *)(cmsg) + ALIGN((cmsg)->cmsg_len))) + CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control) + +/ + + struct linger + { + int l_onoff; + int l_linger; + } + + enum + { + SOCK_DGRAM = 2, + SOCK_SEQPACKET = 5, + SOCK_STREAM = 1 + } + + enum : uint + { + SOL_SOCKET = 0xffff + } + + enum : uint + { + SO_ACCEPTCONN = 0x0002, + SO_BROADCAST = 0x0020, + SO_DEBUG = 0x0001, + SO_DONTROUTE = 0x0010, + SO_ERROR = 0x1007, + SO_KEEPALIVE = 0x0008, + SO_LINGER = 0x1080, + SO_OOBINLINE = 0x0100, + SO_RCVBUF = 0x1002, + SO_RCVLOWAT = 0x1004, + SO_RCVTIMEO = 0x1006, + SO_REUSEADDR = 0x1006, + SO_SNDBUF = 0x1001, + SO_SNDLOWAT = 0x1003, + SO_SNDTIMEO = 0x1005, + SO_TYPE = 0x1008 + } + + enum + { + SOMAXCONN = 128 + } + + enum : uint + { + MSG_CTRUNC = 0x20, + MSG_DONTROUTE = 0x4, + MSG_EOR = 0x8, + MSG_OOB = 0x1, + MSG_PEEK = 0x2, + MSG_TRUNC = 0x10, + MSG_WAITALL = 0x40 + } + + enum + { + AF_INET = 2, + AF_UNIX = 1, + AF_UNSPEC = 0 + } + + enum + { + SHUT_RD, + SHUT_WR, + SHUT_RDWR + } + + int accept(int, sockaddr*, socklen_t*); + int bind(int, in sockaddr*, socklen_t); + int connect(int, in sockaddr*, socklen_t); + int getpeername(int, sockaddr*, socklen_t*); + int getsockname(int, sockaddr*, socklen_t*); + int getsockopt(int, int, int, void*, socklen_t*); + int listen(int, int); + ssize_t recv(int, void*, size_t, int); + ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*); + ssize_t recvmsg(int, msghdr*, int); + ssize_t send(int, in void*, size_t, int); + ssize_t sendmsg(int, in msghdr*, int); + ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); + int setsockopt(int, int, int, in void*, socklen_t); + int shutdown(int, int); + int socket(int, int, int); + int sockatmark(int); + int socketpair(int, int, int, int[2]); +} +else version( freebsd ) +{ + alias uint socklen_t; + alias ubyte sa_family_t; + + struct sockaddr + { + ubyte sa_len; + sa_family_t sa_family; + byte[14] sa_data; + } + + private + { + const _SS_ALIGNSIZE = long.sizeof; + const uint _SS_MAXSIZE = 128; + const _SS_PAD1SIZE = _SS_ALIGNSIZE - ubyte.sizeof - sa_family_t.sizeof; + const _SS_PAD2SIZE = _SS_MAXSIZE - ubyte.sizeof - sa_family_t.sizeof - _SS_PAD1SIZE - _SS_ALIGNSIZE; + } + + struct sockaddr_storage + { + ubyte ss_len; + sa_family_t ss_family; + byte[_SS_PAD1SIZE] __ss_pad1; + long __ss_align; + byte[_SS_PAD2SIZE] __ss_pad2; + } + + struct msghdr + { + void* msg_name; + socklen_t msg_namelen; + iovec* msg_iov; + int msg_iovlen; + void* msg_control; + socklen_t msg_controllen; + int msg_flags; + } + + struct cmsghdr + { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; + } + + enum : uint + { + SCM_RIGHTS = 0x01 + } + + /+ + CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + \ + ALIGN(sizeof(struct cmsghdr))) + CMSG_NXTHDR(mhdr, cmsg) \ + (((unsigned char *)(cmsg) + ALIGN((cmsg)->cmsg_len) + \ + ALIGN(sizeof(struct cmsghdr)) > \ + (unsigned char *)(mhdr)->msg_control +(mhdr)->msg_controllen) ? \ + (struct cmsghdr *)0 /* NULL */ : \ + (struct cmsghdr *)((unsigned char *)(cmsg) + ALIGN((cmsg)->cmsg_len))) + CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control) + +/ + + struct linger + { + int l_onoff; + int l_linger; + } + + enum + { + SOCK_DGRAM = 2, + SOCK_SEQPACKET = 5, + SOCK_STREAM = 1 + } + + enum : uint + { + SOL_SOCKET = 0xffff + } + + enum : uint + { + SO_ACCEPTCONN = 0x0002, + SO_BROADCAST = 0x0020, + SO_DEBUG = 0x0001, + SO_DONTROUTE = 0x0010, + SO_ERROR = 0x1007, + SO_KEEPALIVE = 0x0008, + SO_LINGER = 0x1080, + SO_OOBINLINE = 0x0100, + SO_RCVBUF = 0x1002, + SO_RCVLOWAT = 0x1004, + SO_RCVTIMEO = 0x1006, + SO_REUSEADDR = 0x1006, + SO_SNDBUF = 0x1001, + SO_SNDLOWAT = 0x1003, + SO_SNDTIMEO = 0x1005, + SO_TYPE = 0x1008 + } + + enum + { + SOMAXCONN = 128 + } + + enum : uint + { + MSG_CTRUNC = 0x20, + MSG_DONTROUTE = 0x4, + MSG_EOR = 0x8, + MSG_OOB = 0x1, + MSG_PEEK = 0x2, + MSG_TRUNC = 0x10, + MSG_WAITALL = 0x40 + } + + enum + { + AF_INET = 2, + AF_UNIX = 1, + AF_UNSPEC = 0 + } + + enum + { + SHUT_RD = 0, + SHUT_WR = 1, + SHUT_RDWR = 2 + } + + int accept(int, sockaddr*, socklen_t*); + int bind(int, in sockaddr*, socklen_t); + int connect(int, in sockaddr*, socklen_t); + int getpeername(int, sockaddr*, socklen_t*); + int getsockname(int, sockaddr*, socklen_t*); + int getsockopt(int, int, int, void*, socklen_t*); + int listen(int, int); + ssize_t recv(int, void*, size_t, int); + ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*); + ssize_t recvmsg(int, msghdr*, int); + ssize_t send(int, in void*, size_t, int); + ssize_t sendmsg(int, in msghdr*, int); + ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); + int setsockopt(int, int, int, in void*, socklen_t); + int shutdown(int, int); + int socket(int, int, int); + int sockatmark(int); + int socketpair(int, int, int, int[2]); +} + +// +// IPV6 (IP6) +// +/* +AF_INET6 +*/ + +version( linux ) +{ + enum + { + AF_INET6 = 10 + } +} +else version( darwin ) +{ + enum + { + AF_INET6 = 30 + } +} +else version( freebsd ) +{ + enum + { + AF_INET6 = 28 + } +} + +// +// Raw Sockets (RS) +// +/* +SOCK_RAW +*/ + +version( linux ) +{ + enum + { + SOCK_RAW = 3 + } +} +else version( darwin ) +{ + enum + { + SOCK_RAW = 3 + } +} +else version( freebsd ) +{ + enum + { + SOCK_RAW = 3 + } +} diff --git a/import/stdc/posix/sys/stat.d b/import/stdc/posix/sys/stat.d new file mode 100644 index 0000000..b2cc2bc --- /dev/null +++ b/import/stdc/posix/sys/stat.d @@ -0,0 +1,399 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.stat; + +private import stdc.posix.config; +private import stdc.stdint; +private import stdc.posix.time; // for timespec +public import stdc.stddef; // for size_t +public import stdc.posix.sys.types; // for off_t, mode_t + +extern (C): + +// +// Required +// +/* +struct stat +{ + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +} + +S_IRWXU + S_IRUSR + S_IWUSR + S_IXUSR +S_IRWXG + S_IRGRP + S_IWGRP + S_IXGRP +S_IRWXO + S_IROTH + S_IWOTH + S_IXOTH +S_ISUID +S_ISGID +S_ISVTX + +S_ISBLK(m) +S_ISCHR(m) +S_ISDIR(m) +S_ISFIFO(m) +S_ISREG(m) +S_ISLNK(m) +S_ISSOCK(m) + +S_TYPEISMQ(buf) +S_TYPEISSEM(buf) +S_TYPEISSHM(buf) + +int chmod(in char*, mode_t); +int fchmod(int, mode_t); +int fstat(int, stat*); +int lstat(in char*, stat*); +int mkdir(in char*, mode_t); +int mkfifo(in char*, mode_t); +int stat(in char*, stat*); +mode_t umask(mode_t); +*/ + +version( linux ) +{ + static if( __USE_LARGEFILE64 ) + { + private alias uint _pad_t; + } + else + { + private alias ushort _pad_t; + } + + struct stat_t + { + dev_t st_dev; + _pad_t __pad1; + static if( __USE_FILE_OFFSET64 ) + { + ino_t __st_ino; + } + else + { + ino_t st_ino; + } + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + _pad_t __pad2; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + static if( false /*__USE_MISC*/ ) // true if _BSD_SOURCE || _SVID_SOURCE + { + timespec st_atim; + timespec st_mtim; + timespec st_ctim; + alias st_atim.tv_sec st_atime; + alias st_mtim.tv_sec st_mtime; + alias st_ctim.tv_sec st_ctime; + } + else + { + time_t st_atime; + c_ulong st_atimensec; + time_t st_mtime; + c_ulong st_mtimensec; + time_t st_ctime; + c_ulong st_ctimensec; + } + static if( __USE_FILE_OFFSET64 ) + { + ino_t st_ino; + } + else + { + c_ulong __unused4; + c_ulong __unused5; + } + } + + const S_IRUSR = 0400; + const S_IWUSR = 0200; + const S_IXUSR = 0100; + const S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR; + + const S_IRGRP = S_IRUSR >> 3; + const S_IWGRP = S_IWUSR >> 3; + const S_IXGRP = S_IXUSR >> 3; + const S_IRWXG = S_IRWXU >> 3; + + const S_IROTH = S_IRGRP >> 3; + const S_IWOTH = S_IWGRP >> 3; + const S_IXOTH = S_IXGRP >> 3; + const S_IRWXO = S_IRWXG >> 3; + + const S_ISUID = 04000; + const S_ISGID = 02000; + const S_ISVTX = 01000; + + private + { + extern (D) bool S_ISTYPE( mode_t mode, uint mask ) + { + return ( mode & S_IFMT ) == mask; + } + } + + extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); } + extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); } + extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); } + extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); } + extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); } + extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); } + extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); } + + static if( true /*__USE_POSIX199309*/ ) + { + extern bool S_TYPEISMQ( stat_t* buf ) { return false; } + extern bool S_TYPEISSEM( stat_t* buf ) { return false; } + extern bool S_TYPEISSHM( stat_t* buf ) { return false; } + } +} +else version( darwin ) +{ + struct stat_t + { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + time_t st_atime; + c_ulong st_atimensec; + time_t st_mtime; + c_ulong st_mtimensec; + time_t st_ctime; + c_ulong st_ctimensec; + off_t st_size; + blkcnt_t st_blocks; + blksize_t st_blksize; + uint st_flags; + uint st_gen; + int st_lspare; + long st_qspare[2]; + } + + const S_IRUSR = 0400; + const S_IWUSR = 0200; + const S_IXUSR = 0100; + const S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR; + + const S_IRGRP = S_IRUSR >> 3; + const S_IWGRP = S_IWUSR >> 3; + const S_IXGRP = S_IXUSR >> 3; + const S_IRWXG = S_IRWXU >> 3; + + const S_IROTH = S_IRGRP >> 3; + const S_IWOTH = S_IWGRP >> 3; + const S_IXOTH = S_IXGRP >> 3; + const S_IRWXO = S_IRWXG >> 3; + + const S_ISUID = 04000; + const S_ISGID = 02000; + const S_ISVTX = 01000; + + private + { + extern (D) bool S_ISTYPE( mode_t mode, uint mask ) + { + return ( mode & S_IFMT ) == mask; + } + } + + extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); } + extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); } + extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); } + extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); } + extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); } + extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); } + extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); } +} +else version( freebsd ) +{ + struct stat_t + { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + time_t st_atime; + c_long st_atimensec; + time_t st_mtime; + c_long st_mtimensec; + time_t st_ctime; + c_long st_ctimensec; + off_t st_size; + blkcnt_t st_blocks; + blksize_t st_blksize; + uint st_flags; + uint st_gen; + int st_lspare; + time_t st_birthtime; + c_long st_birthtimensec; + } + + const S_IRUSR = 0000400; + const S_IWUSR = 0000200; + const S_IXUSR = 0000100; + const S_IRWXU = 0000700; + + const S_IRGRP = 0000040; + const S_IWGRP = 0000020; + const S_IXGRP = 0000010; + const S_IRWXG = 0000070; + + const S_IROTH = 0000004; + const S_IWOTH = 0000002; + const S_IXOTH = 0000001; + const S_IRWXO = 0000007; + + const S_ISUID = 0004000; + const S_ISGID = 0002000; + const S_ISVTX = 0001000; + + private + { + extern (D) bool S_ISTYPE( mode_t mode, uint mask ) + { + return ( mode & S_IFMT ) == mask; + } + } + + extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); } + extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); } + extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); } + extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); } + extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); } + extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); } + extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); } +} + +int chmod(in char*, mode_t); +int fchmod(int, mode_t); +//int fstat(int, stat_t*); +//int lstat(in char*, stat_t*); +int mkdir(in char*, mode_t); +int mkfifo(in char*, mode_t); +//int stat(in char*, stat_t*); +mode_t umask(mode_t); + +version( linux ) +{ + static if( __USE_LARGEFILE64 ) + { + int fstat64(int, stat_t*); + alias fstat64 fstat; + + int lstat64(in char*, stat_t*); + alias lstat64 lstat; + + int stat64(in char*, stat_t*); + alias stat64 stat; + } + else + { + int fstat(int, stat_t*); + int lstat(in char*, stat_t*); + int stat(in char*, stat_t*); + } +} +else +{ + int fstat(int, stat_t*); + int lstat(in char*, stat_t*); + int stat(in char*, stat_t*); +} + +// +// Typed Memory Objects (TYM) +// +/* +S_TYPEISTMO(buf) +*/ + +// +// XOpen (XSI) +// +/* +S_IFMT +S_IFBLK +S_IFCHR +S_IFIFO +S_IFREG +S_IFDIR +S_IFLNK +S_IFSOCK + +int mknod(in 3char*, mode_t, dev_t); +*/ + +version( linux ) +{ + const S_IFMT = 0170000; + const S_IFBLK = 0060000; + const S_IFCHR = 0020000; + const S_IFIFO = 0010000; + const S_IFREG = 0100000; + const S_IFDIR = 0040000; + const S_IFLNK = 0120000; + const S_IFSOCK = 0140000; + + int mknod(in char*, mode_t, dev_t); +} +else version( darwin ) +{ + const S_IFMT = 0170000; + const S_IFBLK = 0060000; + const S_IFCHR = 0020000; + const S_IFIFO = 0010000; + const S_IFREG = 0100000; + const S_IFDIR = 0040000; + const S_IFLNK = 0120000; + const S_IFSOCK = 0140000; + + int mknod(in char*, mode_t, dev_t); +} +else version( freebsd ) +{ + const S_IFMT = 0170000; + const S_IFBLK = 0060000; + const S_IFCHR = 0020000; + const S_IFIFO = 0010000; + const S_IFREG = 0100000; + const S_IFDIR = 0040000; + const S_IFLNK = 0120000; + const S_IFSOCK = 0140000; + + int mknod(in char*, mode_t, dev_t); +} diff --git a/import/stdc/posix/sys/time.d b/import/stdc/posix/sys/time.d new file mode 100644 index 0000000..dadd5da --- /dev/null +++ b/import/stdc/posix/sys/time.d @@ -0,0 +1,121 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.time; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for time_t, suseconds_t +public import stdc.posix.sys.select; // for fd_set, FD_CLR() FD_ISSET() FD_SET() FD_ZERO() FD_SETSIZE + +extern (C): + +// +// XOpen (XSI) +// +/* +struct timeval +{ + time_t tv_sec; + suseconds_t tv_usec; +} + +struct itimerval +{ + timeval it_interval; + timeval it_value; +} + +ITIMER_REAL +ITIMER_VIRTUAL +ITIMER_PROF + +int getitimer(int, itimerval*); +int gettimeofday(timeval*, void*); +int select(int, fd_set*, fd_set*, fd_set*, timeval*); +int setitimer(int, in itimerval*, itimerval*); +int utimes(in char*, in timeval[2]); // LEGACY +*/ + +version( linux ) +{ + struct timeval + { + time_t tv_sec; + suseconds_t tv_usec; + } + + struct itimerval + { + timeval it_interval; + timeval it_value; + } + + const ITIMER_REAL = 0; + const ITIMER_VIRTUAL = 1; + const ITIMER_PROF = 2; + + int getitimer(int, itimerval*); + int gettimeofday(timeval*, void*); + int select(int, fd_set*, fd_set*, fd_set*, timeval*); + int setitimer(int, in itimerval*, itimerval*); + int utimes(in char*, in timeval[2]); // LEGACY +} +else version( darwin ) +{ + struct timeval + { + time_t tv_sec; + suseconds_t tv_usec; + } + + struct itimerval + { + timeval it_interval; + timeval it_value; + } + + // non-standard + struct timezone_t + { + int tz_minuteswest; + int tz_dsttime; + } + + int getitimer(int, itimerval*); + int gettimeofday(timeval*, timezone_t*); // timezone_t* is normally void* + int select(int, fd_set*, fd_set*, fd_set*, timeval*); + int setitimer(int, in itimerval*, itimerval*); + int utimes(in char*, in timeval[2]); +} +else version( freebsd ) +{ + struct timeval + { + time_t tv_sec; + suseconds_t tv_usec; + } + + struct itimerval + { + timeval it_interval; + timeval it_value; + } + + // non-standard + struct timezone_t + { + int tz_minuteswest; + int tz_dsttime; + } + + int getitimer(int, itimerval*); + int gettimeofday(timeval*, timezone_t*); // timezone_t* is normally void* + int select(int, fd_set*, fd_set*, fd_set*, timeval*); + int setitimer(int, in itimerval*, itimerval*); + int utimes(in char*, in timeval[2]); +} diff --git a/import/stdc/posix/sys/types.d b/import/stdc/posix/sys/types.d new file mode 100644 index 0000000..579f185 --- /dev/null +++ b/import/stdc/posix/sys/types.d @@ -0,0 +1,452 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.types; + +private import stdc.posix.config; +private import stdc.stdint; +public import stdc.stddef; // for size_t +public import stdc.time; // for clock_t, time_t + +extern (C): + +// +// Required +// +/* +blkcnt_t +blksize_t +dev_t +gid_t +ino_t +mode_t +nlink_t +off_t +pid_t +size_t +ssize_t +time_t +uid_t +*/ + +version( linux ) +{ + static if( __USE_FILE_OFFSET64 ) + { + alias long blkcnt_t; + alias ulong ino_t; + alias long off_t; + } + else + { + alias c_long blkcnt_t; + alias c_ulong ino_t; + alias c_long off_t; + } + alias c_long blksize_t; + alias ulong dev_t; + alias uint gid_t; + alias uint mode_t; + alias c_ulong nlink_t; + alias int pid_t; + //size_t (defined in stdc.stddef) + alias c_long ssize_t; + //time_t (defined in stdc.time) + alias uint uid_t; +} +else version( darwin ) +{ + alias long blkcnt_t; + alias int blksize_t; + alias int dev_t; + alias uint gid_t; + alias uint ino_t; + alias ushort mode_t; + alias ushort nlink_t; + alias long off_t; + alias int pid_t; + //size_t (defined in stdc.stddef) + alias size_t ssize_t; + //time_t (defined in stdc.time) + alias uint uid_t; +} +else version( freebsd ) +{ + alias long blkcnt_t; + alias uint blksize_t; + alias uint dev_t; + alias uint gid_t; + alias uint ino_t; + alias ushort mode_t; + alias ushort nlink_t; + alias long off_t; + alias int pid_t; + //size_t (defined in stdc.stddef) + alias size_t ssize_t; + //time_t (defined in stdc.time) + alias uint uid_t; +} + +// +// XOpen (XSI) +// +/* +clock_t +fsblkcnt_t +fsfilcnt_t +id_t +key_t +suseconds_t +useconds_t +*/ + +version( linux ) +{ + static if( __USE_FILE_OFFSET64 ) + { + alias ulong fsblkcnt_t; + alias ulong fsfilcnt_t; + } + else + { + alias c_ulong fsblkcnt_t; + alias c_ulong fsfilcnt_t; + } + // clock_t (defined in stdc.time) + alias uint id_t; + alias int key_t; + alias c_long suseconds_t; + alias uint useconds_t; +} +else version( darwin ) +{ + //clock_t + alias uint fsblkcnt_t; + alias uint fsfilcnt_t; + alias uint id_t; + // key_t + alias int suseconds_t; + alias uint useconds_t; +} +else version( freebsd ) +{ + //clock_t + alias ulong fsblkcnt_t; + alias ulong fsfilcnt_t; + alias long id_t; + // key_t + alias c_long suseconds_t; // C long + alias uint useconds_t; // C unsigned int +} + +// +// Thread (THR) +// +/* +pthread_attr_t +pthread_cond_t +pthread_condattr_t +pthread_key_t +pthread_mutex_t +pthread_mutexattr_t +pthread_once_t +pthread_rwlock_t +pthread_rwlockattr_t +pthread_t +*/ + +version( linux ) +{ + private struct __sched_param + { + int __sched_priority; + } + + struct pthread_attr_t + { + int __detachstate; + int __schedpolicy; + __sched_param __schedparam; + int __inheritsched; + int __scope; + size_t __guardsize; + int __stackaddr_set; + void* __stackaddr; + size_t __stacksize; + } + + private alias int __atomic_lock_t; + + private struct _pthread_fastlock + { + c_long __status; + __atomic_lock_t __spinlock; + } + + private alias void* _pthread_descr; + + private alias long __pthread_cond_align_t; + + struct pthread_cond_t + { + _pthread_fastlock __c_lock; + _pthread_descr __c_waiting; + char[48 - + _pthread_fastlock.sizeof - + _pthread_descr.sizeof - + __pthread_cond_align_t.sizeof] + __padding; + __pthread_cond_align_t __align; + } + + struct pthread_condattr_t + { + int __dummy; + } + + alias uint pthread_key_t; + + struct pthread_mutex_t + { + int __m_reserved; + int __m_count; + _pthread_descr __m_owner; + int __m_kind; + _pthread_fastlock __m_lock; + } + + struct pthread_mutexattr_t + { + int __mutexkind; + } + + alias int pthread_once_t; + + struct pthread_rwlock_t + { + _pthread_fastlock __rw_lock; + int __rw_readers; + _pthread_descr __rw_writer; + _pthread_descr __rw_read_waiting; + _pthread_descr __rw_write_waiting; + int __rw_kind; + int __rw_pshared; + } + + struct pthread_rwlockattr_t + { + int __lockkind; + int __pshared; + } + + alias c_ulong pthread_t; +} +else version( darwin ) +{ + private + { + // #if defined(__LP64__) + // FIXME: what is LP64, is it important enough to be included? + version( LP64 ) + { + const __PTHREAD_SIZE__ = 1168; + const __PTHREAD_ATTR_SIZE__ = 56; + const __PTHREAD_MUTEXATTR_SIZE__ = 8; + const __PTHREAD_MUTEX_SIZE__ = 56; + const __PTHREAD_CONDATTR_SIZE__ = 8; + const __PTHREAD_COND_SIZE__ = 40; + const __PTHREAD_ONCE_SIZE__ = 8; + const __PTHREAD_RWLOCK_SIZE__ = 192; + const __PTHREAD_RWLOCKATTR_SIZE__ = 16; + } + else + { + const __PTHREAD_SIZE__ = 596; + const __PTHREAD_ATTR_SIZE__ = 36; + const __PTHREAD_MUTEXATTR_SIZE__ = 8; + const __PTHREAD_MUTEX_SIZE__ = 40; + const __PTHREAD_CONDATTR_SIZE__ = 4; + const __PTHREAD_COND_SIZE__ = 24; + const __PTHREAD_ONCE_SIZE__ = 4; + const __PTHREAD_RWLOCK_SIZE__ = 124; + const __PTHREAD_RWLOCKATTR_SIZE__ = 12; + } + } + + struct pthread_handler_rec + { + void function(void*) __routine; + void* __arg; + pthread_handler_rec* __next; + } + + struct pthread_attr_t + { + c_long __sig; + byte[__PTHREAD_ATTR_SIZE__] __opaque; + } + + struct pthread_cond_t + { + c_long __sig; + byte[__PTHREAD_COND_SIZE__] __opaque; + } + + struct pthread_condattr_t + { + c_long __sig; + byte[__PTHREAD_CONDATTR_SIZE__] __opaque; + } + + alias c_ulong pthread_key_t; + + struct pthread_mutex_t + { + c_long __sig; + byte[__PTHREAD_MUTEX_SIZE__] __opaque; + } + + struct pthread_mutexattr_t + { + c_long __sig; + byte[__PTHREAD_MUTEXATTR_SIZE__] __opaque; + } + + struct pthread_once_t + { + c_long __sig; + byte[__PTHREAD_ONCE_SIZE__] __opaque; + } + + struct pthread_rwlock_t + { + c_long __sig; + byte[__PTHREAD_RWLOCK_SIZE__] __opaque; + } + + struct pthread_rwlockattr_t + { + c_long __sig; + byte[__PTHREAD_RWLOCKATTR_SIZE__] __opaque; + } + + private struct _opaque_pthread_t + { + c_long __sig; + pthread_handler_rec* __cleanup_stack; + byte[__PTHREAD_SIZE__] __opaque; + } + + alias _opaque_pthread_t* pthread_t; +} +else version( freebsd ) +{ + struct pthread; + + /* + + { + + c_long tid; + umutex lock; + umtx_t cycle; + int locklevel; // C int + int critical_count; // C int + int sigblock; // C int + TAILQ_ENTRY(pthread) tle; + TAILQ_ENTRY(pthread) gcle; + LIST_ENTRY(pthread) hle; + int refcount; // C int + } + */ + + alias pthread* pthread_t; +} + +// +// Barrier (BAR) +// +/* +pthread_barrier_t +pthread_barrierattr_t +*/ + +version( linux ) +{ + struct pthread_barrier_t + { + _pthread_fastlock __ba_lock; + int __ba_required; + int __ba_present; + _pthread_descr __ba_waiting; + } + + struct pthread_barrierattr_t + { + int __pshared; + } +} +else version( freebsd ) +{ + struct pthread_barrier { + umutex b_lock; + ucond b_cv; + long b_cycle; // volatile + int b_count; // volatile C int + int b_waiters; // volatile C int + } + + alias pthread_barrier* pthread_barrier_t; + + struct pthread_barrierattr + { + int pshared; + } + + alias pthread_barrierattr* pthread_barrierattr_t; +} + +// +// Spin (SPN) +// +/* +pthread_spinlock_t +*/ + +version( linux ) +{ + alias int pthread_spinlock_t; // volatile +} +else version( darwin ) +{ + struct pthread_spinlock_t; +} +else version( freebsd ) +{ + private struct pthread_spinlock; + + alias pthread_spinlock* pthread_spinlock_t; +} + +// +// Timer (TMR) +// +/* +clockid_t +timer_t +*/ + +// +// Trace (TRC) +// +/* +trace_attr_t +trace_event_id_t +trace_event_set_t +trace_id_t +*/ diff --git a/import/stdc/posix/sys/uio.d b/import/stdc/posix/sys/uio.d new file mode 100644 index 0000000..181f073 --- /dev/null +++ b/import/stdc/posix/sys/uio.d @@ -0,0 +1,65 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.uio; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for ssize_t, size_t + +extern (C): + +// +// Required +// +/* +struct iovec +{ + void* iov_base; + size_t iov_len; +} + +ssize_t // from stdc.posix.sys.types +size_t // from stdc.posix.sys.types + +ssize_t readv(int, in iovec*, int); +ssize_t writev(int, in iovec*, int); +*/ + +version( linux ) +{ + struct iovec + { + void* iov_base; + size_t iov_len; + } + + ssize_t readv(int, in iovec*, int); + ssize_t writev(int, in iovec*, int); +} +else version( darwin ) +{ + struct iovec + { + void* iov_base; + size_t iov_len; + } + + ssize_t readv(int, in iovec*, int); + ssize_t writev(int, in iovec*, int); +} +else version( freebsd ) +{ + struct iovec + { + void* iov_base; + size_t iov_len; + } + + ssize_t readv(int, in iovec*, int); + ssize_t writev(int, in iovec*, int); +} diff --git a/import/stdc/posix/sys/wait.d b/import/stdc/posix/sys/wait.d new file mode 100644 index 0000000..b0f8404 --- /dev/null +++ b/import/stdc/posix/sys/wait.d @@ -0,0 +1,136 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.sys.wait; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for id_t, pid_t +public import stdc.posix.signal; // for siginfo_t (XSI) +//public import stdc.posix.resource; // for rusage (XSI) + +extern (C): + +// +// Required +// +/* +WNOHANG +WUNTRACED + +WEXITSTATUS +WIFCONTINUED +WIFEXITED +WIFSIGNALED +WIFSTOPPED +WSTOPSIG +WTERMSIG + +pid_t wait(int*); +pid_t waitpid(pid_t, int*, int); +*/ + +version( linux ) +{ + const WNOHANG = 1; + const WUNTRACED = 2; + + private + { + const __W_CONTINUED = 0xFFFF; + + extern (D) int __WTERMSIG( int status ) { return status & 0x7F; } + } + + // + // NOTE: These macros assume __USE_BSD is not defined in the relevant + // C headers as the parameter definition there is different and + // much more complicated. + // + extern (D) int WEXITSTATUS( int status ) { return ( status & 0xFF00 ) >> 8; } + extern (D) int WIFCONTINUED( int status ) { return status == __W_CONTINUED; } + extern (D) bool WIFEXITED( int status ) { return __WTERMSIG( status ) == 0; } + extern (D) bool WIFSIGNALED( int status ) + { + return ( cast(byte) ( ( status & 0x7F ) + 1 ) >> 1 ) > 0; + } + extern (D) bool WIFSTOPPED( int status ) { return ( status & 0xFF ) == 0x7F; } + extern (D) int WSTOPSIG( int status ) { return WEXITSTATUS( status ); } + extern (D) int WTERMSIG( int status ) { return status & 0x7F; } +} +else version( darwin ) +{ + const WNOHANG = 1; + const WUNTRACED = 2; + + private + { + const _WSTOPPED = 0177; + } + + extern (D) int _WSTATUS(int status) { return (status & 0177); } + extern (D) int WEXITSTATUS( int status ) { return (status >> 8); } + extern (D) int WIFCONTINUED( int status ) { return status == 0x13; } + extern (D) bool WIFEXITED( int status ) { return _WSTATUS(status) == 0; } + extern (D) bool WIFSIGNALED( int status ) + { + return _WSTATUS( status ) != _WSTOPPED && _WSTATUS( status ) != 0; + } + extern (D) bool WIFSTOPPED( int status ) { return _WSTATUS( status ) == _WSTOPPED; } + extern (D) int WSTOPSIG( int status ) { return status >> 8; } + extern (D) int WTERMSIG( int status ) { return _WSTATUS( status ); } +} +else version( freebsd ) +{ + const WNOHANG = 1; + const WUNTRACED = 2; + const WCONTINUED = 4; + + private + { + const _WSTOPPED = 0177; + } + + extern (D) int _WSTATUS(int status) { return (status & 0177); } + extern (D) int WEXITSTATUS( int status ) { return (status >> 8); } + extern (D) int WIFCONTINUED( int status ) { return status == 0x13; } + extern (D) bool WIFEXITED( int status ) { return _WSTATUS(status) == 0; } + extern (D) bool WIFSIGNALED( int status ) + { + return _WSTATUS( status ) != _WSTOPPED && _WSTATUS( status ) != 0; + } + extern (D) bool WIFSTOPPED( int status ) { return _WSTATUS( status ) == _WSTOPPED; } + extern (D) int WSTOPSIG( int status ) { return status >> 8; } + extern (D) int WTERMSIG( int status ) { return _WSTATUS( status ); } +} +else +{ + static assert( false ); +} + +pid_t wait(int*); +pid_t waitpid(pid_t, int*, int); + +// +// XOpen (XSI) +// +/* +WEXITED +WSTOPPED +WCONTINUED +WNOHANG +WNOWAIT + +enum idtype_t +{ + P_ALL, + P_PID, + P_PGID +} + +int waitid(idtype_t, id_t, siginfo_t*, int); +*/ diff --git a/import/stdc/posix/termios.d b/import/stdc/posix/termios.d new file mode 100644 index 0000000..da070a1 --- /dev/null +++ b/import/stdc/posix/termios.d @@ -0,0 +1,415 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.termios; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for pid_t + +extern (C): + +// +// Required +// +/* +cc_t +speed_t +tcflag_t + +NCCS + +struct termios +{ + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t[NCCS] c_cc; +} + +VEOF +VEOL +VERASE +VINTR +VKILL +VMIN +VQUIT +VSTART +VSTOP +VSUSP +VTIME + +BRKINT +ICRNL +IGNBRK +IGNCR +IGNPAR +INLCR +INPCK +ISTRIP +IXOFF +IXON +PARMRK + +OPOST + +B0 +B50 +B75 +B110 +B134 +B150 +B200 +B300 +B600 +B1200 +B1800 +B2400 +B4800 +B9600 +B19200 +B38400 + +CSIZE + CS5 + CS6 + CS7 + CS8 +CSTOPB +CREAD +PARENB +PARODD +HUPCL +CLOCAL + +ECHO +ECHOE +ECHOK +ECHONL +ICANON +IEXTEN +ISIG +NOFLSH +TOSTOP + +TCSANOW +TCSADRAIN +TCSAFLUSH + +TCIFLUSH +TCIOFLUSH +TCOFLUSH + +TCIOFF +TCION +TCOOFF +TCOON + +speed_t cfgetispeed(in termios*); +speed_t cfgetospeed(in termios*); +int cfsetispeed(termios*, speed_t); +int cfsetospeed(termios*, speed_t); +int tcdrain(int); +int tcflow(int, int); +int tcflush(int, int); +int tcgetattr(int, termios*); +int tcsendbreak(int, int); +int tcsetattr(int, int, in termios*); +*/ + +version ( darwin) +{ + alias ubyte cc_t; + alias uint speed_t; + alias uint tcflag_t; + + const NCCS = 20; + + struct termios + { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t[NCCS] c_cc; + speed_t c_ispeed; + speed_t c_ospeed; + } + + const VEOF = 0; + const VEOL = 1; + const VERASE = 3; + const VINTR = 8; + const VKILL = 5; + const VMIN = 16; + const VQUIT = 9; + const VSTART = 12; + const VSTOP = 13; + const VSUSP = 10; + const VTIME = 17; + + const BRKINT = 0x0000002; + const ICRNL = 0x0000100; + const IGNBRK = 0x0000001; + const IGNCR = 0x0000080; + const IGNPAR = 0x0000004; + const INLCR = 0x0000040; + const INPCK = 0x0000010; + const ISTRIP = 0x0000020; + const IXOFF = 0x0000400; + const IXON = 0x0000200; + const PARMRK = 0x0000008; + + const OPOST = 0x0000001; + + const B0 = 0; + const B50 = 50; + const B75 = 75; + const B110 = 110; + const B134 = 134; + const B150 = 150; + const B200 = 200; + const B300 = 300; + const B600 = 600; + const B1200 = 1200; + const B1800 = 1800; + const B2400 = 2400; + const B4800 = 4800; + const B9600 = 9600; + const B19200 = 19200; + const B38400 = 38400; + + const CSIZE = 0x0000300; + const CS5 = 0x0000000; + const CS6 = 0x0000100; + const CS7 = 0x0000200; + const CS8 = 0x0000300; + const CSTOPB = 0x0000400; + const CREAD = 0x0000800; + const PARENB = 0x0001000; + const PARODD = 0x0002000; + const HUPCL = 0x0004000; + const CLOCAL = 0x0008000; + + const ECHO = 0x00000008; + const ECHOE = 0x00000002; + const ECHOK = 0x00000004; + const ECHONL = 0x00000010; + const ICANON = 0x00000100; + const IEXTEN = 0x00000400; + const ISIG = 0x00000080; + const NOFLSH = 0x80000000; + const TOSTOP = 0x00400000; + + const TCSANOW = 0; + const TCSADRAIN = 1; + const TCSAFLUSH = 2; + + const TCIFLUSH = 1; + const TCOFLUSH = 2; + const TCIOFLUSH = 3; + + const TCIOFF = 3; + const TCION = 4; + const TCOOFF = 1; + const TCOON = 2; + + speed_t cfgetispeed(in termios*); + speed_t cfgetospeed(in termios*); + int cfsetispeed(termios*, speed_t); + int cfsetospeed(termios*, speed_t); + int tcdrain(int); + int tcflow(int, int); + int tcflush(int, int); + int tcgetattr(int, termios*); + int tcsendbreak(int, int); + int tcsetattr(int, int, in termios*); + +} + +version( linux ) +{ + alias ubyte cc_t; + alias uint speed_t; + alias uint tcflag_t; + + const NCCS = 32; + + struct termios + { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t[NCCS] c_cc; + speed_t c_ispeed; + speed_t c_ospeed; + } + + const VEOF = 4; + const VEOL = 11; + const VERASE = 2; + const VINTR = 0; + const VKILL = 3; + const VMIN = 6; + const VQUIT = 1; + const VSTART = 8; + const VSTOP = 9; + const VSUSP = 10; + const VTIME = 5; + + const BRKINT = 0000002; + const ICRNL = 0000400; + const IGNBRK = 0000001; + const IGNCR = 0000200; + const IGNPAR = 0000004; + const INLCR = 0000100; + const INPCK = 0000020; + const ISTRIP = 0000040; + const IXOFF = 0010000; + const IXON = 0002000; + const PARMRK = 0000010; + + const OPOST = 0000001; + + const B0 = 0000000; + const B50 = 0000001; + const B75 = 0000002; + const B110 = 0000003; + const B134 = 0000004; + const B150 = 0000005; + const B200 = 0000006; + const B300 = 0000007; + const B600 = 0000010; + const B1200 = 0000011; + const B1800 = 0000012; + const B2400 = 0000013; + const B4800 = 0000014; + const B9600 = 0000015; + const B19200 = 0000016; + const B38400 = 0000017; + + const CSIZE = 0000060; + const CS5 = 0000000; + const CS6 = 0000020; + const CS7 = 0000040; + const CS8 = 0000060; + const CSTOPB = 0000100; + const CREAD = 0000200; + const PARENB = 0000400; + const PARODD = 0001000; + const HUPCL = 0002000; + const CLOCAL = 0004000; + + const ECHO = 0000010; + const ECHOE = 0000020; + const ECHOK = 0000040; + const ECHONL = 0000100; + const ICANON = 0000002; + const IEXTEN = 0100000; + const ISIG = 0000001; + const NOFLSH = 0000200; + const TOSTOP = 0000400; + + const TCSANOW = 0; + const TCSADRAIN = 1; + const TCSAFLUSH = 2; + + const TCIFLUSH = 0; + const TCOFLUSH = 1; + const TCIOFLUSH = 2; + + const TCIOFF = 2; + const TCION = 3; + const TCOOFF = 0; + const TCOON = 1; + + speed_t cfgetispeed(in termios*); + speed_t cfgetospeed(in termios*); + int cfsetispeed(termios*, speed_t); + int cfsetospeed(termios*, speed_t); + int tcdrain(int); + int tcflow(int, int); + int tcflush(int, int); + int tcgetattr(int, termios*); + int tcsendbreak(int, int); + int tcsetattr(int, int, in termios*); +} + +// +// XOpen (XSI) +// +/* +IXANY + +ONLCR +OCRNL +ONOCR +ONLRET +OFILL +NLDLY + NL0 + NL1 +CRDLY + CR0 + CR1 + CR2 + CR3 +TABDLY + TAB0 + TAB1 + TAB2 + TAB3 +BSDLY + BS0 + BS1 +VTDLY + VT0 + VT1 +FFDLY + FF0 + FF1 + +pid_t tcgetsid(int); +*/ + +version( linux ) +{ + const IXANY = 0004000; + + const ONLCR = 0000004; + const OCRNL = 0000010; + const ONOCR = 0000020; + const ONLRET = 0000040; + const OFILL = 0000100; + const NLDLY = 0000400; + const NL0 = 0000000; + const NL1 = 0000400; + const CRDLY = 0003000; + const CR0 = 0000000; + const CR1 = 0001000; + const CR2 = 0002000; + const CR3 = 0003000; + const TABDLY = 0014000; + const TAB0 = 0000000; + const TAB1 = 0004000; + const TAB2 = 0010000; + const TAB3 = 0014000; + const BSDLY = 0020000; + const BS0 = 0000000; + const BS1 = 0020000; + const VTDLY = 0040000; + const VT0 = 0000000; + const VT1 = 0040000; + const FFDLY = 0100000; + const FF0 = 0000000; + const FF1 = 0100000; + + pid_t tcgetsid(int); +} diff --git a/import/stdc/posix/time.d b/import/stdc/posix/time.d new file mode 100644 index 0000000..0c77b08 --- /dev/null +++ b/import/stdc/posix/time.d @@ -0,0 +1,255 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.time; + +private import stdc.posix.config; +public import stdc.time; +public import stdc.posix.sys.types; +public import stdc.posix.signal; // for sigevent + +extern (C): + +// +// Required (defined in stdc.time) +// +/* +char* asctime(in tm*); +clock_t clock(); +char* ctime(in time_t*); +double difftime(time_t, time_t); +tm* gmtime(in time_t*); +tm* localtime(in time_t*); +time_t mktime(tm*); +size_t strftime(char*, size_t, in char*, in tm*); +time_t time(time_t*); +*/ + +version( linux ) +{ + time_t timegm(tm*); // non-standard +} +else version( darwin ) +{ + time_t timegm(tm*); // non-standard +} +else version( freebsd ) +{ + time_t timegm(tm*); // non-standard +} + +// +// C Extension (CX) +// (defined in stdc.time) +// +/* +char* tzname[]; +void tzset(); +*/ + +// +// Process CPU-Time Clocks (CPT) +// +/* +int clock_getcpuclockid(pid_t, clockid_t*); +*/ + +// +// Clock Selection (CS) +// +/* +int clock_nanosleep(clockid_t, int, in timespec*, timespec*); +*/ + +// +// Monotonic Clock (MON) +// +/* +CLOCK_MONOTONIC +*/ + +// +// Timer (TMR) +// +/* +CLOCK_PROCESS_CPUTIME_ID (TMR|CPT) +CLOCK_THREAD_CPUTIME_ID (TMR|TCT) + +NOTE: timespec must be defined in stdc.posix.signal to break + a circular import. + +struct timespec +{ + time_t tv_sec; + int tv_nsec; +} + +struct itimerspec +{ + timespec it_interval; + timespec it_value; +} + +CLOCK_REALTIME +TIMER_ABSTIME + +clockid_t +timer_t + +int clock_getres(clockid_t, timespec*); +int clock_gettime(clockid_t, timespec*); +int clock_settime(clockid_t, in timespec*); +int nanosleep(in timespec*, timespec*); +int timer_create(clockid_t, sigevent*, timer_t*); +int timer_delete(timer_t); +int timer_gettime(timer_t, itimerspec*); +int timer_getoverrun(timer_t); +int timer_settime(timer_t, int, in itimerspec*, itimerspec*); +*/ + +version( linux ) +{ + const CLOCK_PROCESS_CPUTIME_ID = 2; // (TMR|CPT) + const CLOCK_THREAD_CPUTIME_ID = 3; // (TMR|TCT) + + // NOTE: See above for why this is commented out. + // + //struct timespec + //{ + // time_t tv_sec; + // c_long tv_nsec; + //} + + struct itimerspec + { + timespec it_interval; + timespec it_value; + } + + const CLOCK_REALTIME = 0; + const TIMER_ABSTIME = 0x01; + + alias int clockid_t; + alias int timer_t; + + int clock_getres(clockid_t, timespec*); + //int clock_gettime(clockid_t, timespec*); + //int clock_settime(clockid_t, in timespec*); + int nanosleep(in timespec*, timespec*); + int timer_create(clockid_t, sigevent*, timer_t*); + int timer_delete(timer_t); + int timer_gettime(timer_t, itimerspec*); + int timer_getoverrun(timer_t); + int timer_settime(timer_t, int, in itimerspec*, itimerspec*); +} +else version( darwin ) +{ + int nanosleep(in timespec*, timespec*); +} +else version( freebsd ) +{ + const CLOCK_PROCESS_CPUTIME_ID = 2; // (TMR|CPT) + const CLOCK_THREAD_CPUTIME_ID = 3; // (TMR|TCT) + + // NOTE: See above for why this is commented out. + // + //struct timespec + //{ + // time_t tv_sec; + // c_long tv_nsec; + //} + + struct itimerspec + { + timespec it_interval; + timespec it_value; + } + + const CLOCK_REALTIME = 0; + const TIMER_ABSTIME = 0x01; + + alias int clockid_t; + alias int timer_t; + + int clock_getres(clockid_t, timespec*); + int clock_gettime(clockid_t, timespec*); + int clock_settime(clockid_t, in timespec*); + int nanosleep(in timespec*, timespec*); + int timer_create(clockid_t, sigevent*, timer_t*); + int timer_delete(timer_t); + int timer_gettime(timer_t, itimerspec*); + int timer_getoverrun(timer_t); + int timer_settime(timer_t, int, in itimerspec*, itimerspec*); +} + + +// +// Thread-Safe Functions (TSF) +// +/* +char* asctime_r(in tm*, char*); +char* ctime_r(in time_t*, char*); +tm* gmtime_r(in time_t*, tm*); +tm* localtime_r(in time_t*, tm*); +*/ + +version( linux ) +{ + char* asctime_r(in tm*, char*); + char* ctime_r(in time_t*, char*); + tm* gmtime_r(in time_t*, tm*); + tm* localtime_r(in time_t*, tm*); +} +else version( darwin ) +{ + char* asctime_r(in tm*, char*); + char* ctime_r(in time_t*, char*); + tm* gmtime_r(in time_t*, tm*); + tm* localtime_r(in time_t*, tm*); +} +else version( freebsd ) +{ + char* asctime_r(in tm*, char*); + char* ctime_r(in time_t*, char*); + tm* gmtime_r(in time_t*, tm*); + tm* localtime_r(in time_t*, tm*); +} + +// +// XOpen (XSI) +// +/* +getdate_err + +int daylight; +int timezone; + +tm* getdate(in char*); +char* strptime(in char*, in char*, tm*); +*/ + +version( linux ) +{ + extern int daylight; + extern c_long timezone; + + tm* getdate(in char*); + char* strptime(in char*, in char*, tm*); +} +else version( darwin ) +{ + extern c_long timezone; + + tm* getdate(in char*); + char* strptime(in char*, in char*, tm*); +} +else version( freebsd ) +{ + //tm* getdate(in char*); + char* strptime(in char*, in char*, tm*); +} diff --git a/import/stdc/posix/ucontext.d b/import/stdc/posix/ucontext.d new file mode 100644 index 0000000..21e6a6a --- /dev/null +++ b/import/stdc/posix/ucontext.d @@ -0,0 +1,155 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.ucontext; + +private import stdc.posix.config; +public import stdc.posix.signal; // for sigset_t, stack_t + +extern (C): + +// +// XOpen (XSI) +// +/* +mcontext_t + +struct ucontext_t +{ + ucontext_t* uc_link; + sigset_t uc_sigmask; + stack_t uc_stack; + mcontext_t uc_mcontext; +} +*/ + +version( linux ) +{ + + version( X86_64 ) + { + private + { + struct _libc_fpxreg + { + ushort[4] significand; + ushort exponent; + ushort[3] padding; + } + + struct _libc_xmmreg + { + uint[4] element; + } + + struct _libc_fpstate + { + ushort cwd; + ushort swd; + ushort ftw; + ushort fop; + ulong rip; + ulong rdp; + uint mxcsr; + uint mxcr_mask; + _libc_fpxreg[8] _st; + _libc_xmmreg[16] _xmm; + uint[24] padding; + } + + const NGREG = 23; + + alias c_long greg_t; + alias greg_t[NGREG] gregset_t; + alias _libc_fpstate* fpregset_t; + } + + struct mcontext_t + { + gregset_t gregs; + fpregset_t fpregs; + c_ulong[8] __reserved1; + } + + struct ucontext_t + { + c_ulong uc_flags; + ucontext_t* uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; + _libc_fpstate __fpregs_mem; + } + } + else version( X86 ) + { + private + { + struct _libc_fpreg + { + ushort[4] significand; + ushort exponent; + } + + struct _libc_fpstate + { + c_ulong cw; + c_ulong sw; + c_ulong tag; + c_ulong ipoff; + c_ulong cssel; + c_ulong dataoff; + c_ulong datasel; + _libc_fpreg[8] _st; + c_ulong status; + } + + const NGREG = 19; + + alias int greg_t; + alias greg_t[NGREG] gregset_t; + alias _libc_fpstate* fpregset_t; + } + + struct mcontext_t + { + gregset_t gregs; + fpregset_t fpregs; + c_ulong oldmask; + c_ulong cr2; + } + + struct ucontext_t + { + c_ulong uc_flags; + ucontext_t* uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; + _libc_fpstate __fpregs_mem; + } + } +} + +// +// Obsolescent (OB) +// +/* +int getcontext(ucontext_t*); +void makecontext(ucontext_t*, void function(), int, ...); +int setcontext(in ucontext_t*); +int swapcontext(ucontext_t*, in ucontext_t*); +*/ + +static if( is( ucontext_t ) ) +{ + int getcontext(ucontext_t*); + void makecontext(ucontext_t*, void function(), int, ...); + int setcontext(in ucontext_t*); + int swapcontext(ucontext_t*, in ucontext_t*); +} diff --git a/import/stdc/posix/unistd.d b/import/stdc/posix/unistd.d new file mode 100644 index 0000000..a40472d --- /dev/null +++ b/import/stdc/posix/unistd.d @@ -0,0 +1,589 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.unistd; + +private import stdc.posix.config; +private import stdc.stddef; +public import stdc.posix.inttypes; // for intptr_t +public import stdc.posix.sys.types; // for size_t, ssize_t, uid_t, gid_t, off_t, pid_t, useconds_t + +extern (C): + +const STDIN_FILENO = 0; +const STDOUT_FILENO = 1; +const STDERR_FILENO = 2; + +char* optarg; +int optind; +int opterr; +int optopt; + +int access(in char*, int); +uint alarm(uint); +int chdir(in char*); +int chown(in char*, uid_t, gid_t); +int close(int); +size_t confstr(int, char*, size_t); +int dup(int); +int dup2(int, int); +int execl(in char*, in char*, ...); +int execle(in char*, in char*, ...); +int execlp(in char*, in char*, ...); +int execv(in char*, in char**); +int execve(in char*, in char**, in char**); +int execvp(in char*, in char**); +void _exit(int); +int fchown(int, uid_t, gid_t); +pid_t fork(); +c_long fpathconf(int, int); +//int ftruncate(int, off_t); +char* getcwd(char*, size_t); +gid_t getegid(); +uid_t geteuid(); +gid_t getgid(); +int getgroups(int, gid_t *); +int gethostname(char*, size_t); +char* getlogin(); +int getlogin_r(char*, size_t); +int getopt(int, in char**, in char*); +pid_t getpgrp(); +pid_t getpid(); +pid_t getppid(); +uid_t getuid(); +int isatty(int); +int link(in char*, in char*); +//off_t lseek(int, off_t, int); +c_long pathconf(in char*, int); +int pause(); +int pipe(int[2]); +ssize_t read(int, void*, size_t); +ssize_t readlink(in char*, char*, size_t); +int rmdir(in char*); +int setegid(gid_t); +int seteuid(uid_t); +int setgid(gid_t); +int setpgid(pid_t, pid_t); +pid_t setsid(); +int setuid(uid_t); +uint sleep(uint); +int symlink(in char*, in char*); +c_long sysconf(int); +pid_t tcgetpgrp(int); +int tcsetpgrp(int, pid_t); +char* ttyname(int); +int ttyname_r(int, char*, size_t); +int unlink(in char*); +ssize_t write(int, in void*, size_t); + +version( linux ) +{ + static if( __USE_FILE_OFFSET64 ) + { + off_t lseek64(int, off_t, int); + alias lseek64 lseek; + } + else + { + off_t lseek(int, off_t, int); + } + static if( __USE_LARGEFILE64 ) + { + int ftruncate64(int, off_t); + alias ftruncate64 ftruncate; + } + else + { + int ftruncate(int, off_t); + } +} +else +{ + off_t lseek(int, off_t, int); + int ftruncate(int, off_t); +} + +version( linux ) +{ + const F_OK = 0; + const R_OK = 4; + const W_OK = 2; + const X_OK = 1; + + const F_ULOCK = 0; + const F_LOCK = 1; + const F_TLOCK = 2; + const F_TEST = 3; + + enum + { + _CS_PATH, + + _CS_V6_WIDTH_RESTRICTED_ENVS, + + _CS_GNU_LIBC_VERSION, + _CS_GNU_LIBPTHREAD_VERSION, + + _CS_LFS_CFLAGS = 1000, + _CS_LFS_LDFLAGS, + _CS_LFS_LIBS, + _CS_LFS_LINTFLAGS, + _CS_LFS64_CFLAGS, + _CS_LFS64_LDFLAGS, + _CS_LFS64_LIBS, + _CS_LFS64_LINTFLAGS, + + _CS_XBS5_ILP32_OFF32_CFLAGS = 1100, + _CS_XBS5_ILP32_OFF32_LDFLAGS, + _CS_XBS5_ILP32_OFF32_LIBS, + _CS_XBS5_ILP32_OFF32_LINTFLAGS, + _CS_XBS5_ILP32_OFFBIG_CFLAGS, + _CS_XBS5_ILP32_OFFBIG_LDFLAGS, + _CS_XBS5_ILP32_OFFBIG_LIBS, + _CS_XBS5_ILP32_OFFBIG_LINTFLAGS, + _CS_XBS5_LP64_OFF64_CFLAGS, + _CS_XBS5_LP64_OFF64_LDFLAGS, + _CS_XBS5_LP64_OFF64_LIBS, + _CS_XBS5_LP64_OFF64_LINTFLAGS, + _CS_XBS5_LPBIG_OFFBIG_CFLAGS, + _CS_XBS5_LPBIG_OFFBIG_LDFLAGS, + _CS_XBS5_LPBIG_OFFBIG_LIBS, + _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS, + + _CS_POSIX_V6_ILP32_OFF32_CFLAGS, + _CS_POSIX_V6_ILP32_OFF32_LDFLAGS, + _CS_POSIX_V6_ILP32_OFF32_LIBS, + _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS, + _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS, + _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS, + _CS_POSIX_V6_ILP32_OFFBIG_LIBS, + _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS, + _CS_POSIX_V6_LP64_OFF64_CFLAGS, + _CS_POSIX_V6_LP64_OFF64_LDFLAGS, + _CS_POSIX_V6_LP64_OFF64_LIBS, + _CS_POSIX_V6_LP64_OFF64_LINTFLAGS, + _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS, + _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS, + _CS_POSIX_V6_LPBIG_OFFBIG_LIBS, + _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS + } + + enum + { + _PC_LINK_MAX, + _PC_MAX_CANON, + _PC_MAX_INPUT, + _PC_NAME_MAX, + _PC_PATH_MAX, + _PC_PIPE_BUF, + _PC_CHOWN_RESTRICTED, + _PC_NO_TRUNC, + _PC_VDISABLE, + _PC_SYNC_IO, + _PC_ASYNC_IO, + _PC_PRIO_IO, + _PC_SOCK_MAXBUF, + _PC_FILESIZEBITS, + _PC_REC_INCR_XFER_SIZE, + _PC_REC_MAX_XFER_SIZE, + _PC_REC_MIN_XFER_SIZE, + _PC_REC_XFER_ALIGN, + _PC_ALLOC_SIZE_MIN, + _PC_SYMLINK_MAX, + _PC_2_SYMLINKS + } + + enum + { + _SC_ARG_MAX, + _SC_CHILD_MAX, + _SC_CLK_TCK, + _SC_NGROUPS_MAX, + _SC_OPEN_MAX, + _SC_STREAM_MAX, + _SC_TZNAME_MAX, + _SC_JOB_CONTROL, + _SC_SAVED_IDS, + _SC_REALTIME_SIGNALS, + _SC_PRIORITY_SCHEDULING, + _SC_TIMERS, + _SC_ASYNCHRONOUS_IO, + _SC_PRIORITIZED_IO, + _SC_SYNCHRONIZED_IO, + _SC_FSYNC, + _SC_MAPPED_FILES, + _SC_MEMLOCK, + _SC_MEMLOCK_RANGE, + _SC_MEMORY_PROTECTION, + _SC_MESSAGE_PASSING, + _SC_SEMAPHORES, + _SC_SHARED_MEMORY_OBJECTS, + _SC_AIO_LISTIO_MAX, + _SC_AIO_MAX, + _SC_AIO_PRIO_DELTA_MAX, + _SC_DELAYTIMER_MAX, + _SC_MQ_OPEN_MAX, + _SC_MQ_PRIO_MAX, + _SC_VERSION, + _SC_PAGESIZE, + _SC_PAGE_SIZE = _SC_PAGESIZE, + _SC_RTSIG_MAX, + _SC_SEM_NSEMS_MAX, + _SC_SEM_VALUE_MAX, + _SC_SIGQUEUE_MAX, + _SC_TIMER_MAX, + + _SC_BC_BASE_MAX, + _SC_BC_DIM_MAX, + _SC_BC_SCALE_MAX, + _SC_BC_STRING_MAX, + _SC_COLL_WEIGHTS_MAX, + _SC_EQUIV_CLASS_MAX, + _SC_EXPR_NEST_MAX, + _SC_LINE_MAX, + _SC_RE_DUP_MAX, + _SC_CHARCLASS_NAME_MAX, + + _SC_2_VERSION, + _SC_2_C_BIND, + _SC_2_C_DEV, + _SC_2_FORT_DEV, + _SC_2_FORT_RUN, + _SC_2_SW_DEV, + _SC_2_LOCALEDEF, + + _SC_PII, + _SC_PII_XTI, + _SC_PII_SOCKET, + _SC_PII_INTERNET, + _SC_PII_OSI, + _SC_POLL, + _SC_SELECT, + _SC_UIO_MAXIOV, + _SC_IOV_MAX = _SC_UIO_MAXIOV, + _SC_PII_INTERNET_STREAM, + _SC_PII_INTERNET_DGRAM, + _SC_PII_OSI_COTS, + _SC_PII_OSI_CLTS, + _SC_PII_OSI_M, + _SC_T_IOV_MAX, + + _SC_THREADS, + _SC_THREAD_SAFE_FUNCTIONS, + _SC_GETGR_R_SIZE_MAX, + _SC_GETPW_R_SIZE_MAX, + _SC_LOGIN_NAME_MAX, + _SC_TTY_NAME_MAX, + _SC_THREAD_DESTRUCTOR_ITERATIONS, + _SC_THREAD_KEYS_MAX, + _SC_THREAD_STACK_MIN, + _SC_THREAD_THREADS_MAX, + _SC_THREAD_ATTR_STACKADDR, + _SC_THREAD_ATTR_STACKSIZE, + _SC_THREAD_PRIORITY_SCHEDULING, + _SC_THREAD_PRIO_INHERIT, + _SC_THREAD_PRIO_PROTECT, + _SC_THREAD_PROCESS_SHARED, + + _SC_NPROCESSORS_CONF, + _SC_NPROCESSORS_ONLN, + _SC_PHYS_PAGES, + _SC_AVPHYS_PAGES, + _SC_ATEXIT_MAX, + _SC_PASS_MAX, + + _SC_XOPEN_VERSION, + _SC_XOPEN_XCU_VERSION, + _SC_XOPEN_UNIX, + _SC_XOPEN_CRYPT, + _SC_XOPEN_ENH_I18N, + _SC_XOPEN_SHM, + + _SC_2_CHAR_TERM, + _SC_2_C_VERSION, + _SC_2_UPE, + + _SC_XOPEN_XPG2, + _SC_XOPEN_XPG3, + _SC_XOPEN_XPG4, + + _SC_CHAR_BIT, + _SC_CHAR_MAX, + _SC_CHAR_MIN, + _SC_INT_MAX, + _SC_INT_MIN, + _SC_LONG_BIT, + _SC_WORD_BIT, + _SC_MB_LEN_MAX, + _SC_NZERO, + _SC_SSIZE_MAX, + _SC_SCHAR_MAX, + _SC_SCHAR_MIN, + _SC_SHRT_MAX, + _SC_SHRT_MIN, + _SC_UCHAR_MAX, + _SC_UINT_MAX, + _SC_ULONG_MAX, + _SC_USHRT_MAX, + + _SC_NL_ARGMAX, + _SC_NL_LANGMAX, + _SC_NL_MSGMAX, + _SC_NL_NMAX, + _SC_NL_SETMAX, + _SC_NL_TEXTMAX, + + _SC_XBS5_ILP32_OFF32, + _SC_XBS5_ILP32_OFFBIG, + _SC_XBS5_LP64_OFF64, + _SC_XBS5_LPBIG_OFFBIG, + + _SC_XOPEN_LEGACY, + _SC_XOPEN_REALTIME, + _SC_XOPEN_REALTIME_THREADS, + + _SC_ADVISORY_INFO, + _SC_BARRIERS, + _SC_BASE, + _SC_C_LANG_SUPPORT, + _SC_C_LANG_SUPPORT_R, + _SC_CLOCK_SELECTION, + _SC_CPUTIME, + _SC_THREAD_CPUTIME, + _SC_DEVICE_IO, + _SC_DEVICE_SPECIFIC, + _SC_DEVICE_SPECIFIC_R, + _SC_FD_MGMT, + _SC_FIFO, + _SC_PIPE, + _SC_FILE_ATTRIBUTES, + _SC_FILE_LOCKING, + _SC_FILE_SYSTEM, + _SC_MONOTONIC_CLOCK, + _SC_MULTI_PROCESS, + _SC_SINGLE_PROCESS, + _SC_NETWORKING, + _SC_READER_WRITER_LOCKS, + _SC_SPIN_LOCKS, + _SC_REGEXP, + _SC_REGEX_VERSION, + _SC_SHELL, + _SC_SIGNALS, + _SC_SPAWN, + _SC_SPORADIC_SERVER, + _SC_THREAD_SPORADIC_SERVER, + _SC_SYSTEM_DATABASE, + _SC_SYSTEM_DATABASE_R, + _SC_TIMEOUTS, + _SC_TYPED_MEMORY_OBJECTS, + _SC_USER_GROUPS, + _SC_USER_GROUPS_R, + _SC_2_PBS, + _SC_2_PBS_ACCOUNTING, + _SC_2_PBS_LOCATE, + _SC_2_PBS_MESSAGE, + _SC_2_PBS_TRACK, + _SC_SYMLOOP_MAX, + _SC_STREAMS, + _SC_2_PBS_CHECKPOINT, + + _SC_V6_ILP32_OFF32, + _SC_V6_ILP32_OFFBIG, + _SC_V6_LP64_OFF64, + _SC_V6_LPBIG_OFFBIG, + + _SC_HOST_NAME_MAX, + _SC_TRACE, + _SC_TRACE_EVENT_FILTER, + _SC_TRACE_INHERIT, + _SC_TRACE_LOG, + + _SC_LEVEL1_ICACHE_SIZE, + _SC_LEVEL1_ICACHE_ASSOC, + _SC_LEVEL1_ICACHE_LINESIZE, + _SC_LEVEL1_DCACHE_SIZE, + _SC_LEVEL1_DCACHE_ASSOC, + _SC_LEVEL1_DCACHE_LINESIZE, + _SC_LEVEL2_CACHE_SIZE, + _SC_LEVEL2_CACHE_ASSOC, + _SC_LEVEL2_CACHE_LINESIZE, + _SC_LEVEL3_CACHE_SIZE, + _SC_LEVEL3_CACHE_ASSOC, + _SC_LEVEL3_CACHE_LINESIZE, + _SC_LEVEL4_CACHE_SIZE, + _SC_LEVEL4_CACHE_ASSOC, + _SC_LEVEL4_CACHE_LINESIZE, + + _SC_IPV6 = _SC_LEVEL1_ICACHE_SIZE + 50, + _SC_RAW_SOCKETS + } +} +else version( darwin ) +{ + const F_OK = 0; + const R_OK = 4; + const W_OK = 2; + const X_OK = 1; + + const F_ULOCK = 0; + const F_LOCK = 1; + const F_TLOCK = 2; + const F_TEST = 3; +} +else version( freebsd ) +{ + const F_OK = 0; + const R_OK = 0x04; + const W_OK = 0x02; + const X_OK = 0x01; + + const F_ULOCK = 0; + const F_LOCK = 1; + const F_TLOCK = 2; + const F_TEST = 3; +} + +// +// File Synchronization (FSC) +// +/* +int fsync(int); +*/ + +// +// Synchronized I/O (SIO) +// +/* +int fdatasync(int); +*/ + +// +// XOpen (XSI) +// +/* +char* crypt(in char*, in char*); +char* ctermid(char*); +void encrypt(char[64], int); +int fchdir(int); +c_long gethostid(); +pid_t getpgid(pid_t); +pid_t getsid(pid_t); +char* getwd(char*); // LEGACY +int lchown(in char*, uid_t, gid_t); +int lockf(int, int, off_t); +int nice(int); +ssize_t pread(int, void*, size_t, off_t); +ssize_t pwrite(int, in void*, size_t, off_t); +pid_t setpgrp(); +int setregid(gid_t, gid_t); +int setreuid(uid_t, uid_t); +void swab(in void*, void*, ssize_t); +void sync(); +int truncate(in char*, off_t); +useconds_t ualarm(useconds_t, useconds_t); +int usleep(useconds_t); +pid_t vfork(); +*/ + +version( linux ) +{ + char* crypt(in char*, in char*); + char* ctermid(char*); + void encrypt(char[64], int); + int fchdir(int); + c_long gethostid(); + pid_t getpgid(pid_t); + pid_t getsid(pid_t); + char* getwd(char*); // LEGACY + int lchown(in char*, uid_t, gid_t); + //int lockf(int, int, off_t); + int nice(int); + //ssize_t pread(int, void*, size_t, off_t); + //ssize_t pwrite(int, in void*, size_t, off_t); + pid_t setpgrp(); + int setregid(gid_t, gid_t); + int setreuid(uid_t, uid_t); + void swab(in void*, void*, ssize_t); + void sync(); + //int truncate(in char*, off_t); + useconds_t ualarm(useconds_t, useconds_t); + int usleep(useconds_t); + pid_t vfork(); + + static if( __USE_LARGEFILE64 ) + { + int lockf64(int, int, off_t); + alias lockf64 lockf; + + ssize_t pread64(int, void*, size_t, off_t); + alias pread64 pread; + + ssize_t pwrite64(int, in void*, size_t, off_t); + alias pwrite64 pwrite; + + int truncate64(in char*, off_t); + alias truncate64 truncate; + } + else + { + int lockf(int, int, off_t); + ssize_t pread(int, void*, size_t, off_t); + ssize_t pwrite(int, in void*, size_t, off_t); + int truncate(in char*, off_t); + } +} +else version (darwin) +{ + char* crypt(in char*, in char*); + char* ctermid(char*); + void encrypt(char[64], int); + int fchdir(int); + c_long gethostid(); + pid_t getpgid(pid_t); + pid_t getsid(pid_t); + char* getwd(char*); // LEGACY + int lchown(in char*, uid_t, gid_t); + int lockf(int, int, off_t); + int nice(int); + ssize_t pread(int, void*, size_t, off_t); + ssize_t pwrite(int, in void*, size_t, off_t); + pid_t setpgrp(); + int setregid(gid_t, gid_t); + int setreuid(uid_t, uid_t); + void swab(in void*, void*, ssize_t); + void sync(); + int truncate(in char*, off_t); + useconds_t ualarm(useconds_t, useconds_t); + int usleep(useconds_t); + pid_t vfork(); +} +else version (freebsd) +{ + char* crypt(in char*, in char*); + //char* ctermid(char*); + void encrypt(char*, int); + int fchdir(int); + c_long gethostid(); + int getpgid(pid_t); + int getsid(pid_t); + char* getwd(char*); // LEGACY + int lchown(in char*, uid_t, gid_t); + int lockf(int, int, off_t); + int nice(int); + ssize_t pread(int, void*, size_t, off_t); + ssize_t pwrite(int, in void*, size_t, off_t); + int setpgrp(pid_t, pid_t); + int setregid(gid_t, gid_t); + int setreuid(uid_t, uid_t); + void swab(in void*, void*, ssize_t); + void sync(); + int truncate(in char*, off_t); + useconds_t ualarm(useconds_t, useconds_t); + int usleep(useconds_t); + pid_t vfork(); +} diff --git a/import/stdc/posix/utime.d b/import/stdc/posix/utime.d new file mode 100644 index 0000000..947e0f6 --- /dev/null +++ b/import/stdc/posix/utime.d @@ -0,0 +1,58 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module stdc.posix.utime; + +private import stdc.posix.config; +public import stdc.posix.sys.types; // for time_t + +extern (C): + +// +// Required +// +/* +struct utimbuf +{ + time_t actime; + time_t modtime; +} + +int utime(in char*, in utimbuf*); +*/ + +version( linux ) +{ + struct utimbuf + { + time_t actime; + time_t modtime; + } + + int utime(in char*, in utimbuf*); +} +else version( darwin ) +{ + struct utimbuf + { + time_t actime; + time_t modtime; + } + + int utime(in char*, in utimbuf*); +} +else version( freebsd ) +{ + struct utimbuf + { + time_t actime; + time_t modtime; + } + + int utime(in char*, in utimbuf*); +} diff --git a/import/stdc/signal.d b/import/stdc/signal.d new file mode 100644 index 0000000..b7ce585 --- /dev/null +++ b/import/stdc/signal.d @@ -0,0 +1,48 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.signal; + +extern (C): + +// this should be volatile +alias int sig_atomic_t; + +private alias void function(int) sigfn_t; + +version( Posix ) +{ + const SIG_ERR = cast(sigfn_t) -1; + const SIG_DFL = cast(sigfn_t) 0; + const SIG_IGN = cast(sigfn_t) 1; + + // standard C signals + const SIGABRT = 6; // Abnormal termination + const SIGFPE = 8; // Floating-point error + const SIGILL = 4; // Illegal hardware instruction + const SIGINT = 2; // Terminal interrupt character + const SIGSEGV = 11; // Invalid memory reference + const SIGTERM = 15; // Termination +} +else +{ + const SIG_ERR = cast(sigfn_t) -1; + const SIG_DFL = cast(sigfn_t) 0; + const SIG_IGN = cast(sigfn_t) 1; + + // standard C signals + const SIGABRT = 22; // Abnormal termination + const SIGFPE = 8; // Floating-point error + const SIGILL = 4; // Illegal hardware instruction + const SIGINT = 2; // Terminal interrupt character + const SIGSEGV = 11; // Invalid memory reference + const SIGTERM = 15; // Termination +} + +sigfn_t signal(int sig, sigfn_t func); +int raise(int sig); diff --git a/import/stdc/stdarg.d b/import/stdc/stdarg.d new file mode 100644 index 0000000..afdbceb --- /dev/null +++ b/import/stdc/stdarg.d @@ -0,0 +1,47 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Hauke Duden, Walter Bright + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.stdarg; + + +version( GNU ) +{ + public import std.c.stdarg; +} +else +{ + alias void* va_list; + + template va_start( T ) + { + void va_start( out va_list ap, inout T parmn ) + { + ap = cast(va_list) ( cast(void*) &parmn + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) ); + } + } + + template va_arg( T ) + { + T va_arg( 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; + } + } + + void va_end( va_list ap ) + { + + } + + void va_copy( out va_list dest, va_list src ) + { + dest = src; + } +} diff --git a/import/stdc/stddef.d b/import/stdc/stddef.d new file mode 100644 index 0000000..e6a5bf7 --- /dev/null +++ b/import/stdc/stddef.d @@ -0,0 +1,33 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.stddef; + +extern (C): + +//alias typeof(int.sizeof) size_t; +//alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; + +version( Windows ) +{ + alias wchar wint_t; + alias wchar wchar_t; + alias wchar wctype_t; + alias wchar wctrans_t; + + const wchar WEOF = 0xFFFF; +} +else +{ + alias dchar wint_t; + alias dchar wchar_t; + alias dchar wctype_t; + alias dchar wctrans_t; + + const dchar WEOF = 0xFFFF; +} diff --git a/import/stdc/stdint.d b/import/stdc/stdint.d new file mode 100644 index 0000000..5db5c6a --- /dev/null +++ b/import/stdc/stdint.d @@ -0,0 +1,151 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.stdint; + +private +{ + template typify(T) + { + T typify( T val ) { return val; } + } +} + +extern (C): + +alias byte int8_t; +alias short int16_t; +alias int int32_t; +alias long int64_t; +//alias cent int128_t; + +alias ubyte uint8_t; +alias ushort uint16_t; +alias uint uint32_t; +alias ulong uint64_t; +//alias ucent uint128_t; + +alias byte int_least8_t; +alias short int_least16_t; +alias int int_least32_t; +alias long int_least64_t; + +alias ubyte uint_least8_t; +alias ushort uint_least16_t; +alias uint uint_least32_t; +alias ulong uint_least64_t; + +alias byte int_fast8_t; +alias int int_fast16_t; +alias int int_fast32_t; +alias long int_fast64_t; + +alias ubyte uint_fast8_t; +alias uint uint_fast16_t; +alias uint uint_fast32_t; +alias ulong uint_fast64_t; + +version( X86_64 ) +{ + alias long intptr_t; + alias ulong uintptr_t; +} +else +{ + alias int intptr_t; + alias uint uintptr_t; +} + +alias long intmax_t; +alias ulong uintmax_t; + +version( VerboseC ) +{ + private import stdc.stddef; + private import stdc.signal; // for sig_atomic_t + + const int8_t INT8_MIN = int8_t.min; + const int8_t INT8_MAX = int8_t.max; + const int16_t INT16_MIN = int16_t.min; + const int16_t INT16_MAX = int16_t.max; + const int32_t INT32_MIN = int32_t.min; + const int32_t INT32_MAX = int32_t.max; + const int64_t INT64_MIN = int64_t.min; + const int64_t INT64_MAX = int64_t.max; + + const uint8_t UINT8_MAX = uint8_t.max; + const uint16_t UINT16_MAX = uint16_t.max; + const uint32_t UINT32_MAX = uint32_t.max; + const uint64_t UINT64_MAX = uint64_t.max; + + const int_least8_t INT_LEAST8_MIN = int_least8_t.min; + const int_least8_t INT_LEAST8_MAX = int_least8_t.max; + const int_least16_t INT_LEAST16_MIN = int_least16_t.min; + const int_least16_t INT_LEAST16_MAX = int_least16_t.max; + const int_least32_t INT_LEAST32_MIN = int_least32_t.min; + const int_least32_t INT_LEAST32_MAX = int_least32_t.max; + const int_least64_t INT_LEAST64_MIN = int_least64_t.min; + const int_least64_t INT_LEAST64_MAX = int_least64_t.max; + + const uint_least8_t UINT_LEAST8_MAX = uint_least8_t.max; + const uint_least16_t UINT_LEAST16_MAX = uint_least16_t.max; + const uint_least32_t UINT_LEAST32_MAX = uint_least32_t.max; + const uint_least64_t UINT_LEAST64_MAX = uint_least64_t.max; + + const int_fast8_t INT_FAST8_MIN = int_fast8_t.min; + const int_fast8_t INT_FAST8_MAX = int_fast8_t.max; + const int_fast16_t INT_FAST16_MIN = int_fast16_t.min; + const int_fast16_t INT_FAST16_MAX = int_fast16_t.max; + const int_fast32_t INT_FAST32_MIN = int_fast32_t.min; + const int_fast32_t INT_FAST32_MAX = int_fast32_t.max; + const int_fast64_t INT_FAST64_MIN = int_fast64_t.min; + const int_fast64_t INT_FAST64_MAX = int_fast64_t.max; + + const uint_fast8_t UINT_FAST8_MAX = uint_fast8_t.max; + const uint_fast16_t UINT_FAST16_MAX = uint_fast16_t.max; + const uint_fast32_t UINT_FAST32_MAX = uint_fast32_t.max; + const uint_fast64_t UINT_FAST64_MAX = uint_fast64_t.max; + + const intptr_t INTPTR_MIN = intptr_t.min; + const intptr_t INTPTR_MAX = intptr_t.max; + + const uintptr_t UINTPTR_MIN = uintptr_t.min; + const uintptr_t UINTPTR_MAX = uintptr_t.max; + + const intmax_t INTMAX_MIN = intmax_t.min; + const intmax_t INTMAX_MAX = intmax_t.max; + + const uintmax_t UINTMAX_MAX = uintmax_t.max; + + const ptrdiff_t PTRDIFF_MIN = ptrdiff_t.min; + const ptrdiff_t PTRDIFF_MAX = ptrdiff_t.max; + + const sig_atomic_t SIG_ATOMIC_MIN = sig_atomic_t.min; + const sig_atomic_t SIG_ATOMIC_MAX = sig_atomic_t.max; + + const size_t SIZE_MAX = size_t.max; + + const wchar_t WCHAR_MIN = wchar_t.min; + const wchar_t WCHAR_MAX = wchar_t.max; + + const wint_t WINT_MIN = wint_t.min; + const wint_t WINT_MAX = wint_t.max; +} + +alias typify!(int8_t) INT8_C; +alias typify!(int16_t) INT16_C; +alias typify!(int32_t) INT32_C; +alias typify!(int64_t) INT64_C; + +alias typify!(uint8_t) UINT8_C; +alias typify!(uint16_t) UINT16_C; +alias typify!(uint32_t) UINT32_C; +alias typify!(uint64_t) UINT64_C; + +alias typify!(intmax_t) INTMAX_C; +alias typify!(uintmax_t) UINTMAX_C; diff --git a/import/stdc/stdio.d b/import/stdc/stdio.d new file mode 100644 index 0000000..f988a41 --- /dev/null +++ b/import/stdc/stdio.d @@ -0,0 +1,445 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly, Walter Bright + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.stdio; + +private +{ + import stdc.stdarg; + import stdc.stddef; + import stdc.config; +} + +extern (C): + +version( Windows ) +{ + const int BUFSIZ = 0x4000; + const int EOF = -1; + const int FOPEN_MAX = 20; + const int FILENAME_MAX = 256; // 255 plus NULL + const int TMP_MAX = 32767; + const int _SYS_OPEN = 20; + const int SYS_OPEN = _SYS_OPEN; + + const int _NFILE = 60; + const char[] _P_tmpdir = "\\"; + const wchar[] _wP_tmpdir = "\\"; + const int L_tmpnam = _P_tmpdir.length + 12; +} +else version( linux ) +{ + //const int BUFSIZ = 0x4000; + const int EOF = -1; + const int FOPEN_MAX = 16; + const int FILENAME_MAX = 4095; + const int TMP_MAX = 238328; + const int L_tmpnam = 20; +} +else version( darwin ) +{ + const int EOF = -1; + const int FOPEN_MAX = 20; + const int FILENAME_MAX = 1024; + const int TMP_MAX = 308915776; + const int L_tmpnam = 1024; + + private + { + struct __sbuf + { + ubyte* _base; + int _size; + } + + struct __sFILEX + { + + } + } +} +else version ( freebsd ) +{ + const int EOF = -1; + const int FOPEN_MAX = 20; + const int FILENAME_MAX = 1024; + const int TMP_MAX = 308915776; + const int L_tmpnam = 1024; + + private + { + struct __sbuf + { + ubyte *_base; + int _size; + } + struct __sFILEX + { + } + } +} +else +{ + static assert( false ); +} + +enum +{ + SEEK_SET, + SEEK_CUR, + SEEK_END +} + +struct _iobuf +{ + align (1): + version( Windows ) + { + char* _ptr; + int _cnt; + char* _base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + int __tmpnum; + } + else version( linux ) + { + char* _read_ptr; + char* _read_end; + char* _read_base; + char* _write_base; + char* _write_ptr; + char* _write_end; + char* _buf_base; + char* _buf_end; + char* _save_base; + char* _backup_base; + char* _save_end; + void* _markers; + _iobuf* _chain; + int _fileno; + int _blksize; + int _old_offset; + ushort _cur_column; + byte _vtable_offset; + char[1] _shortbuf; + void* _lock; + } + else version( darwin ) + { + ubyte* _p; + int _r; + int _w; + short _flags; + short _file; + __sbuf _bf; + int _lbfsize; + + int* function(void*) _close; + int* function(void*, char*, int) _read; + fpos_t* function(void*, fpos_t, int) _seek; + int* function(void*, char *, int) _write; + + __sbuf _ub; + __sFILEX* _extra; + int _ur; + + ubyte[3] _ubuf; + ubyte[1] _nbuf; + + __sbuf _lb; + + int _blksize; + fpos_t _offset; + } + else version( freebsd ) + { + ubyte* _p; + int _r; + int _w; + short _flags; + short _file; + __sbuf _bf; + int _lbfsize; + + void* function() _cookie; + int* function(void*) _close; + int* function(void*, char*, int) _read; + fpos_t* function(void*, fpos_t, int) _seek; + int* function(void*, char *, int) _write; + + __sbuf _ub; + __sFILEX* _extra; + int _ur; + + ubyte[3] _ubuf; + ubyte[1] _nbuf; + + __sbuf _lb; + + int _blksize; + fpos_t _offset; + } + else + { + static assert( false ); + } +} + +alias _iobuf FILE; + +enum +{ + _F_RDWR = 0x0003, + _F_READ = 0x0001, + _F_WRIT = 0x0002, + _F_BUF = 0x0004, + _F_LBUF = 0x0008, + _F_ERR = 0x0010, + _F_EOF = 0x0020, + _F_BIN = 0x0040, + _F_IN = 0x0080, + _F_OUT = 0x0100, + _F_TERM = 0x0200, +} + +version( Windows ) +{ + enum + { + _IOFBF = 0, + _IOREAD = 1, + _IOWRT = 2, + _IONBF = 4, + _IOMYBUF = 8, + _IOEOF = 0x10, + _IOERR = 0x20, + _IOLBF = 0x40, + _IOSTRG = 0x40, + _IORW = 0x80, + _IOTRAN = 0x100, + _IOAPP = 0x200, + } + + extern void function() _fcloseallp; + + version (GNU) + { + extern FILE[_NFILE]* _imp___iob; + + const FILE* stdin; + const FILE* stdout; + const FILE* stderr; + const FILE* stdaux; + const FILE* stdprn; + + static this() + { + stdin = &(*_imp___iob)[0]; + stdout = &(*_imp___iob)[1]; + stderr = &(*_imp___iob)[2]; + stdaux = &(*_imp___iob)[3]; + stdprn = &(*_imp___iob)[4]; + } + } + else + { + extern FILE[_NFILE] _iob; + + const FILE* stdin = &_iob[0]; + const FILE* stdout = &_iob[1]; + const FILE* stderr = &_iob[2]; + const FILE* stdaux = &_iob[3]; + const FILE* stdprn = &_iob[4]; + } +} +else version( linux ) +{ + enum + { + _IOFBF = 0, + _IOLBF = 1, + _IONBF = 2, + } + + extern FILE* stdin; + extern FILE* stdout; + extern FILE* stderr; +} +else version( darwin ) +{ + extern FILE* __stdinp; + extern FILE* __stdoutp; + extern FILE* __stderrp; + + const FILE* stdin; + const FILE* stdout; + const FILE* stderr; + + static this() + { + stdin = __stdinp; + stdout = __stdoutp; + stderr = __stderrp; + } +} +else version( freebsd ) +{ + extern FILE[3] __sF; + + const FILE* stdin = &__sF[0]; + const FILE* stdout = &__sF[1]; + const FILE* stderr = &__sF[2]; +} +else +{ + static assert( false ); +} + +alias int fpos_t; + +int remove(in char* filename); +int rename(in char* from, in char* to); + +FILE* tmpfile(); +char* tmpnam(char* s); + +int fclose(FILE* stream); +int fflush(FILE* stream); +FILE* fopen(in char* filename, in char* mode); +FILE* freopen(in char* filename, in char* mode, FILE* stream); + +void setbuf(FILE* stream, char* buf); +int setvbuf(FILE* stream, char* buf, int mode, size_t size); + +int fprintf(FILE* stream, in char* format, ...); +int fscanf(FILE* stream, in char* format, ...); +int sprintf(char* s, in char* format, ...); +int sscanf(in char* s, in char* format, ...); +int vfprintf(FILE* stream, in char* format, va_list arg); +int vfscanf(FILE* stream, in char* format, va_list arg); +int vsprintf(char* s, in char* format, va_list arg); +int vsscanf(in char* s, in char* format, va_list arg); +int vprintf(in char* format, va_list arg); +int vscanf(in char* format, va_list arg); +int printf(in char* format, ...); +int scanf(in char* format, ...); + +int fgetc(FILE* stream); +int fputc(int c, FILE* stream); + +char* fgets(char* s, int n, FILE* stream); +int fputs(in char* s, FILE* stream); +char* gets(char* s); +int puts(in char* s); + +extern (D) +{ + int getchar() { return getc(stdin); } + int putchar(int c) { return putc(c,stdout); } + int getc(FILE* stream) { return fgetc(stream); } + int putc(int c, FILE* stream) { return fputc(c,stream); } +} + +int ungetc(int c, FILE* stream); + +size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream); +size_t fwrite(in void* ptr, size_t size, size_t nmemb, FILE* stream); + +int fgetpos(FILE* stream, fpos_t * pos); +int fsetpos(FILE* stream, in fpos_t* pos); + +int fseek(FILE* stream, c_long offset, int whence); +c_long ftell(FILE* stream); + +version( Windows ) +{ + extern (D) + { + void rewind(FILE* stream) { fseek(stream,0L,SEEK_SET); stream._flag&=~_IOERR; } + void clearerr(FILE* stream) { stream._flag &= ~(_IOERR|_IOEOF); } + int feof(FILE* stream) { return stream._flag&_IOEOF; } + int ferror(FILE* stream) { return stream._flag&_IOERR; } + } + int _snprintf(char* s, size_t n, in char* fmt, ...); + alias _snprintf snprintf; + + int _vsnprintf(char* s, size_t n, in char* format, va_list arg); + alias _vsnprintf vsnprintf; +} +else version( linux ) +{ + void rewind(FILE* stream); + void clearerr(FILE* stream); + int feof(FILE* stream); + int ferror(FILE* stream); + int fileno(FILE *); + + int snprintf(char* s, size_t n, in char* format, ...); + int vsnprintf(char* s, size_t n, in char* format, va_list arg); +} +else version( darwin ) +{ + void rewind(FILE*); + void clearerr(FILE*); + int feof(FILE*); + int ferror(FILE*); + int fileno(FILE*); + + int snprintf(char* s, size_t n, in char* format, ...); + int vsnprintf(char* s, size_t n, in char* format, va_list arg); +} +else version( freebsd ) +{ + void rewind(FILE*); + void clearerr(FILE*); + int feof(FILE*); + int ferror(FILE*); + int fileno(FILE*); + + int snprintf(char* s, size_t n, in char* format, ...); + int vsnprintf(char* s, size_t n, in char* format, va_list arg); +} +else +{ + static assert( false ); +} + +void perror(in char* s); + +int fwprintf(FILE* stream, in wchar_t* format, ...); +int fwscanf(FILE* stream, in wchar_t* format, ...); +int swprintf(wchar_t* s, size_t n, in wchar_t* format, ...); +int swscanf(in wchar_t* s, in wchar_t* format, ...); +int vfwprintf(FILE* stream, in wchar_t* format, va_list arg); +int vfwscanf(FILE* stream, in wchar_t* format, va_list arg); +int vswprintf(wchar_t* s, size_t n, in wchar_t* format, va_list arg); +int vswscanf(in wchar_t* s, in wchar_t* format, va_list arg); +int vwprintf(in wchar_t* format, va_list arg); +int vwscanf(in wchar_t* format, va_list arg); +int wprintf(in wchar_t* format, ...); +int wscanf(in wchar_t* format, ...); + +wint_t fgetwc(FILE* stream); +wint_t fputwc(wchar_t c, FILE* stream); + +wchar_t* fgetws(wchar_t* s, int n, FILE* stream); +int fputws(in wchar_t* s, FILE* stream); + +extern (D) +{ + wint_t getwchar() { return fgetwc(stdin); } + wint_t putwchar(wchar_t c) { return fputwc(c,stdout); } + wint_t getwc(FILE* stream) { return fgetwc(stream); } + wint_t putwc(wchar_t c, FILE* stream) { return fputwc(c, stream); } +} + +wint_t ungetwc(wint_t c, FILE* stream); +int fwide(FILE* stream, int mode); diff --git a/import/stdc/stdlib.d b/import/stdc/stdlib.d new file mode 100644 index 0000000..2ed0b4d --- /dev/null +++ b/import/stdc/stdlib.d @@ -0,0 +1,101 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.stdlib; + +private import stdc.stddef; +private import stdc.config; + +extern (C): + +struct div_t +{ + int quot, + rem; +} + +struct ldiv_t +{ + int quot, + rem; +} + +struct lldiv_t +{ + long quot, + rem; +} + +const EXIT_SUCCESS = 0; +const EXIT_FAILURE = 1; +const RAND_MAX = 32767; +const MB_CUR_MAX = 1; + +double atof(in char* nptr); +int atoi(in char* nptr); +c_long atol(in char* nptr); +long atoll(in char* nptr); + +double strtod(in char* nptr, char** endptr); +float strtof(in char* nptr, char** endptr); +real strtold(in char* nptr, char** endptr); +c_long strtol(in char* nptr, char** endptr, int base); +long strtoll(in char* nptr, char** endptr, int base); +c_ulong strtoul(in char* nptr, char** endptr, int base); +ulong strtoull(in char* nptr, char** endptr, int base); + +double wcstod(in wchar_t* nptr, wchar_t** endptr); +float wcstof(in wchar_t* nptr, wchar_t** endptr); +real wcstold(in wchar_t* nptr, wchar_t** endptr); +c_long wcstol(in wchar_t* nptr, wchar_t** endptr, int base); +long wcstoll(in wchar_t* nptr, wchar_t** endptr, int base); +c_ulong wcstoul(in wchar_t* nptr, wchar_t** endptr, int base); +ulong wcstoull(in wchar_t* nptr, wchar_t** endptr, int base); + +int rand(); +void srand(uint seed); + +void* malloc(size_t size); +void* calloc(size_t nmemb, size_t size); +void* realloc(void* ptr, size_t size); +void free(void* ptr); + +void abort(); +void exit(int status); +int atexit(void function() func); +void _Exit(int status); + +char* getenv(in char* name); +int system(in char* string); + +void* bsearch(in void* key, in void* base, size_t nmemb, size_t size, int function(in void*, in void*) compar); +void qsort(void* base, size_t nmemb, size_t size, int function(in void*, in void*) compar); + +int abs(int j); +c_long labs(c_long j); +long llabs(long j); + +div_t div(int numer, int denom); +ldiv_t ldiv(c_long numer, c_long denom); +lldiv_t lldiv(long numer, long denom); + +int mblen(in char* s, size_t n); +int mbtowc(wchar_t* pwc, in char* s, size_t n); +int wctomb(char*s, wchar_t wc); +size_t mbstowcs(wchar_t* pwcs, in char* s, size_t n); +size_t wcstombs(char* s, in wchar_t* pwcs, size_t n); + +version( DigitalMars ) +{ + void* alloca(size_t size); +} +else version( GNU ) +{ + private import gcc.builtins; + alias gcc.builtins.__builtin_alloca alloca; +} diff --git a/import/stdc/string.d b/import/stdc/string.d new file mode 100644 index 0000000..880ce38 --- /dev/null +++ b/import/stdc/string.d @@ -0,0 +1,76 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.string; + +private import stdc.stddef; + +extern (C): + +void* memchr(in void* s, int c, size_t n); +int memcmp(in void* s1, in void* s2, size_t n); +void* memcpy(void* s1, in void* s2, size_t n); +void* memmove(void* s1, in void* s2, size_t n); +void* memset(void* s, int c, size_t n); + +char* strcpy(char* s1, in char* s2); +char* strncpy(char* s1, in char* s2, size_t n); +char* strcat(char* s1, in char* s2); +char* strncat(char* s1, in char* s2, size_t n); +int strcmp(in char* s1, in char* s2); +int strcoll(in char* s1, in char* s2); +int strncmp(in char* s1, in char* s2, size_t n); +size_t strxfrm(char* s1, in char* s2, size_t n); +char* strchr(in char* s, int c); +size_t strcspn(in char* s1, in char* s2); +char* strpbrk(in char* s1, in char* s2); +char* strrchr(in char* s, int c); +size_t strspn(in char* s1, in char* s2); +char* strstr(in char* s1, in char* s2); +char* strtok(char* s1, in char* s2); +char* strerror(int errnum); +size_t strlen(in char* s); + +version( Posix ) +{ + char* strdup(char*); +} + +wchar_t* wmemchr(in wchar_t* s, wchar_t c, size_t n); +int wmemcmp(in wchar_t* s1, in wchar_t* s2, size_t n); +wchar_t* wmemcpy(wchar_t* s1, in wchar_t* s2, size_t n); +wchar_t* wmemmove(wchar_t*s1, in wchar_t* s2, size_t n); +wchar_t* wmemset(wchar_t* s, wchar_t c, size_t n); + +wchar_t* wcscpy(wchar_t* s1, in wchar_t* s2); +wchar_t* wcsncpy(wchar_t* s1, in wchar_t* s2, size_t n); +wchar_t* wcscat(wchar_t* s1, in wchar_t* s2); +wchar_t* wcsncat(wchar_t* s1, in wchar_t* s2, size_t n); +int wcscmp(in wchar_t* s1, in wchar_t* s2); +int wcscoll(in wchar_t* s1, in wchar_t* s2); +int wcsncmp(in wchar_t* s1, in wchar_t* s2, size_t n); +size_t wcsxfrm(wchar_t* s1, in wchar_t* s2, size_t n); +wchar_t* wcschr(in wchar_t* s, wchar_t c); +size_t wcscspn(in wchar_t* s1, in wchar_t* s2); +wchar_t* wcspbrk(in wchar_t* s1, in wchar_t* s2); +wchar_t* wcsrchr(in wchar_t* s, wchar_t c); +size_t wcsspn(in wchar_t* s1, in wchar_t* s2); +wchar_t* wcsstr(in wchar_t* s1, in wchar_t* s2); +wchar_t* wcstok(wchar_t* s1, in wchar_t* s2, wchar_t** ptr); +size_t wcslen(wchar_t* s); + +alias int mbstate_t; + +wint_t btowc(int c); +int wctob(wint_t c); +int mbsinit(in mbstate_t* ps); +size_t mbrlen(in char* s, size_t n, mbstate_t* ps); +size_t mbrtowc(wchar_t* pwc, in char* s, size_t n, mbstate_t* ps); +size_t wcrtomb(char* s, wchar_t wc, mbstate_t* ps); +size_t mbsrtowcs(wchar_t* dst, in char** src, size_t len, mbstate_t* ps); +size_t wcsrtombs(char* dst, in wchar_t** src, size_t len, mbstate_t* ps); diff --git a/import/stdc/tgmath.d b/import/stdc/tgmath.d new file mode 100644 index 0000000..5ace9c5 --- /dev/null +++ b/import/stdc/tgmath.d @@ -0,0 +1,331 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly, Walter Bright + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.tgmath; + +private import stdc.config; +private static import stdc.math; +private static import stdc.complex; + +extern (C): + +alias stdc.math.acos acos; +alias stdc.math.acosf acos; +alias stdc.math.acosl acos; + +alias stdc.complex.cacos acos; +alias stdc.complex.cacosf acos; +alias stdc.complex.cacosl acos; + +alias stdc.math.asin asin; +alias stdc.math.asinf asin; +alias stdc.math.asinl asin; + +alias stdc.complex.casin asin; +alias stdc.complex.casinf asin; +alias stdc.complex.casinl asin; + +alias stdc.math.atan atan; +alias stdc.math.atanf atan; +alias stdc.math.atanl atan; + +alias stdc.complex.catan atan; +alias stdc.complex.catanf atan; +alias stdc.complex.catanl atan; + +alias stdc.math.atan2 atan2; +alias stdc.math.atan2f atan2; +alias stdc.math.atan2l atan2; + +alias stdc.math.cos cos; +alias stdc.math.cosf cos; +alias stdc.math.cosl cos; + +alias stdc.complex.ccos cos; +alias stdc.complex.ccosf cos; +alias stdc.complex.ccosl cos; + +alias stdc.math.sin sin; +alias stdc.math.sinf sin; +alias stdc.math.sinl sin; + +alias stdc.complex.csin csin; +alias stdc.complex.csinf csin; +alias stdc.complex.csinl csin; + +alias stdc.math.tan tan; +alias stdc.math.tanf tan; +alias stdc.math.tanl tan; + +alias stdc.complex.ctan tan; +alias stdc.complex.ctanf tan; +alias stdc.complex.ctanl tan; + +alias stdc.math.acosh acosh; +alias stdc.math.acoshf acosh; +alias stdc.math.acoshl acosh; + +alias stdc.complex.cacosh acosh; +alias stdc.complex.cacoshf acosh; +alias stdc.complex.cacoshl acosh; + +alias stdc.math.asinh asinh; +alias stdc.math.asinhf asinh; +alias stdc.math.asinhl asinh; + +alias stdc.complex.casinh asinh; +alias stdc.complex.casinhf asinh; +alias stdc.complex.casinhl asinh; + +alias stdc.math.atanh atanh; +alias stdc.math.atanhf atanh; +alias stdc.math.atanhl atanh; + +alias stdc.complex.catanh atanh; +alias stdc.complex.catanhf atanh; +alias stdc.complex.catanhl atanh; + +alias stdc.math.cosh cosh; +alias stdc.math.coshf cosh; +alias stdc.math.coshl cosh; + +alias stdc.complex.ccosh cosh; +alias stdc.complex.ccoshf cosh; +alias stdc.complex.ccoshl cosh; + +alias stdc.math.sinh sinh; +alias stdc.math.sinhf sinh; +alias stdc.math.sinhl sinh; + +alias stdc.complex.csinh sinh; +alias stdc.complex.csinhf sinh; +alias stdc.complex.csinhl sinh; + +alias stdc.math.tanh tanh; +alias stdc.math.tanhf tanh; +alias stdc.math.tanhl tanh; + +alias stdc.complex.ctanh tanh; +alias stdc.complex.ctanhf tanh; +alias stdc.complex.ctanhl tanh; + +alias stdc.math.exp exp; +alias stdc.math.expf exp; +alias stdc.math.expl exp; + +alias stdc.complex.cexp exp; +alias stdc.complex.cexpf exp; +alias stdc.complex.cexpl exp; + +alias stdc.math.exp2 exp2; +alias stdc.math.exp2f exp2; +alias stdc.math.exp2l exp2; + +alias stdc.math.expm1 expm1; +alias stdc.math.expm1f expm1; +alias stdc.math.expm1l expm1; + +alias stdc.math.frexp frexp; +alias stdc.math.frexpf frexp; +alias stdc.math.frexpl frexp; + +alias stdc.math.ilogb ilogb; +alias stdc.math.ilogbf ilogb; +alias stdc.math.ilogbl ilogb; + +alias stdc.math.ldexp ldexp; +alias stdc.math.ldexpf ldexp; +alias stdc.math.ldexpl ldexp; + +alias stdc.math.log log; +alias stdc.math.logf log; +alias stdc.math.logl log; + +alias stdc.complex.clog log; +alias stdc.complex.clogf log; +alias stdc.complex.clogl log; + +alias stdc.math.log10 log10; +alias stdc.math.log10f log10; +alias stdc.math.log10l log10; + +alias stdc.math.log1p log1p; +alias stdc.math.log1pf log1p; +alias stdc.math.log1pl log1p; + +alias stdc.math.log2 log1p; +alias stdc.math.log2f log1p; +alias stdc.math.log2l log1p; + +alias stdc.math.logb log1p; +alias stdc.math.logbf log1p; +alias stdc.math.logbl log1p; + +alias stdc.math.modf modf; +alias stdc.math.modff modf; +alias stdc.math.modfl modf; + +alias stdc.math.scalbn scalbn; +alias stdc.math.scalbnf scalbn; +alias stdc.math.scalbnl scalbn; + +alias stdc.math.scalbln scalbln; +alias stdc.math.scalblnf scalbln; +alias stdc.math.scalblnl scalbln; + +alias stdc.math.cbrt cbrt; +alias stdc.math.cbrtf cbrt; +alias stdc.math.cbrtl cbrt; + +alias stdc.math.fabs fabs; +alias stdc.math.fabsf fabs; +alias stdc.math.fabsl fabs; + +alias stdc.complex.cabs fabs; +alias stdc.complex.cabsf fabs; +alias stdc.complex.cabsl fabs; + +alias stdc.math.hypot hypot; +alias stdc.math.hypotf hypot; +alias stdc.math.hypotl hypot; + +alias stdc.math.pow pow; +alias stdc.math.powf pow; +alias stdc.math.powl pow; + +alias stdc.complex.cpow pow; +alias stdc.complex.cpowf pow; +alias stdc.complex.cpowl pow; + +alias stdc.math.sqrt sqrt; +alias stdc.math.sqrtf sqrt; +alias stdc.math.sqrtl sqrt; + +alias stdc.complex.csqrt sqrt; +alias stdc.complex.csqrtf sqrt; +alias stdc.complex.csqrtl sqrt; + +alias stdc.math.erf erf; +alias stdc.math.erff erf; +alias stdc.math.erfl erf; + +alias stdc.math.erfc erfc; +alias stdc.math.erfcf erfc; +alias stdc.math.erfcl erfc; + +alias stdc.math.lgamma lgamma; +alias stdc.math.lgammaf lgamma; +alias stdc.math.lgammal lgamma; + +alias stdc.math.tgamma tgamma; +alias stdc.math.tgammaf tgamma; +alias stdc.math.tgammal tgamma; + +alias stdc.math.ceil ceil; +alias stdc.math.ceilf ceil; +alias stdc.math.ceill ceil; + +alias stdc.math.floor floor; +alias stdc.math.floorf floor; +alias stdc.math.floorl floor; + +alias stdc.math.nearbyint nearbyint; +alias stdc.math.nearbyintf nearbyint; +alias stdc.math.nearbyintl nearbyint; + +alias stdc.math.rint rint; +alias stdc.math.rintf rint; +alias stdc.math.rintl rint; + +alias stdc.math.lrint lrint; +alias stdc.math.lrintf lrint; +alias stdc.math.lrintl lrint; + +alias stdc.math.llrint llrint; +alias stdc.math.llrintf llrint; +alias stdc.math.llrintl llrint; + +alias stdc.math.round round; +alias stdc.math.roundf round; +alias stdc.math.roundl round; + +alias stdc.math.lround lround; +alias stdc.math.lroundf lround; +alias stdc.math.lroundl lround; + +alias stdc.math.llround llround; +alias stdc.math.llroundf llround; +alias stdc.math.llroundl llround; + +alias stdc.math.trunc trunc; +alias stdc.math.truncf trunc; +alias stdc.math.truncl trunc; + +alias stdc.math.fmod fmod; +alias stdc.math.fmodf fmod; +alias stdc.math.fmodl fmod; + +alias stdc.math.remainder remainder; +alias stdc.math.remainderf remainder; +alias stdc.math.remainderl remainder; + +alias stdc.math.remquo remquo; +alias stdc.math.remquof remquo; +alias stdc.math.remquol remquo; + +alias stdc.math.copysign copysign; +alias stdc.math.copysignf copysign; +alias stdc.math.copysignl copysign; + +alias stdc.math.nan nan; +alias stdc.math.nanf nan; +alias stdc.math.nanl nan; + +alias stdc.math.nextafter nextafter; +alias stdc.math.nextafterf nextafter; +alias stdc.math.nextafterl nextafter; + +alias stdc.math.nexttoward nexttoward; +alias stdc.math.nexttowardf nexttoward; +alias stdc.math.nexttowardl nexttoward; + +alias stdc.math.fdim fdim; +alias stdc.math.fdimf fdim; +alias stdc.math.fdiml fdim; + +alias stdc.math.fmax fmax; +alias stdc.math.fmaxf fmax; +alias stdc.math.fmaxl fmax; + +alias stdc.math.fmin fmin; +alias stdc.math.fmin fmin; +alias stdc.math.fminl fmin; + +alias stdc.math.fma fma; +alias stdc.math.fmaf fma; +alias stdc.math.fmal fma; + +alias stdc.complex.carg carg; +alias stdc.complex.cargf carg; +alias stdc.complex.cargl carg; + +alias stdc.complex.cimag cimag; +alias stdc.complex.cimagf cimag; +alias stdc.complex.cimagl cimag; + +alias stdc.complex.conj conj; +alias stdc.complex.conjf conj; +alias stdc.complex.conjl conj; + +alias stdc.complex.cproj cproj; +alias stdc.complex.cprojf cproj; +alias stdc.complex.cprojl cproj; + +//alias stdc.complex.creal creal; +//alias stdc.complex.crealf creal; +//alias stdc.complex.creall creal; diff --git a/import/stdc/time.d b/import/stdc/time.d new file mode 100644 index 0000000..6030c58 --- /dev/null +++ b/import/stdc/time.d @@ -0,0 +1,95 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.time; + +private import stdc.config; +private import stdc.stddef; + +extern (C): + +version( Windows ) +{ + struct tm + { + int tm_sec; // seconds after the minute - [0, 60] + int tm_min; // minutes after the hour - [0, 59] + int tm_hour; // hours since midnight - [0, 23] + int tm_mday; // day of the month - [1, 31] + int tm_mon; // months since January - [0, 11] + int tm_year; // years since 1900 + int tm_wday; // days since Sunday - [0, 6] + int tm_yday; // days since January 1 - [0, 365] + int tm_isdst; // Daylight Saving Time flag + } +} +else +{ + struct tm + { + int tm_sec; // seconds after the minute [0-60] + int tm_min; // minutes after the hour [0-59] + int tm_hour; // hours since midnight [0-23] + int tm_mday; // day of the month [1-31] + int tm_mon; // months since January [0-11] + int tm_year; // years since 1900 + int tm_wday; // days since Sunday [0-6] + int tm_yday; // days since January 1 [0-365] + int tm_isdst; // Daylight Savings Time flag + c_long tm_gmtoff; // offset from CUT in seconds + char* tm_zone; // timezone abbreviation + } +} + +alias c_long time_t; +alias c_long clock_t; + +version( Windows ) +{ + clock_t CLOCKS_PER_SEC = 1000; +} +else version( darwin ) +{ + clock_t CLOCKS_PER_SEC = 100; +} +else version( freebsd ) +{ + clock_t CLOCKS_PER_SEC = 128; +} +else +{ + clock_t CLOCKS_PER_SEC = 1000000; +} + +clock_t clock(); +double difftime(time_t time1, time_t time0); +time_t mktime(tm* timeptr); +time_t time(time_t* timer); +char* asctime(in tm* timeptr); +char* ctime(in time_t* timer); +tm* gmtime(in time_t* timer); +tm* localtime(in time_t* timer); +size_t strftime(char* s, size_t maxsize, in char* format, in tm* timeptr); +size_t wcsftime(wchar_t* s, size_t maxsize, in wchar_t* format, in tm* timeptr); + +version( Windows ) +{ + void tzset(); + void _tzset(); + char* _strdate(char* s); + char* _strtime(char* s); + + wchar_t* _wasctime(tm*); + wchar_t* _wctime(time_t*); + wchar_t* _wstrdate(wchar_t*); + wchar_t* _wstrtime(wchar_t*); +} +else version( linux ) +{ + void tzset(); +} diff --git a/import/stdc/wctype.d b/import/stdc/wctype.d new file mode 100644 index 0000000..125da7d --- /dev/null +++ b/import/stdc/wctype.d @@ -0,0 +1,33 @@ +/** + * D header file for C99. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: ISO/IEC 9899:1999 (E) + */ +module stdc.wctype; + +private import stdc.stddef; + +extern (C): + +int iswalnum(wint_t wc); +int iswalpha(wint_t wc); +int iswblank(wint_t wc); +int iswcntrl(wint_t wc); +int iswdigit(wint_t wc); +int iswgraph(wint_t wc); +int iswlower(wint_t wc); +int iswprint(wint_t wc); +int iswpunct(wint_t wc); +int iswspace(wint_t wc); +int iswupper(wint_t wc); +int iswxdigit(wint_t wc); + +int iswctype(wint_t wc, wctype_t desc); +wctype_t wctype(in char* property); +wint_t towlower(wint_t wc); +wint_t towupper(wint_t wc); +wint_t towctrans(wint_t wc, wctrans_t desc); +wctrans_t wctrans(in char* property); \ No newline at end of file diff --git a/import/sys/windows/windows.d b/import/sys/windows/windows.d new file mode 100644 index 0000000..3863064 --- /dev/null +++ b/import/sys/windows/windows.d @@ -0,0 +1,3221 @@ + +/* Windows is a registered trademark of Microsoft Corporation in the United +States and other countries. */ + +module sys.windows.windows; + +version (Windows) +{ +} +else +{ + static assert(0); // Windows only +} + +extern (Windows) +{ + alias uint ULONG; + alias ULONG *PULONG; + alias ushort USHORT; + alias USHORT *PUSHORT; + alias ubyte UCHAR; + alias UCHAR *PUCHAR; + alias char *PSZ; + alias wchar WCHAR; + + alias void VOID; + alias char CHAR; + alias short SHORT; + alias int LONG; + alias CHAR *LPSTR; + alias CHAR *PSTR; + version(D_Version2) + { + mixin("alias const(CHAR) *LPCSTR;"); + mixin("alias const(CHAR) *PCSTR;"); + } + else + { + alias CHAR *LPCSTR; + alias CHAR *PCSTR; + } + alias LPSTR LPTCH, PTCH; + alias LPSTR PTSTR, LPTSTR; + alias LPCSTR LPCTSTR; + + alias WCHAR* LPWSTR; + version(D_Version2) + { + mixin("alias const(WCHAR)* LPCWSTR, PCWSTR;"); + } + else + { + alias WCHAR* LPCWSTR, PCWSTR; + } + alias uint DWORD; + alias int BOOL; + alias ubyte BYTE; + alias ushort WORD; + alias float FLOAT; + alias FLOAT *PFLOAT; + alias BOOL *PBOOL; + alias BOOL *LPBOOL; + alias BYTE *PBYTE; + alias BYTE *LPBYTE; + alias int *PINT; + alias int *LPINT; + alias WORD *PWORD; + alias WORD *LPWORD; + alias int *LPLONG; + alias DWORD *PDWORD; + alias DWORD *LPDWORD; + alias void *LPVOID; + alias void *LPCVOID; + + alias int INT; + alias uint UINT; + alias uint *PUINT; + +// ULONG_PTR must be able to store a pointer as an integral type +version(Win64) +{ + alias long INT_PTR; + alias ulong UINT_PTR; + alias long LONG_PTR; + alias ulong ULONG_PTR; + alias long * PINT_PTR; + alias ulong * PUINT_PTR; + alias long * PLONG_PTR; + alias ulong * PULONG_PTR; +} +version(Windows) +{ + alias int INT_PTR; + alias uint UINT_PTR; + alias int LONG_PTR; + alias uint ULONG_PTR; + alias int * PINT_PTR; + alias uint * PUINT_PTR; + alias int * PLONG_PTR; + alias uint * PULONG_PTR; +} + + typedef void *HANDLE; + alias void *PVOID; + alias HANDLE HGLOBAL; + alias HANDLE HLOCAL; + alias LONG HRESULT; + alias LONG SCODE; + alias HANDLE HINSTANCE; + alias HINSTANCE HMODULE; + alias HANDLE HWND; + + alias HANDLE HGDIOBJ; + alias HANDLE HACCEL; + alias HANDLE HBITMAP; + alias HANDLE HBRUSH; + alias HANDLE HCOLORSPACE; + alias HANDLE HDC; + alias HANDLE HGLRC; + alias HANDLE HDESK; + alias HANDLE HENHMETAFILE; + alias HANDLE HFONT; + alias HANDLE HICON; + alias HANDLE HMENU; + alias HANDLE HMETAFILE; + alias HANDLE HPALETTE; + alias HANDLE HPEN; + alias HANDLE HRGN; + alias HANDLE HRSRC; + alias HANDLE HSTR; + alias HANDLE HTASK; + alias HANDLE HWINSTA; + alias HANDLE HKL; + alias HICON HCURSOR; + + alias HANDLE HKEY; + alias HKEY *PHKEY; + alias DWORD ACCESS_MASK; + alias ACCESS_MASK *PACCESS_MASK; + alias ACCESS_MASK REGSAM; + + alias int (*FARPROC)(); + + alias UINT WPARAM; + alias LONG LPARAM; + alias LONG LRESULT; + + alias DWORD COLORREF; + alias DWORD *LPCOLORREF; + alias WORD ATOM; + +version (0) +{ // Properly prototyped versions + alias BOOL function(HWND, UINT, WPARAM, LPARAM) DLGPROC; + alias VOID function(HWND, UINT, UINT, DWORD) TIMERPROC; + alias BOOL function(HDC, LPARAM, int) GRAYSTRINGPROC; + alias BOOL function(HWND, LPARAM) WNDENUMPROC; + alias LRESULT function(int code, WPARAM wParam, LPARAM lParam) HOOKPROC; + alias VOID function(HWND, UINT, DWORD, LRESULT) SENDASYNCPROC; + alias BOOL function(HWND, LPCSTR, HANDLE) PROPENUMPROCA; + alias BOOL function(HWND, LPCWSTR, HANDLE) PROPENUMPROCW; + alias BOOL function(HWND, LPSTR, HANDLE, DWORD) PROPENUMPROCEXA; + alias BOOL function(HWND, LPWSTR, HANDLE, DWORD) PROPENUMPROCEXW; + alias int function(LPSTR lpch, int ichCurrent, int cch, int code) + EDITWORDBREAKPROCA; + alias int function(LPWSTR lpch, int ichCurrent, int cch, int code) + EDITWORDBREAKPROCW; + alias BOOL function(HDC hdc, LPARAM lData, WPARAM wData, int cx, int cy) + DRAWSTATEPROC; +} +else +{ + alias FARPROC DLGPROC; + alias FARPROC TIMERPROC; + alias FARPROC GRAYSTRINGPROC; + alias FARPROC WNDENUMPROC; + alias FARPROC HOOKPROC; + alias FARPROC SENDASYNCPROC; + alias FARPROC EDITWORDBREAKPROCA; + alias FARPROC EDITWORDBREAKPROCW; + alias FARPROC PROPENUMPROCA; + alias FARPROC PROPENUMPROCW; + alias FARPROC PROPENUMPROCEXA; + alias FARPROC PROPENUMPROCEXW; + alias FARPROC DRAWSTATEPROC; +} + +extern (D) +{ +WORD HIWORD(int l) { return cast(WORD)((l >> 16) & 0xFFFF); } +WORD LOWORD(int l) { return cast(WORD)l; } +bool FAILED(int status) { return status < 0; } +bool SUCCEEDED(int Status) { return Status >= 0; } +} + +enum : int +{ + FALSE = 0, + TRUE = 1, +} + +enum : uint +{ + MAX_PATH = 260, + HINSTANCE_ERROR = 32, +} + +enum +{ + ERROR_SUCCESS = 0, + ERROR_INVALID_FUNCTION = 1, + ERROR_FILE_NOT_FOUND = 2, + ERROR_PATH_NOT_FOUND = 3, + ERROR_TOO_MANY_OPEN_FILES = 4, + ERROR_ACCESS_DENIED = 5, + ERROR_INVALID_HANDLE = 6, + ERROR_NO_MORE_FILES = 18, + ERROR_MORE_DATA = 234, + ERROR_NO_MORE_ITEMS = 259, +} + +enum +{ + DLL_PROCESS_ATTACH = 1, + DLL_THREAD_ATTACH = 2, + DLL_THREAD_DETACH = 3, + DLL_PROCESS_DETACH = 0, +} + +enum +{ + FILE_BEGIN = 0, + FILE_CURRENT = 1, + FILE_END = 2, +} + +enum : uint +{ + DELETE = 0x00010000, + READ_CONTROL = 0x00020000, + WRITE_DAC = 0x00040000, + WRITE_OWNER = 0x00080000, + SYNCHRONIZE = 0x00100000, + + STANDARD_RIGHTS_REQUIRED = 0x000F0000, + STANDARD_RIGHTS_READ = READ_CONTROL, + STANDARD_RIGHTS_WRITE = READ_CONTROL, + STANDARD_RIGHTS_EXECUTE = READ_CONTROL, + STANDARD_RIGHTS_ALL = 0x001F0000, + SPECIFIC_RIGHTS_ALL = 0x0000FFFF, + ACCESS_SYSTEM_SECURITY = 0x01000000, + MAXIMUM_ALLOWED = 0x02000000, + + GENERIC_READ = 0x80000000, + GENERIC_WRITE = 0x40000000, + GENERIC_EXECUTE = 0x20000000, + GENERIC_ALL = 0x10000000, +} + +enum +{ + FILE_SHARE_READ = 0x00000001, + FILE_SHARE_WRITE = 0x00000002, + FILE_SHARE_DELETE = 0x00000004, + FILE_ATTRIBUTE_READONLY = 0x00000001, + FILE_ATTRIBUTE_HIDDEN = 0x00000002, + FILE_ATTRIBUTE_SYSTEM = 0x00000004, + FILE_ATTRIBUTE_DIRECTORY = 0x00000010, + FILE_ATTRIBUTE_ARCHIVE = 0x00000020, + FILE_ATTRIBUTE_NORMAL = 0x00000080, + FILE_ATTRIBUTE_TEMPORARY = 0x00000100, + FILE_ATTRIBUTE_COMPRESSED = 0x00000800, + FILE_ATTRIBUTE_OFFLINE = 0x00001000, + FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001, + FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002, + FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004, + FILE_NOTIFY_CHANGE_SIZE = 0x00000008, + FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010, + FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020, + FILE_NOTIFY_CHANGE_CREATION = 0x00000040, + FILE_NOTIFY_CHANGE_SECURITY = 0x00000100, + FILE_ACTION_ADDED = 0x00000001, + FILE_ACTION_REMOVED = 0x00000002, + FILE_ACTION_MODIFIED = 0x00000003, + FILE_ACTION_RENAMED_OLD_NAME = 0x00000004, + FILE_ACTION_RENAMED_NEW_NAME = 0x00000005, + FILE_CASE_SENSITIVE_SEARCH = 0x00000001, + FILE_CASE_PRESERVED_NAMES = 0x00000002, + FILE_UNICODE_ON_DISK = 0x00000004, + FILE_PERSISTENT_ACLS = 0x00000008, + FILE_FILE_COMPRESSION = 0x00000010, + FILE_VOLUME_IS_COMPRESSED = 0x00008000, +} + +enum : DWORD +{ + MAILSLOT_NO_MESSAGE = cast(DWORD)-1, + MAILSLOT_WAIT_FOREVER = cast(DWORD)-1, +} + +enum : uint +{ + FILE_FLAG_WRITE_THROUGH = 0x80000000, + FILE_FLAG_OVERLAPPED = 0x40000000, + FILE_FLAG_NO_BUFFERING = 0x20000000, + FILE_FLAG_RANDOM_ACCESS = 0x10000000, + FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000, + FILE_FLAG_DELETE_ON_CLOSE = 0x04000000, + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, + FILE_FLAG_POSIX_SEMANTICS = 0x01000000, +} + +enum +{ + CREATE_NEW = 1, + CREATE_ALWAYS = 2, + OPEN_EXISTING = 3, + OPEN_ALWAYS = 4, + TRUNCATE_EXISTING = 5, +} + +version(D_Version2) +{ + mixin(" + enum + { + HANDLE INVALID_HANDLE_VALUE = cast(HANDLE)-1, + DWORD INVALID_SET_FILE_POINTER = cast(DWORD)-1, + DWORD INVALID_FILE_SIZE = cast(DWORD)0xFFFFFFFF, + }"); +} +else +{ + const HANDLE INVALID_HANDLE_VALUE = cast(HANDLE)-1; + + enum : DWORD + { + INVALID_SET_FILE_POINTER = cast(DWORD)-1, + INVALID_FILE_SIZE = cast(DWORD)0xFFFFFFFF, + } +} + +struct OVERLAPPED { + DWORD Internal; + DWORD InternalHigh; + DWORD Offset; + DWORD OffsetHigh; + HANDLE hEvent; +} + +struct SECURITY_ATTRIBUTES { + DWORD nLength; + void *lpSecurityDescriptor; + BOOL bInheritHandle; +} + +alias SECURITY_ATTRIBUTES* PSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES; + +struct FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} +alias FILETIME* PFILETIME, LPFILETIME; + +struct WIN32_FIND_DATA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + char cFileName[MAX_PATH]; + char cAlternateFileName[ 14 ]; +} + +struct WIN32_FIND_DATAW { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + wchar cFileName[ 260 ]; + wchar cAlternateFileName[ 14 ]; +} + +// Critical Section + +struct _LIST_ENTRY +{ + _LIST_ENTRY *Flink; + _LIST_ENTRY *Blink; +} +alias _LIST_ENTRY LIST_ENTRY; + +struct _RTL_CRITICAL_SECTION_DEBUG +{ + WORD Type; + WORD CreatorBackTraceIndex; + _RTL_CRITICAL_SECTION *CriticalSection; + LIST_ENTRY ProcessLocksList; + DWORD EntryCount; + DWORD ContentionCount; + DWORD Spare[ 2 ]; +} +alias _RTL_CRITICAL_SECTION_DEBUG RTL_CRITICAL_SECTION_DEBUG; + +struct _RTL_CRITICAL_SECTION +{ + RTL_CRITICAL_SECTION_DEBUG * DebugInfo; + + // + // The following three fields control entering and exiting the critical + // section for the resource + // + + LONG LockCount; + LONG RecursionCount; + HANDLE OwningThread; // from the thread's ClientId->UniqueThread + HANDLE LockSemaphore; + ULONG_PTR SpinCount; // force size on 64-bit systems when packed +} +alias _RTL_CRITICAL_SECTION CRITICAL_SECTION; + + +enum +{ + STD_INPUT_HANDLE = cast(DWORD)-10, + STD_OUTPUT_HANDLE = cast(DWORD)-11, + STD_ERROR_HANDLE = cast(DWORD)-12, +} + +export +{ +BOOL SetCurrentDirectoryA(LPCSTR lpPathName); +BOOL SetCurrentDirectoryW(LPCWSTR lpPathName); +DWORD GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer); +DWORD GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer); +BOOL CreateDirectoryA(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +BOOL CreateDirectoryExA(LPCSTR lpTemplateDirectory, LPCSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +BOOL CreateDirectoryExW(LPCWSTR lpTemplateDirectory, LPCWSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +BOOL RemoveDirectoryA(LPCSTR lpPathName); +BOOL RemoveDirectoryW(LPCWSTR lpPathName); + +BOOL CloseHandle(HANDLE hObject); + +HANDLE CreateFileA(in char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); +HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + +BOOL DeleteFileA(in char *lpFileName); +BOOL DeleteFileW(LPCWSTR lpFileName); + +BOOL FindClose(HANDLE hFindFile); +HANDLE FindFirstFileA(in char *lpFileName, WIN32_FIND_DATA* lpFindFileData); +HANDLE FindFirstFileW(in LPCWSTR lpFileName, WIN32_FIND_DATAW* lpFindFileData); +BOOL FindNextFileA(HANDLE hFindFile, WIN32_FIND_DATA* lpFindFileData); +BOOL FindNextFileW(HANDLE hFindFile, WIN32_FIND_DATAW* lpFindFileData); +BOOL GetExitCodeThread(HANDLE hThread, DWORD *lpExitCode); +DWORD GetLastError(); +DWORD GetFileAttributesA(in char *lpFileName); +DWORD GetFileAttributesW(in wchar *lpFileName); +DWORD GetFileSize(HANDLE hFile, DWORD *lpFileSizeHigh); +BOOL CopyFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists); +BOOL CopyFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists); +BOOL MoveFileA(in char *from, in char *to); +BOOL MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName); +BOOL ReadFile(HANDLE hFile, void *lpBuffer, DWORD nNumberOfBytesToRead, + DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); +DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, + LONG *lpDistanceToMoveHigh, DWORD dwMoveMethod); +BOOL WriteFile(HANDLE hFile, in void *lpBuffer, DWORD nNumberOfBytesToWrite, + DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); +DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize); +HANDLE GetStdHandle(DWORD nStdHandle); +BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle); +} + +struct MEMORYSTATUS { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORD dwTotalPhys; + DWORD dwAvailPhys; + DWORD dwTotalPageFile; + DWORD dwAvailPageFile; + DWORD dwTotalVirtual; + DWORD dwAvailVirtual; +}; +alias MEMORYSTATUS *LPMEMORYSTATUS; + +HMODULE LoadLibraryA(LPCSTR lpLibFileName); +FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName); +DWORD GetVersion(); +BOOL FreeLibrary(HMODULE hLibModule); +void FreeLibraryAndExitThread(HMODULE hLibModule, DWORD dwExitCode); +BOOL DisableThreadLibraryCalls(HMODULE hLibModule); + +// +// Registry Specific Access Rights. +// + +enum +{ + KEY_QUERY_VALUE = 0x0001, + KEY_SET_VALUE = 0x0002, + KEY_CREATE_SUB_KEY = 0x0004, + KEY_ENUMERATE_SUB_KEYS = 0x0008, + KEY_NOTIFY = 0x0010, + KEY_CREATE_LINK = 0x0020, + + KEY_READ = cast(int)((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & ~SYNCHRONIZE), + KEY_WRITE = cast(int)((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & ~SYNCHRONIZE), + KEY_EXECUTE = cast(int)(KEY_READ & ~SYNCHRONIZE), + KEY_ALL_ACCESS = cast(int)((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & ~SYNCHRONIZE), +} + +// +// Key creation/open disposition +// + +enum : int +{ + REG_CREATED_NEW_KEY = 0x00000001, // New Registry Key created + REG_OPENED_EXISTING_KEY = 0x00000002, // Existing Key opened +} + +// +// +// Predefined Value Types. +// +enum +{ + REG_NONE = 0, // No value type + REG_SZ = 1, // Unicode nul terminated string + REG_EXPAND_SZ = 2, // Unicode nul terminated string + // (with environment variable references) + REG_BINARY = 3, // Free form binary + REG_DWORD = 4, // 32-bit number + REG_DWORD_LITTLE_ENDIAN = 4, // 32-bit number (same as REG_DWORD) + REG_DWORD_BIG_ENDIAN = 5, // 32-bit number + REG_LINK = 6, // Symbolic Link (unicode) + REG_MULTI_SZ = 7, // Multiple Unicode strings + REG_RESOURCE_LIST = 8, // Resource list in the resource map + REG_FULL_RESOURCE_DESCRIPTOR = 9, // Resource list in the hardware description + REG_RESOURCE_REQUIREMENTS_LIST = 10, + REG_QWORD = 11, + REG_QWORD_LITTLE_ENDIAN = 11, +} + +/* + * MessageBox() Flags + */ +enum +{ + MB_OK = 0x00000000, + MB_OKCANCEL = 0x00000001, + MB_ABORTRETRYIGNORE = 0x00000002, + MB_YESNOCANCEL = 0x00000003, + MB_YESNO = 0x00000004, + MB_RETRYCANCEL = 0x00000005, + + + MB_ICONHAND = 0x00000010, + MB_ICONQUESTION = 0x00000020, + MB_ICONEXCLAMATION = 0x00000030, + MB_ICONASTERISK = 0x00000040, + + + MB_USERICON = 0x00000080, + MB_ICONWARNING = MB_ICONEXCLAMATION, + MB_ICONERROR = MB_ICONHAND, + + + MB_ICONINFORMATION = MB_ICONASTERISK, + MB_ICONSTOP = MB_ICONHAND, + + MB_DEFBUTTON1 = 0x00000000, + MB_DEFBUTTON2 = 0x00000100, + MB_DEFBUTTON3 = 0x00000200, + + MB_DEFBUTTON4 = 0x00000300, + + + MB_APPLMODAL = 0x00000000, + MB_SYSTEMMODAL = 0x00001000, + MB_TASKMODAL = 0x00002000, + + MB_HELP = 0x00004000, // Help Button + + + MB_NOFOCUS = 0x00008000, + MB_SETFOREGROUND = 0x00010000, + MB_DEFAULT_DESKTOP_ONLY = 0x00020000, + + + MB_TOPMOST = 0x00040000, + MB_RIGHT = 0x00080000, + MB_RTLREADING = 0x00100000, + + + MB_TYPEMASK = 0x0000000F, + MB_ICONMASK = 0x000000F0, + MB_DEFMASK = 0x00000F00, + MB_MODEMASK = 0x00003000, + MB_MISCMASK = 0x0000C000, +} + + +int MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); +int MessageBoxExA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId); + +version(D_Version2) +{ + mixin(" + enum : HKEY + { + HKEY_CLASSES_ROOT = cast(HKEY)(0x80000000), + HKEY_CURRENT_USER = cast(HKEY)(0x80000001), + HKEY_LOCAL_MACHINE = cast(HKEY)(0x80000002), + HKEY_USERS = cast(HKEY)(0x80000003), + HKEY_PERFORMANCE_DATA = cast(HKEY)(0x80000004), + HKEY_PERFORMANCE_TEXT = cast(HKEY)(0x80000050), + HKEY_PERFORMANCE_NLSTEXT = cast(HKEY)(0x80000060), + HKEY_CURRENT_CONFIG = cast(HKEY)(0x80000005), + HKEY_DYN_DATA = cast(HKEY)(0x80000006), + }"); +} +else +{ + const HKEY_CLASSES_ROOT = cast(HKEY)(0x80000000); + const HKEY_CURRENT_USER = cast(HKEY)(0x80000001); + const HKEY_LOCAL_MACHINE = cast(HKEY)(0x80000002); + const HKEY_USERS = cast(HKEY)(0x80000003); + const HKEY_PERFORMANCE_DATA = cast(HKEY)(0x80000004); + const HKEY_PERFORMANCE_TEXT = cast(HKEY)(0x80000050); + const HKEY_PERFORMANCE_NLSTEXT = cast(HKEY)(0x80000060); + const HKEY_CURRENT_CONFIG = cast(HKEY)(0x80000005); + const HKEY_DYN_DATA = cast(HKEY)(0x80000006); +} + + +enum +{ + REG_OPTION_RESERVED = (0x00000000), // Parameter is reserved + + REG_OPTION_NON_VOLATILE = (0x00000000), // Key is preserved + // when system is rebooted + + REG_OPTION_VOLATILE = (0x00000001), // Key is not preserved + // when system is rebooted + + REG_OPTION_CREATE_LINK = (0x00000002), // Created key is a + // symbolic link + + REG_OPTION_BACKUP_RESTORE = (0x00000004), // open for backup or restore + // special access rules + // privilege required + + REG_OPTION_OPEN_LINK = (0x00000008), // Open symbolic link + + REG_LEGAL_OPTION = (REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK), +} + +export LONG RegDeleteKeyA(HKEY hKey, LPCSTR lpSubKey); +export LONG RegDeleteValueA(HKEY hKey, LPCSTR lpValueName); + +export LONG RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName, LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass, FILETIME* lpftLastWriteTime); +export LONG RegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved, + LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); + +export LONG RegCloseKey(HKEY hKey); +export LONG RegFlushKey(HKEY hKey); + +export LONG RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult); +export LONG RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); + +export LONG RegQueryInfoKeyA(HKEY hKey, LPSTR lpClass, LPDWORD lpcbClass, + LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, + LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, + PFILETIME lpftLastWriteTime); + +export LONG RegQueryValueA(HKEY hKey, LPCSTR lpSubKey, LPSTR lpValue, + LPLONG lpcbValue); + +export LONG RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, + DWORD dwOptions, REGSAM samDesired, SECURITY_ATTRIBUTES* lpSecurityAttributes, + PHKEY phkResult, LPDWORD lpdwDisposition); + +export LONG RegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, BYTE* lpData, DWORD cbData); + +struct MEMORY_BASIC_INFORMATION { + PVOID BaseAddress; + PVOID AllocationBase; + DWORD AllocationProtect; + DWORD RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; +} +alias MEMORY_BASIC_INFORMATION* PMEMORY_BASIC_INFORMATION; + +enum +{ + SECTION_QUERY = 0x0001, + SECTION_MAP_WRITE = 0x0002, + SECTION_MAP_READ = 0x0004, + SECTION_MAP_EXECUTE = 0x0008, + SECTION_EXTEND_SIZE = 0x0010, + + SECTION_ALL_ACCESS = cast(int)(STANDARD_RIGHTS_REQUIRED|SECTION_QUERY| SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE), + PAGE_NOACCESS = 0x01, + PAGE_READONLY = 0x02, + PAGE_READWRITE = 0x04, + PAGE_WRITECOPY = 0x08, + PAGE_EXECUTE = 0x10, + PAGE_EXECUTE_READ = 0x20, + PAGE_EXECUTE_READWRITE = 0x40, + PAGE_EXECUTE_WRITECOPY = 0x80, + PAGE_GUARD = 0x100, + PAGE_NOCACHE = 0x200, + MEM_COMMIT = 0x1000, + MEM_RESERVE = 0x2000, + MEM_DECOMMIT = 0x4000, + MEM_RELEASE = 0x8000, + MEM_FREE = 0x10000, + MEM_PRIVATE = 0x20000, + MEM_MAPPED = 0x40000, + MEM_RESET = 0x80000, + MEM_TOP_DOWN = 0x100000, + SEC_FILE = 0x800000, + SEC_IMAGE = 0x1000000, + SEC_RESERVE = 0x4000000, + SEC_COMMIT = 0x8000000, + SEC_NOCACHE = 0x10000000, + MEM_IMAGE = SEC_IMAGE, +} + +enum +{ + FILE_MAP_COPY = SECTION_QUERY, + FILE_MAP_WRITE = SECTION_MAP_WRITE, + FILE_MAP_READ = SECTION_MAP_READ, + FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS, +} + + +// +// Define access rights to files and directories +// + +// +// The FILE_READ_DATA and FILE_WRITE_DATA constants are also defined in +// devioctl.h as FILE_READ_ACCESS and FILE_WRITE_ACCESS. The values for these +// constants *MUST* always be in sync. +// The values are redefined in devioctl.h because they must be available to +// both DOS and NT. +// + +enum +{ + FILE_READ_DATA = ( 0x0001 ), // file & pipe + FILE_LIST_DIRECTORY = ( 0x0001 ), // directory + + FILE_WRITE_DATA = ( 0x0002 ), // file & pipe + FILE_ADD_FILE = ( 0x0002 ), // directory + + FILE_APPEND_DATA = ( 0x0004 ), // file + FILE_ADD_SUBDIRECTORY = ( 0x0004 ), // directory + FILE_CREATE_PIPE_INSTANCE = ( 0x0004 ), // named pipe + + FILE_READ_EA = ( 0x0008 ), // file & directory + + FILE_WRITE_EA = ( 0x0010 ), // file & directory + + FILE_EXECUTE = ( 0x0020 ), // file + FILE_TRAVERSE = ( 0x0020 ), // directory + + FILE_DELETE_CHILD = ( 0x0040 ), // directory + + FILE_READ_ATTRIBUTES = ( 0x0080 ), // all + + FILE_WRITE_ATTRIBUTES = ( 0x0100 ), // all + + FILE_ALL_ACCESS = cast(int)(STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF), + + FILE_GENERIC_READ = cast(int)(STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE), + + FILE_GENERIC_WRITE = cast(int)(STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE), + + FILE_GENERIC_EXECUTE = cast(int)(STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE), +} + +export +{ + BOOL FreeResource(HGLOBAL hResData); + LPVOID LockResource(HGLOBAL hResData); + BOOL GlobalUnlock(HGLOBAL hMem); + HGLOBAL GlobalFree(HGLOBAL hMem); + UINT GlobalCompact(DWORD dwMinFree); + void GlobalFix(HGLOBAL hMem); + void GlobalUnfix(HGLOBAL hMem); + LPVOID GlobalWire(HGLOBAL hMem); + BOOL GlobalUnWire(HGLOBAL hMem); + void GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer); + HLOCAL LocalAlloc(UINT uFlags, UINT uBytes); + HLOCAL LocalReAlloc(HLOCAL hMem, UINT uBytes, UINT uFlags); + LPVOID LocalLock(HLOCAL hMem); + HLOCAL LocalHandle(LPCVOID pMem); + BOOL LocalUnlock(HLOCAL hMem); + UINT LocalSize(HLOCAL hMem); + UINT LocalFlags(HLOCAL hMem); + HLOCAL LocalFree(HLOCAL hMem); + UINT LocalShrink(HLOCAL hMem, UINT cbNewSize); + UINT LocalCompact(UINT uMinFree); + BOOL FlushInstructionCache(HANDLE hProcess, LPCVOID lpBaseAddress, DWORD dwSize); + LPVOID VirtualAlloc(LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect); + BOOL VirtualFree(LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType); + BOOL VirtualProtect(LPVOID lpAddress, DWORD dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); + DWORD VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, DWORD dwLength); + LPVOID VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect); + BOOL VirtualFreeEx(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType); + BOOL VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); + DWORD VirtualQueryEx(HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, DWORD dwLength); +} + +struct SYSTEMTIME +{ + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; +} + +struct TIME_ZONE_INFORMATION { + LONG Bias; + WCHAR StandardName[ 32 ]; + SYSTEMTIME StandardDate; + LONG StandardBias; + WCHAR DaylightName[ 32 ]; + SYSTEMTIME DaylightDate; + LONG DaylightBias; +} + +enum +{ + TIME_ZONE_ID_UNKNOWN = 0, + TIME_ZONE_ID_STANDARD = 1, + TIME_ZONE_ID_DAYLIGHT = 2, +} + +export void GetSystemTime(SYSTEMTIME* lpSystemTime); +export void GetSystemTimeAsFileTime(FILETIME* lpSystemTimeAsFileTime); +export BOOL SetSystemTime(SYSTEMTIME* lpSystemTime); +export void GetLocalTime(SYSTEMTIME* lpSystemTime); +export BOOL SetLocalTime(SYSTEMTIME* lpSystemTime); +export BOOL SystemTimeToTzSpecificLocalTime(TIME_ZONE_INFORMATION* lpTimeZoneInformation, SYSTEMTIME* lpUniversalTime, SYSTEMTIME* lpLocalTime); +export DWORD GetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation); +export BOOL SetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation); + +export BOOL SystemTimeToFileTime(in SYSTEMTIME *lpSystemTime, FILETIME* lpFileTime); +export BOOL FileTimeToLocalFileTime(in FILETIME *lpFileTime, FILETIME* lpLocalFileTime); +export BOOL LocalFileTimeToFileTime(in FILETIME *lpLocalFileTime, FILETIME* lpFileTime); +export BOOL FileTimeToSystemTime(in FILETIME *lpFileTime, SYSTEMTIME* lpSystemTime); +export LONG CompareFileTime(in FILETIME *lpFileTime1, in FILETIME *lpFileTime2); +export BOOL FileTimeToDosDateTime(in FILETIME *lpFileTime, WORD* lpFatDate, WORD* lpFatTime); +export BOOL DosDateTimeToFileTime(WORD wFatDate, WORD wFatTime, FILETIME* lpFileTime); +export DWORD GetTickCount(); +export BOOL SetSystemTimeAdjustment(DWORD dwTimeAdjustment, BOOL bTimeAdjustmentDisabled); +export BOOL GetSystemTimeAdjustment(DWORD* lpTimeAdjustment, DWORD* lpTimeIncrement, BOOL* lpTimeAdjustmentDisabled); +export DWORD FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, void* *Arguments);export DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, void* *Arguments); + +enum +{ + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_HMODULE = 0x00000800, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000, + FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF, +}; + + +// +// Language IDs. +// +// The following two combinations of primary language ID and +// sublanguage ID have special semantics: +// +// Primary Language ID Sublanguage ID Result +// ------------------- --------------- ------------------------ +// LANG_NEUTRAL SUBLANG_NEUTRAL Language neutral +// LANG_NEUTRAL SUBLANG_DEFAULT User default language +// LANG_NEUTRAL SUBLANG_SYS_DEFAULT System default language +// + +// +// Primary language IDs. +// + +enum +{ + LANG_NEUTRAL = 0x00, + + LANG_AFRIKAANS = 0x36, + LANG_ALBANIAN = 0x1c, + LANG_ARABIC = 0x01, + LANG_BASQUE = 0x2d, + LANG_BELARUSIAN = 0x23, + LANG_BULGARIAN = 0x02, + LANG_CATALAN = 0x03, + LANG_CHINESE = 0x04, + LANG_CROATIAN = 0x1a, + LANG_CZECH = 0x05, + LANG_DANISH = 0x06, + LANG_DUTCH = 0x13, + LANG_ENGLISH = 0x09, + LANG_ESTONIAN = 0x25, + LANG_FAEROESE = 0x38, + LANG_FARSI = 0x29, + LANG_FINNISH = 0x0b, + LANG_FRENCH = 0x0c, + LANG_GERMAN = 0x07, + LANG_GREEK = 0x08, + LANG_HEBREW = 0x0d, + LANG_HUNGARIAN = 0x0e, + LANG_ICELANDIC = 0x0f, + LANG_INDONESIAN = 0x21, + LANG_ITALIAN = 0x10, + LANG_JAPANESE = 0x11, + LANG_KOREAN = 0x12, + LANG_LATVIAN = 0x26, + LANG_LITHUANIAN = 0x27, + LANG_NORWEGIAN = 0x14, + LANG_POLISH = 0x15, + LANG_PORTUGUESE = 0x16, + LANG_ROMANIAN = 0x18, + LANG_RUSSIAN = 0x19, + LANG_SERBIAN = 0x1a, + LANG_SLOVAK = 0x1b, + LANG_SLOVENIAN = 0x24, + LANG_SPANISH = 0x0a, + LANG_SWEDISH = 0x1d, + LANG_THAI = 0x1e, + LANG_TURKISH = 0x1f, + LANG_UKRAINIAN = 0x22, + LANG_VIETNAMESE = 0x2a, +} +// +// Sublanguage IDs. +// +// The name immediately following SUBLANG_ dictates which primary +// language ID that sublanguage ID can be combined with to form a +// valid language ID. +// +enum +{ + SUBLANG_NEUTRAL = 0x00, // language neutral + SUBLANG_DEFAULT = 0x01, // user default + SUBLANG_SYS_DEFAULT = 0x02, // system default + + SUBLANG_ARABIC_SAUDI_ARABIA = 0x01, // Arabic (Saudi Arabia) + SUBLANG_ARABIC_IRAQ = 0x02, // Arabic (Iraq) + SUBLANG_ARABIC_EGYPT = 0x03, // Arabic (Egypt) + SUBLANG_ARABIC_LIBYA = 0x04, // Arabic (Libya) + SUBLANG_ARABIC_ALGERIA = 0x05, // Arabic (Algeria) + SUBLANG_ARABIC_MOROCCO = 0x06, // Arabic (Morocco) + SUBLANG_ARABIC_TUNISIA = 0x07, // Arabic (Tunisia) + SUBLANG_ARABIC_OMAN = 0x08, // Arabic (Oman) + SUBLANG_ARABIC_YEMEN = 0x09, // Arabic (Yemen) + SUBLANG_ARABIC_SYRIA = 0x0a, // Arabic (Syria) + SUBLANG_ARABIC_JORDAN = 0x0b, // Arabic (Jordan) + SUBLANG_ARABIC_LEBANON = 0x0c, // Arabic (Lebanon) + SUBLANG_ARABIC_KUWAIT = 0x0d, // Arabic (Kuwait) + SUBLANG_ARABIC_UAE = 0x0e, // Arabic (U.A.E) + SUBLANG_ARABIC_BAHRAIN = 0x0f, // Arabic (Bahrain) + SUBLANG_ARABIC_QATAR = 0x10, // Arabic (Qatar) + SUBLANG_CHINESE_TRADITIONAL = 0x01, // Chinese (Taiwan) + SUBLANG_CHINESE_SIMPLIFIED = 0x02, // Chinese (PR China) + SUBLANG_CHINESE_HONGKONG = 0x03, // Chinese (Hong Kong) + SUBLANG_CHINESE_SINGAPORE = 0x04, // Chinese (Singapore) + SUBLANG_DUTCH = 0x01, // Dutch + SUBLANG_DUTCH_BELGIAN = 0x02, // Dutch (Belgian) + SUBLANG_ENGLISH_US = 0x01, // English (USA) + SUBLANG_ENGLISH_UK = 0x02, // English (UK) + SUBLANG_ENGLISH_AUS = 0x03, // English (Australian) + SUBLANG_ENGLISH_CAN = 0x04, // English (Canadian) + SUBLANG_ENGLISH_NZ = 0x05, // English (New Zealand) + SUBLANG_ENGLISH_EIRE = 0x06, // English (Irish) + SUBLANG_ENGLISH_SOUTH_AFRICA = 0x07, // English (South Africa) + SUBLANG_ENGLISH_JAMAICA = 0x08, // English (Jamaica) + SUBLANG_ENGLISH_CARIBBEAN = 0x09, // English (Caribbean) + SUBLANG_ENGLISH_BELIZE = 0x0a, // English (Belize) + SUBLANG_ENGLISH_TRINIDAD = 0x0b, // English (Trinidad) + SUBLANG_FRENCH = 0x01, // French + SUBLANG_FRENCH_BELGIAN = 0x02, // French (Belgian) + SUBLANG_FRENCH_CANADIAN = 0x03, // French (Canadian) + SUBLANG_FRENCH_SWISS = 0x04, // French (Swiss) + SUBLANG_FRENCH_LUXEMBOURG = 0x05, // French (Luxembourg) + SUBLANG_GERMAN = 0x01, // German + SUBLANG_GERMAN_SWISS = 0x02, // German (Swiss) + SUBLANG_GERMAN_AUSTRIAN = 0x03, // German (Austrian) + SUBLANG_GERMAN_LUXEMBOURG = 0x04, // German (Luxembourg) + SUBLANG_GERMAN_LIECHTENSTEIN = 0x05, // German (Liechtenstein) + SUBLANG_ITALIAN = 0x01, // Italian + SUBLANG_ITALIAN_SWISS = 0x02, // Italian (Swiss) + SUBLANG_KOREAN = 0x01, // Korean (Extended Wansung) + SUBLANG_KOREAN_JOHAB = 0x02, // Korean (Johab) + SUBLANG_NORWEGIAN_BOKMAL = 0x01, // Norwegian (Bokmal) + SUBLANG_NORWEGIAN_NYNORSK = 0x02, // Norwegian (Nynorsk) + SUBLANG_PORTUGUESE = 0x02, // Portuguese + SUBLANG_PORTUGUESE_BRAZILIAN = 0x01, // Portuguese (Brazilian) + SUBLANG_SERBIAN_LATIN = 0x02, // Serbian (Latin) + SUBLANG_SERBIAN_CYRILLIC = 0x03, // Serbian (Cyrillic) + SUBLANG_SPANISH = 0x01, // Spanish (Castilian) + SUBLANG_SPANISH_MEXICAN = 0x02, // Spanish (Mexican) + SUBLANG_SPANISH_MODERN = 0x03, // Spanish (Modern) + SUBLANG_SPANISH_GUATEMALA = 0x04, // Spanish (Guatemala) + SUBLANG_SPANISH_COSTA_RICA = 0x05, // Spanish (Costa Rica) + SUBLANG_SPANISH_PANAMA = 0x06, // Spanish (Panama) + SUBLANG_SPANISH_DOMINICAN_REPUBLIC = 0x07, // Spanish (Dominican Republic) + SUBLANG_SPANISH_VENEZUELA = 0x08, // Spanish (Venezuela) + SUBLANG_SPANISH_COLOMBIA = 0x09, // Spanish (Colombia) + SUBLANG_SPANISH_PERU = 0x0a, // Spanish (Peru) + SUBLANG_SPANISH_ARGENTINA = 0x0b, // Spanish (Argentina) + SUBLANG_SPANISH_ECUADOR = 0x0c, // Spanish (Ecuador) + SUBLANG_SPANISH_CHILE = 0x0d, // Spanish (Chile) + SUBLANG_SPANISH_URUGUAY = 0x0e, // Spanish (Uruguay) + SUBLANG_SPANISH_PARAGUAY = 0x0f, // Spanish (Paraguay) + SUBLANG_SPANISH_BOLIVIA = 0x10, // Spanish (Bolivia) + SUBLANG_SPANISH_EL_SALVADOR = 0x11, // Spanish (El Salvador) + SUBLANG_SPANISH_HONDURAS = 0x12, // Spanish (Honduras) + SUBLANG_SPANISH_NICARAGUA = 0x13, // Spanish (Nicaragua) + SUBLANG_SPANISH_PUERTO_RICO = 0x14, // Spanish (Puerto Rico) + SUBLANG_SWEDISH = 0x01, // Swedish + SUBLANG_SWEDISH_FINLAND = 0x02, // Swedish (Finland) +} +// +// Sorting IDs. +// + +enum +{ + SORT_DEFAULT = 0x0, // sorting default + + SORT_JAPANESE_XJIS = 0x0, // Japanese XJIS order + SORT_JAPANESE_UNICODE = 0x1, // Japanese Unicode order + + SORT_CHINESE_BIG5 = 0x0, // Chinese BIG5 order + SORT_CHINESE_PRCP = 0x0, // PRC Chinese Phonetic order + SORT_CHINESE_UNICODE = 0x1, // Chinese Unicode order + SORT_CHINESE_PRC = 0x2, // PRC Chinese Stroke Count order + + SORT_KOREAN_KSC = 0x0, // Korean KSC order + SORT_KOREAN_UNICODE = 0x1, // Korean Unicode order + + SORT_GERMAN_PHONE_BOOK = 0x1, // German Phone Book order +} + +// end_r_winnt + +// +// A language ID is a 16 bit value which is the combination of a +// primary language ID and a secondary language ID. The bits are +// allocated as follows: +// +// +-----------------------+-------------------------+ +// | Sublanguage ID | Primary Language ID | +// +-----------------------+-------------------------+ +// 15 10 9 0 bit +// +// +// Language ID creation/extraction macros: +// +// MAKELANGID - construct language id from a primary language id and +// a sublanguage id. +// PRIMARYLANGID - extract primary language id from a language id. +// SUBLANGID - extract sublanguage id from a language id. +// + +int MAKELANGID(int p, int s) { return ((cast(WORD)s) << 10) | cast(WORD)p; } +WORD PRIMARYLANGID(int lgid) { return cast(WORD)(lgid & 0x3ff); } +WORD SUBLANGID(int lgid) { return cast(WORD)(lgid >> 10); } + + +struct FLOATING_SAVE_AREA { + DWORD ControlWord; + DWORD StatusWord; + DWORD TagWord; + DWORD ErrorOffset; + DWORD ErrorSelector; + DWORD DataOffset; + DWORD DataSelector; + BYTE RegisterArea[80 ]; + DWORD Cr0NpxState; +} + +enum +{ + SIZE_OF_80387_REGISTERS = 80, +// +// The following flags control the contents of the CONTEXT structure. +// + CONTEXT_i386 = 0x00010000, // this assumes that i386 and + CONTEXT_i486 = 0x00010000, // i486 have identical context records + + CONTEXT_CONTROL = (CONTEXT_i386 | 0x00000001), // SS:SP, CS:IP, FLAGS, BP + CONTEXT_INTEGER = (CONTEXT_i386 | 0x00000002), // AX, BX, CX, DX, SI, DI + CONTEXT_SEGMENTS = (CONTEXT_i386 | 0x00000004), // DS, ES, FS, GS + CONTEXT_FLOATING_POINT = (CONTEXT_i386 | 0x00000008), // 387 state + CONTEXT_DEBUG_REGISTERS = (CONTEXT_i386 | 0x00000010), // DB 0-3,6,7 + + CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS), +} + +struct CONTEXT +{ + + // + // The flags values within this flag control the contents of + // a CONTEXT record. + // + // If the context record is used as an input parameter, then + // for each portion of the context record controlled by a flag + // whose value is set, it is assumed that that portion of the + // context record contains valid context. If the context record + // is being used to modify a threads context, then only that + // portion of the threads context will be modified. + // + // If the context record is used as an IN OUT parameter to capture + // the context of a thread, then only those portions of the thread's + // context corresponding to set flags will be returned. + // + // The context record is never used as an OUT only parameter. + // + + DWORD ContextFlags; + + // + // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is + // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT + // included in CONTEXT_FULL. + // + + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + + // + // This section is specified/returned if the + // ContextFlags word contians the flag CONTEXT_FLOATING_POINT. + // + + FLOATING_SAVE_AREA FloatSave; + + // + // This section is specified/returned if the + // ContextFlags word contians the flag CONTEXT_SEGMENTS. + // + + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + + // + // This section is specified/returned if the + // ContextFlags word contians the flag CONTEXT_INTEGER. + // + + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + + // + // This section is specified/returned if the + // ContextFlags word contians the flag CONTEXT_CONTROL. + // + + DWORD Ebp; + DWORD Eip; + DWORD SegCs; // MUST BE SANITIZED + DWORD EFlags; // MUST BE SANITIZED + DWORD Esp; + DWORD SegSs; +} + +enum +{ + THREAD_BASE_PRIORITY_LOWRT = 15, // value that gets a thread to LowRealtime-1 + THREAD_BASE_PRIORITY_MAX = 2, // maximum thread base priority boost + THREAD_BASE_PRIORITY_MIN = -2, // minimum thread base priority boost + THREAD_BASE_PRIORITY_IDLE = -15, // value that gets a thread to idle + + THREAD_PRIORITY_LOWEST = THREAD_BASE_PRIORITY_MIN, + THREAD_PRIORITY_BELOW_NORMAL = (THREAD_PRIORITY_LOWEST+1), + THREAD_PRIORITY_NORMAL = 0, + THREAD_PRIORITY_HIGHEST = THREAD_BASE_PRIORITY_MAX, + THREAD_PRIORITY_ABOVE_NORMAL = (THREAD_PRIORITY_HIGHEST-1), + THREAD_PRIORITY_ERROR_RETURN = int.max, + + THREAD_PRIORITY_TIME_CRITICAL = THREAD_BASE_PRIORITY_LOWRT, + THREAD_PRIORITY_IDLE = THREAD_BASE_PRIORITY_IDLE, +} + +export HANDLE GetCurrentThread(); +export BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); +export HANDLE GetCurrentProcess(); +export DWORD GetCurrentProcessId(); +export BOOL DuplicateHandle (HANDLE sourceProcess, HANDLE sourceThread, + HANDLE targetProcessHandle, HANDLE *targetHandle, DWORD access, + BOOL inheritHandle, DWORD options); +export DWORD GetCurrentThreadId(); +export BOOL SetThreadPriority(HANDLE hThread, int nPriority); +export BOOL SetThreadPriorityBoost(HANDLE hThread, BOOL bDisablePriorityBoost); +export BOOL GetThreadPriorityBoost(HANDLE hThread, PBOOL pDisablePriorityBoost); +export BOOL GetThreadTimes(HANDLE hThread, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); +export int GetThreadPriority(HANDLE hThread); +export BOOL GetThreadContext(HANDLE hThread, CONTEXT* lpContext); +export BOOL SetThreadContext(HANDLE hThread, CONTEXT* lpContext); +export DWORD SuspendThread(HANDLE hThread); +export DWORD ResumeThread(HANDLE hThread); +export DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); +export DWORD WaitForMultipleObjects(DWORD nCount, HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds); +export void Sleep(DWORD dwMilliseconds); + +// Synchronization + +export +{ +LONG InterlockedIncrement(LPLONG lpAddend); +LONG InterlockedDecrement(LPLONG lpAddend); +LONG InterlockedExchange(LPLONG Target, LONG Value); +LONG InterlockedExchangeAdd(LPLONG Addend, LONG Value); +PVOID InterlockedCompareExchange(PVOID *Destination, PVOID Exchange, PVOID Comperand); + +void InitializeCriticalSection(CRITICAL_SECTION * lpCriticalSection); +void EnterCriticalSection(CRITICAL_SECTION * lpCriticalSection); +BOOL TryEnterCriticalSection(CRITICAL_SECTION * lpCriticalSection); +void LeaveCriticalSection(CRITICAL_SECTION * lpCriticalSection); +void DeleteCriticalSection(CRITICAL_SECTION * lpCriticalSection); + +} + + + +export BOOL QueryPerformanceCounter(long* lpPerformanceCount); +export BOOL QueryPerformanceFrequency(long* lpFrequency); + +enum +{ + WM_NOTIFY = 0x004E, + WM_INPUTLANGCHANGEREQUEST = 0x0050, + WM_INPUTLANGCHANGE = 0x0051, + WM_TCARD = 0x0052, + WM_HELP = 0x0053, + WM_USERCHANGED = 0x0054, + WM_NOTIFYFORMAT = 0x0055, + + NFR_ANSI = 1, + NFR_UNICODE = 2, + NF_QUERY = 3, + NF_REQUERY = 4, + + WM_CONTEXTMENU = 0x007B, + WM_STYLECHANGING = 0x007C, + WM_STYLECHANGED = 0x007D, + WM_DISPLAYCHANGE = 0x007E, + WM_GETICON = 0x007F, + WM_SETICON = 0x0080, + + + + WM_NCCREATE = 0x0081, + WM_NCDESTROY = 0x0082, + WM_NCCALCSIZE = 0x0083, + WM_NCHITTEST = 0x0084, + WM_NCPAINT = 0x0085, + WM_NCACTIVATE = 0x0086, + WM_GETDLGCODE = 0x0087, + + WM_NCMOUSEMOVE = 0x00A0, + WM_NCLBUTTONDOWN = 0x00A1, + WM_NCLBUTTONUP = 0x00A2, + WM_NCLBUTTONDBLCLK = 0x00A3, + WM_NCRBUTTONDOWN = 0x00A4, + WM_NCRBUTTONUP = 0x00A5, + WM_NCRBUTTONDBLCLK = 0x00A6, + WM_NCMBUTTONDOWN = 0x00A7, + WM_NCMBUTTONUP = 0x00A8, + WM_NCMBUTTONDBLCLK = 0x00A9, + + WM_KEYFIRST = 0x0100, + WM_KEYDOWN = 0x0100, + WM_KEYUP = 0x0101, + WM_CHAR = 0x0102, + WM_DEADCHAR = 0x0103, + WM_SYSKEYDOWN = 0x0104, + WM_SYSKEYUP = 0x0105, + WM_SYSCHAR = 0x0106, + WM_SYSDEADCHAR = 0x0107, + WM_KEYLAST = 0x0108, + + + WM_IME_STARTCOMPOSITION = 0x010D, + WM_IME_ENDCOMPOSITION = 0x010E, + WM_IME_COMPOSITION = 0x010F, + WM_IME_KEYLAST = 0x010F, + + + WM_INITDIALOG = 0x0110, + WM_COMMAND = 0x0111, + WM_SYSCOMMAND = 0x0112, + WM_TIMER = 0x0113, + WM_HSCROLL = 0x0114, + WM_VSCROLL = 0x0115, + WM_INITMENU = 0x0116, + WM_INITMENUPOPUP = 0x0117, + WM_MENUSELECT = 0x011F, + WM_MENUCHAR = 0x0120, + WM_ENTERIDLE = 0x0121, + + WM_CTLCOLORMSGBOX = 0x0132, + WM_CTLCOLOREDIT = 0x0133, + WM_CTLCOLORLISTBOX = 0x0134, + WM_CTLCOLORBTN = 0x0135, + WM_CTLCOLORDLG = 0x0136, + WM_CTLCOLORSCROLLBAR = 0x0137, + WM_CTLCOLORSTATIC = 0x0138, + + + + WM_MOUSEFIRST = 0x0200, + WM_MOUSEMOVE = 0x0200, + WM_LBUTTONDOWN = 0x0201, + WM_LBUTTONUP = 0x0202, + WM_LBUTTONDBLCLK = 0x0203, + WM_RBUTTONDOWN = 0x0204, + WM_RBUTTONUP = 0x0205, + WM_RBUTTONDBLCLK = 0x0206, + WM_MBUTTONDOWN = 0x0207, + WM_MBUTTONUP = 0x0208, + WM_MBUTTONDBLCLK = 0x0209, + + + + WM_MOUSELAST = 0x0209, + + + + + + + + + WM_PARENTNOTIFY = 0x0210, + MENULOOP_WINDOW = 0, + MENULOOP_POPUP = 1, + WM_ENTERMENULOOP = 0x0211, + WM_EXITMENULOOP = 0x0212, + + + WM_NEXTMENU = 0x0213, +} + +enum +{ +/* + * Dialog Box Command IDs + */ + IDOK = 1, + IDCANCEL = 2, + IDABORT = 3, + IDRETRY = 4, + IDIGNORE = 5, + IDYES = 6, + IDNO = 7, + + IDCLOSE = 8, + IDHELP = 9, + + +// end_r_winuser + + + +/* + * Control Manager Structures and Definitions + */ + + + +// begin_r_winuser + +/* + * Edit Control Styles + */ + ES_LEFT = 0x0000, + ES_CENTER = 0x0001, + ES_RIGHT = 0x0002, + ES_MULTILINE = 0x0004, + ES_UPPERCASE = 0x0008, + ES_LOWERCASE = 0x0010, + ES_PASSWORD = 0x0020, + ES_AUTOVSCROLL = 0x0040, + ES_AUTOHSCROLL = 0x0080, + ES_NOHIDESEL = 0x0100, + ES_OEMCONVERT = 0x0400, + ES_READONLY = 0x0800, + ES_WANTRETURN = 0x1000, + + ES_NUMBER = 0x2000, + + +// end_r_winuser + + + +/* + * Edit Control Notification Codes + */ + EN_SETFOCUS = 0x0100, + EN_KILLFOCUS = 0x0200, + EN_CHANGE = 0x0300, + EN_UPDATE = 0x0400, + EN_ERRSPACE = 0x0500, + EN_MAXTEXT = 0x0501, + EN_HSCROLL = 0x0601, + EN_VSCROLL = 0x0602, + + +/* Edit control EM_SETMARGIN parameters */ + EC_LEFTMARGIN = 0x0001, + EC_RIGHTMARGIN = 0x0002, + EC_USEFONTINFO = 0xffff, + + + + +// begin_r_winuser + +/* + * Edit Control Messages + */ + EM_GETSEL = 0x00B0, + EM_SETSEL = 0x00B1, + EM_GETRECT = 0x00B2, + EM_SETRECT = 0x00B3, + EM_SETRECTNP = 0x00B4, + EM_SCROLL = 0x00B5, + EM_LINESCROLL = 0x00B6, + EM_SCROLLCARET = 0x00B7, + EM_GETMODIFY = 0x00B8, + EM_SETMODIFY = 0x00B9, + EM_GETLINECOUNT = 0x00BA, + EM_LINEINDEX = 0x00BB, + EM_SETHANDLE = 0x00BC, + EM_GETHANDLE = 0x00BD, + EM_GETTHUMB = 0x00BE, + EM_LINELENGTH = 0x00C1, + EM_REPLACESEL = 0x00C2, + EM_GETLINE = 0x00C4, + EM_LIMITTEXT = 0x00C5, + EM_CANUNDO = 0x00C6, + EM_UNDO = 0x00C7, + EM_FMTLINES = 0x00C8, + EM_LINEFROMCHAR = 0x00C9, + EM_SETTABSTOPS = 0x00CB, + EM_SETPASSWORDCHAR = 0x00CC, + EM_EMPTYUNDOBUFFER = 0x00CD, + EM_GETFIRSTVISIBLELINE = 0x00CE, + EM_SETREADONLY = 0x00CF, + EM_SETWORDBREAKPROC = 0x00D0, + EM_GETWORDBREAKPROC = 0x00D1, + EM_GETPASSWORDCHAR = 0x00D2, + + EM_SETMARGINS = 0x00D3, + EM_GETMARGINS = 0x00D4, + EM_SETLIMITTEXT = EM_LIMITTEXT, /* ;win40 Name change */ + EM_GETLIMITTEXT = 0x00D5, + EM_POSFROMCHAR = 0x00D6, + EM_CHARFROMPOS = 0x00D7, + + + +// end_r_winuser + + +/* + * EDITWORDBREAKPROC code values + */ + WB_LEFT = 0, + WB_RIGHT = 1, + WB_ISDELIMITER = 2, + +// begin_r_winuser + +/* + * Button Control Styles + */ + BS_PUSHBUTTON = 0x00000000, + BS_DEFPUSHBUTTON = 0x00000001, + BS_CHECKBOX = 0x00000002, + BS_AUTOCHECKBOX = 0x00000003, + BS_RADIOBUTTON = 0x00000004, + BS_3STATE = 0x00000005, + BS_AUTO3STATE = 0x00000006, + BS_GROUPBOX = 0x00000007, + BS_USERBUTTON = 0x00000008, + BS_AUTORADIOBUTTON = 0x00000009, + BS_OWNERDRAW = 0x0000000B, + BS_LEFTTEXT = 0x00000020, + + BS_TEXT = 0x00000000, + BS_ICON = 0x00000040, + BS_BITMAP = 0x00000080, + BS_LEFT = 0x00000100, + BS_RIGHT = 0x00000200, + BS_CENTER = 0x00000300, + BS_TOP = 0x00000400, + BS_BOTTOM = 0x00000800, + BS_VCENTER = 0x00000C00, + BS_PUSHLIKE = 0x00001000, + BS_MULTILINE = 0x00002000, + BS_NOTIFY = 0x00004000, + BS_FLAT = 0x00008000, + BS_RIGHTBUTTON = BS_LEFTTEXT, + + + +/* + * User Button Notification Codes + */ + BN_CLICKED = 0, + BN_PAINT = 1, + BN_HILITE = 2, + BN_UNHILITE = 3, + BN_DISABLE = 4, + BN_DOUBLECLICKED = 5, + + BN_PUSHED = BN_HILITE, + BN_UNPUSHED = BN_UNHILITE, + BN_DBLCLK = BN_DOUBLECLICKED, + BN_SETFOCUS = 6, + BN_KILLFOCUS = 7, + +/* + * Button Control Messages + */ + BM_GETCHECK = 0x00F0, + BM_SETCHECK = 0x00F1, + BM_GETSTATE = 0x00F2, + BM_SETSTATE = 0x00F3, + BM_SETSTYLE = 0x00F4, + + BM_CLICK = 0x00F5, + BM_GETIMAGE = 0x00F6, + BM_SETIMAGE = 0x00F7, + + BST_UNCHECKED = 0x0000, + BST_CHECKED = 0x0001, + BST_INDETERMINATE = 0x0002, + BST_PUSHED = 0x0004, + BST_FOCUS = 0x0008, + + +/* + * Static Control Constants + */ + SS_LEFT = 0x00000000, + SS_CENTER = 0x00000001, + SS_RIGHT = 0x00000002, + SS_ICON = 0x00000003, + SS_BLACKRECT = 0x00000004, + SS_GRAYRECT = 0x00000005, + SS_WHITERECT = 0x00000006, + SS_BLACKFRAME = 0x00000007, + SS_GRAYFRAME = 0x00000008, + SS_WHITEFRAME = 0x00000009, + SS_USERITEM = 0x0000000A, + SS_SIMPLE = 0x0000000B, + SS_LEFTNOWORDWRAP = 0x0000000C, + + SS_OWNERDRAW = 0x0000000D, + SS_BITMAP = 0x0000000E, + SS_ENHMETAFILE = 0x0000000F, + SS_ETCHEDHORZ = 0x00000010, + SS_ETCHEDVERT = 0x00000011, + SS_ETCHEDFRAME = 0x00000012, + SS_TYPEMASK = 0x0000001F, + + SS_NOPREFIX = 0x00000080, /* Don't do "&" character translation */ + + SS_NOTIFY = 0x00000100, + SS_CENTERIMAGE = 0x00000200, + SS_RIGHTJUST = 0x00000400, + SS_REALSIZEIMAGE = 0x00000800, + SS_SUNKEN = 0x00001000, + SS_ENDELLIPSIS = 0x00004000, + SS_PATHELLIPSIS = 0x00008000, + SS_WORDELLIPSIS = 0x0000C000, + SS_ELLIPSISMASK = 0x0000C000, + + +// end_r_winuser + + +/* + * Static Control Mesages + */ + STM_SETICON = 0x0170, + STM_GETICON = 0x0171, + + STM_SETIMAGE = 0x0172, + STM_GETIMAGE = 0x0173, + STN_CLICKED = 0, + STN_DBLCLK = 1, + STN_ENABLE = 2, + STN_DISABLE = 3, + + STM_MSGMAX = 0x0174, +} + + +enum +{ +/* + * Window Messages + */ + + WM_NULL = 0x0000, + WM_CREATE = 0x0001, + WM_DESTROY = 0x0002, + WM_MOVE = 0x0003, + WM_SIZE = 0x0005, + + WM_ACTIVATE = 0x0006, +/* + * WM_ACTIVATE state values + */ + WA_INACTIVE = 0, + WA_ACTIVE = 1, + WA_CLICKACTIVE = 2, + + WM_SETFOCUS = 0x0007, + WM_KILLFOCUS = 0x0008, + WM_ENABLE = 0x000A, + WM_SETREDRAW = 0x000B, + WM_SETTEXT = 0x000C, + WM_GETTEXT = 0x000D, + WM_GETTEXTLENGTH = 0x000E, + WM_PAINT = 0x000F, + WM_CLOSE = 0x0010, + WM_QUERYENDSESSION = 0x0011, + WM_QUIT = 0x0012, + WM_QUERYOPEN = 0x0013, + WM_ERASEBKGND = 0x0014, + WM_SYSCOLORCHANGE = 0x0015, + WM_ENDSESSION = 0x0016, + WM_SHOWWINDOW = 0x0018, + WM_WININICHANGE = 0x001A, + + WM_SETTINGCHANGE = WM_WININICHANGE, + + + + WM_DEVMODECHANGE = 0x001B, + WM_ACTIVATEAPP = 0x001C, + WM_FONTCHANGE = 0x001D, + WM_TIMECHANGE = 0x001E, + WM_CANCELMODE = 0x001F, + WM_SETCURSOR = 0x0020, + WM_MOUSEACTIVATE = 0x0021, + WM_CHILDACTIVATE = 0x0022, + WM_QUEUESYNC = 0x0023, + + WM_GETMINMAXINFO = 0x0024, +} + +struct RECT +{ + LONG left; + LONG top; + LONG right; + LONG bottom; +} +alias RECT* PRECT, NPRECT, LPRECT; + +struct PAINTSTRUCT { + HDC hdc; + BOOL fErase; + RECT rcPaint; + BOOL fRestore; + BOOL fIncUpdate; + BYTE rgbReserved[32]; +} +alias PAINTSTRUCT* PPAINTSTRUCT, NPPAINTSTRUCT, LPPAINTSTRUCT; + +// flags for GetDCEx() + +enum +{ + DCX_WINDOW = 0x00000001, + DCX_CACHE = 0x00000002, + DCX_NORESETATTRS = 0x00000004, + DCX_CLIPCHILDREN = 0x00000008, + DCX_CLIPSIBLINGS = 0x00000010, + DCX_PARENTCLIP = 0x00000020, + DCX_EXCLUDERGN = 0x00000040, + DCX_INTERSECTRGN = 0x00000080, + DCX_EXCLUDEUPDATE = 0x00000100, + DCX_INTERSECTUPDATE = 0x00000200, + DCX_LOCKWINDOWUPDATE = 0x00000400, + DCX_VALIDATE = 0x00200000, +} + +export +{ + BOOL UpdateWindow(HWND hWnd); + HWND SetActiveWindow(HWND hWnd); + HWND GetForegroundWindow(); + BOOL PaintDesktop(HDC hdc); + BOOL SetForegroundWindow(HWND hWnd); + HWND WindowFromDC(HDC hDC); + HDC GetDC(HWND hWnd); + HDC GetDCEx(HWND hWnd, HRGN hrgnClip, DWORD flags); + HDC GetWindowDC(HWND hWnd); + int ReleaseDC(HWND hWnd, HDC hDC); + HDC BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint); + BOOL EndPaint(HWND hWnd, PAINTSTRUCT *lpPaint); + BOOL GetUpdateRect(HWND hWnd, LPRECT lpRect, BOOL bErase); + int GetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase); + int SetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw); + int GetWindowRgn(HWND hWnd, HRGN hRgn); + int ExcludeUpdateRgn(HDC hDC, HWND hWnd); + BOOL InvalidateRect(HWND hWnd, RECT *lpRect, BOOL bErase); + BOOL ValidateRect(HWND hWnd, RECT *lpRect); + BOOL InvalidateRgn(HWND hWnd, HRGN hRgn, BOOL bErase); + BOOL ValidateRgn(HWND hWnd, HRGN hRgn); + BOOL RedrawWindow(HWND hWnd, RECT *lprcUpdate, HRGN hrgnUpdate, UINT flags); +} + +// flags for RedrawWindow() +enum +{ + RDW_INVALIDATE = 0x0001, + RDW_INTERNALPAINT = 0x0002, + RDW_ERASE = 0x0004, + RDW_VALIDATE = 0x0008, + RDW_NOINTERNALPAINT = 0x0010, + RDW_NOERASE = 0x0020, + RDW_NOCHILDREN = 0x0040, + RDW_ALLCHILDREN = 0x0080, + RDW_UPDATENOW = 0x0100, + RDW_ERASENOW = 0x0200, + RDW_FRAME = 0x0400, + RDW_NOFRAME = 0x0800, +} + +export +{ + BOOL GetClientRect(HWND hWnd, LPRECT lpRect); + BOOL GetWindowRect(HWND hWnd, LPRECT lpRect); + BOOL AdjustWindowRect(LPRECT lpRect, DWORD dwStyle, BOOL bMenu); + BOOL AdjustWindowRectEx(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle); + HFONT CreateFontA(int, int, int, int, int, DWORD, + DWORD, DWORD, DWORD, DWORD, DWORD, + DWORD, DWORD, LPCSTR); + HFONT CreateFontW(int, int, int, int, int, DWORD, + DWORD, DWORD, DWORD, DWORD, DWORD, + DWORD, DWORD, LPCWSTR); +} + +enum +{ + OUT_DEFAULT_PRECIS = 0, + OUT_STRING_PRECIS = 1, + OUT_CHARACTER_PRECIS = 2, + OUT_STROKE_PRECIS = 3, + OUT_TT_PRECIS = 4, + OUT_DEVICE_PRECIS = 5, + OUT_RASTER_PRECIS = 6, + OUT_TT_ONLY_PRECIS = 7, + OUT_OUTLINE_PRECIS = 8, + OUT_SCREEN_OUTLINE_PRECIS = 9, + + CLIP_DEFAULT_PRECIS = 0, + CLIP_CHARACTER_PRECIS = 1, + CLIP_STROKE_PRECIS = 2, + CLIP_MASK = 0xf, + CLIP_LH_ANGLES = (1<<4), + CLIP_TT_ALWAYS = (2<<4), + CLIP_EMBEDDED = (8<<4), + + DEFAULT_QUALITY = 0, + DRAFT_QUALITY = 1, + PROOF_QUALITY = 2, + + NONANTIALIASED_QUALITY = 3, + ANTIALIASED_QUALITY = 4, + + + DEFAULT_PITCH = 0, + FIXED_PITCH = 1, + VARIABLE_PITCH = 2, + + MONO_FONT = 8, + + + ANSI_CHARSET = 0, + DEFAULT_CHARSET = 1, + SYMBOL_CHARSET = 2, + SHIFTJIS_CHARSET = 128, + HANGEUL_CHARSET = 129, + GB2312_CHARSET = 134, + CHINESEBIG5_CHARSET = 136, + OEM_CHARSET = 255, + + JOHAB_CHARSET = 130, + HEBREW_CHARSET = 177, + ARABIC_CHARSET = 178, + GREEK_CHARSET = 161, + TURKISH_CHARSET = 162, + VIETNAMESE_CHARSET = 163, + THAI_CHARSET = 222, + EASTEUROPE_CHARSET = 238, + RUSSIAN_CHARSET = 204, + + MAC_CHARSET = 77, + BALTIC_CHARSET = 186, + + FS_LATIN1 = 0x00000001L, + FS_LATIN2 = 0x00000002L, + FS_CYRILLIC = 0x00000004L, + FS_GREEK = 0x00000008L, + FS_TURKISH = 0x00000010L, + FS_HEBREW = 0x00000020L, + FS_ARABIC = 0x00000040L, + FS_BALTIC = 0x00000080L, + FS_VIETNAMESE = 0x00000100L, + FS_THAI = 0x00010000L, + FS_JISJAPAN = 0x00020000L, + FS_CHINESESIMP = 0x00040000L, + FS_WANSUNG = 0x00080000L, + FS_CHINESETRAD = 0x00100000L, + FS_JOHAB = 0x00200000L, + FS_SYMBOL = cast(int)0x80000000L, + + +/* Font Families */ + FF_DONTCARE = (0<<4), /* Don't care or don't know. */ + FF_ROMAN = (1<<4), /* Variable stroke width, serifed. */ + /* Times Roman, Century Schoolbook, etc. */ + FF_SWISS = (2<<4), /* Variable stroke width, sans-serifed. */ + /* Helvetica, Swiss, etc. */ + FF_MODERN = (3<<4), /* Constant stroke width, serifed or sans-serifed. */ + /* Pica, Elite, Courier, etc. */ + FF_SCRIPT = (4<<4), /* Cursive, etc. */ + FF_DECORATIVE = (5<<4), /* Old English, etc. */ + +/* Font Weights */ + FW_DONTCARE = 0, + FW_THIN = 100, + FW_EXTRALIGHT = 200, + FW_LIGHT = 300, + FW_NORMAL = 400, + FW_MEDIUM = 500, + FW_SEMIBOLD = 600, + FW_BOLD = 700, + FW_EXTRABOLD = 800, + FW_HEAVY = 900, + + FW_ULTRALIGHT = FW_EXTRALIGHT, + FW_REGULAR = FW_NORMAL, + FW_DEMIBOLD = FW_SEMIBOLD, + FW_ULTRABOLD = FW_EXTRABOLD, + FW_BLACK = FW_HEAVY, + + PANOSE_COUNT = 10, + PAN_FAMILYTYPE_INDEX = 0, + PAN_SERIFSTYLE_INDEX = 1, + PAN_WEIGHT_INDEX = 2, + PAN_PROPORTION_INDEX = 3, + PAN_CONTRAST_INDEX = 4, + PAN_STROKEVARIATION_INDEX = 5, + PAN_ARMSTYLE_INDEX = 6, + PAN_LETTERFORM_INDEX = 7, + PAN_MIDLINE_INDEX = 8, + PAN_XHEIGHT_INDEX = 9, + + PAN_CULTURE_LATIN = 0, +} + +struct RGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; +} +alias RGBQUAD* LPRGBQUAD; + +struct BITMAPINFOHEADER +{ + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} +alias BITMAPINFOHEADER* LPBITMAPINFOHEADER, PBITMAPINFOHEADER; + +struct BITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; +} +alias BITMAPINFO* LPBITMAPINFO, PBITMAPINFO; + +struct PALETTEENTRY { + BYTE peRed; + BYTE peGreen; + BYTE peBlue; + BYTE peFlags; +} +alias PALETTEENTRY* PPALETTEENTRY, LPPALETTEENTRY; + +struct LOGPALETTE { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[1]; +} +alias LOGPALETTE* PLOGPALETTE, NPLOGPALETTE, LPLOGPALETTE; + +/* Pixel format descriptor */ +struct PIXELFORMATDESCRIPTOR +{ + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerType; + BYTE bReserved; + DWORD dwLayerMask; + DWORD dwVisibleMask; + DWORD dwDamageMask; +} +alias PIXELFORMATDESCRIPTOR* PPIXELFORMATDESCRIPTOR, LPPIXELFORMATDESCRIPTOR; + + +export +{ + BOOL RoundRect(HDC, int, int, int, int, int, int); + BOOL ResizePalette(HPALETTE, UINT); + int SaveDC(HDC); + int SelectClipRgn(HDC, HRGN); + int ExtSelectClipRgn(HDC, HRGN, int); + int SetMetaRgn(HDC); + HGDIOBJ SelectObject(HDC, HGDIOBJ); + HPALETTE SelectPalette(HDC, HPALETTE, BOOL); + COLORREF SetBkColor(HDC, COLORREF); + int SetBkMode(HDC, int); + LONG SetBitmapBits(HBITMAP, DWORD, void *); + UINT SetBoundsRect(HDC, RECT *, UINT); + int SetDIBits(HDC, HBITMAP, UINT, UINT, void *, BITMAPINFO *, UINT); + int SetDIBitsToDevice(HDC, int, int, DWORD, DWORD, int, + int, UINT, UINT, void *, BITMAPINFO *, UINT); + DWORD SetMapperFlags(HDC, DWORD); + int SetGraphicsMode(HDC hdc, int iMode); + int SetMapMode(HDC, int); + HMETAFILE SetMetaFileBitsEx(UINT, BYTE *); + UINT SetPaletteEntries(HPALETTE, UINT, UINT, PALETTEENTRY *); + COLORREF SetPixel(HDC, int, int, COLORREF); + BOOL SetPixelV(HDC, int, int, COLORREF); + BOOL SetPixelFormat(HDC, int, PIXELFORMATDESCRIPTOR *); + int SetPolyFillMode(HDC, int); + BOOL StretchBlt(HDC, int, int, int, int, HDC, int, int, int, int, DWORD); + BOOL SetRectRgn(HRGN, int, int, int, int); + int StretchDIBits(HDC, int, int, int, int, int, int, int, int, + void *, BITMAPINFO *, UINT, DWORD); + int SetROP2(HDC, int); + int SetStretchBltMode(HDC, int); + UINT SetSystemPaletteUse(HDC, UINT); + int SetTextCharacterExtra(HDC, int); + COLORREF SetTextColor(HDC, COLORREF); + UINT SetTextAlign(HDC, UINT); + BOOL SetTextJustification(HDC, int, int); + BOOL UpdateColors(HDC); +} + +/* Text Alignment Options */ +enum +{ + TA_NOUPDATECP = 0, + TA_UPDATECP = 1, + + TA_LEFT = 0, + TA_RIGHT = 2, + TA_CENTER = 6, + + TA_TOP = 0, + TA_BOTTOM = 8, + TA_BASELINE = 24, + + TA_RTLREADING = 256, + TA_MASK = (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING), +} + +struct POINT +{ + LONG x; + LONG y; +} +alias POINT* PPOINT, NPPOINT, LPPOINT; + + +export +{ + BOOL MoveToEx(HDC, int, int, LPPOINT); + BOOL TextOutA(HDC, int, int, LPCSTR, int); + BOOL TextOutW(HDC, int, int, LPCWSTR, int); +} + +export void PostQuitMessage(int nExitCode); +export LRESULT DefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +export HMODULE GetModuleHandleA(LPCSTR lpModuleName); + +alias LRESULT (* WNDPROC)(HWND, UINT, WPARAM, LPARAM); + +struct WNDCLASSEXA { + UINT cbSize; + /* Win 3.x */ + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; + /* Win 4.0 */ + HICON hIconSm; +} +alias WNDCLASSEXA* PWNDCLASSEXA, NPWNDCLASSEXA, LPWNDCLASSEXA; + + +struct WNDCLASSA { + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; +} +alias WNDCLASSA* PWNDCLASSA, NPWNDCLASSA, LPWNDCLASSA; +alias WNDCLASSA WNDCLASS; + +/* + * Window Styles + */ +enum : uint +{ + WS_OVERLAPPED = 0x00000000, + WS_POPUP = 0x80000000, + WS_CHILD = 0x40000000, + WS_MINIMIZE = 0x20000000, + WS_VISIBLE = 0x10000000, + WS_DISABLED = 0x08000000, + WS_CLIPSIBLINGS = 0x04000000, + WS_CLIPCHILDREN = 0x02000000, + WS_MAXIMIZE = 0x01000000, + WS_CAPTION = 0x00C00000, /* WS_BORDER | WS_DLGFRAME */ + WS_BORDER = 0x00800000, + WS_DLGFRAME = 0x00400000, + WS_VSCROLL = 0x00200000, + WS_HSCROLL = 0x00100000, + WS_SYSMENU = 0x00080000, + WS_THICKFRAME = 0x00040000, + WS_GROUP = 0x00020000, + WS_TABSTOP = 0x00010000, + + WS_MINIMIZEBOX = 0x00020000, + WS_MAXIMIZEBOX = 0x00010000, + + WS_TILED = WS_OVERLAPPED, + WS_ICONIC = WS_MINIMIZE, + WS_SIZEBOX = WS_THICKFRAME, + +/* + * Common Window Styles + */ + WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX), + WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW, + WS_POPUPWINDOW = (WS_POPUP | WS_BORDER | WS_SYSMENU), + WS_CHILDWINDOW = (WS_CHILD), +} + +/* + * Class styles + */ +enum +{ + CS_VREDRAW = 0x0001, + CS_HREDRAW = 0x0002, + CS_KEYCVTWINDOW = 0x0004, + CS_DBLCLKS = 0x0008, + CS_OWNDC = 0x0020, + CS_CLASSDC = 0x0040, + CS_PARENTDC = 0x0080, + CS_NOKEYCVT = 0x0100, + CS_NOCLOSE = 0x0200, + CS_SAVEBITS = 0x0800, + CS_BYTEALIGNCLIENT = 0x1000, + CS_BYTEALIGNWINDOW = 0x2000, + CS_GLOBALCLASS = 0x4000, + + + CS_IME = 0x00010000, +} + +export +{ + HICON LoadIconA(HINSTANCE hInstance, LPCSTR lpIconName); + HICON LoadIconW(HINSTANCE hInstance, LPCWSTR lpIconName); + HCURSOR LoadCursorA(HINSTANCE hInstance, LPCSTR lpCursorName); + HCURSOR LoadCursorW(HINSTANCE hInstance, LPCWSTR lpCursorName); +} + +version(D_Version2) +{ + mixin(" + enum : LPSTR + { + IDI_APPLICATION = cast(LPSTR)(32512), + + IDC_ARROW = cast(LPSTR)(32512), + IDC_CROSS = cast(LPSTR)(32515), + }"); +} +else +{ + const IDI_APPLICATION = cast(LPSTR)(32512); + + const IDC_ARROW = cast(LPSTR)(32512); + const IDC_CROSS = cast(LPSTR)(32515); +} + +/* + * Color Types + */ +enum +{ + CTLCOLOR_MSGBOX = 0, + CTLCOLOR_EDIT = 1, + CTLCOLOR_LISTBOX = 2, + CTLCOLOR_BTN = 3, + CTLCOLOR_DLG = 4, + CTLCOLOR_SCROLLBAR = 5, + CTLCOLOR_STATIC = 6, + CTLCOLOR_MAX = 7, + + COLOR_SCROLLBAR = 0, + COLOR_BACKGROUND = 1, + COLOR_ACTIVECAPTION = 2, + COLOR_INACTIVECAPTION = 3, + COLOR_MENU = 4, + COLOR_WINDOW = 5, + COLOR_WINDOWFRAME = 6, + COLOR_MENUTEXT = 7, + COLOR_WINDOWTEXT = 8, + COLOR_CAPTIONTEXT = 9, + COLOR_ACTIVEBORDER = 10, + COLOR_INACTIVEBORDER = 11, + COLOR_APPWORKSPACE = 12, + COLOR_HIGHLIGHT = 13, + COLOR_HIGHLIGHTTEXT = 14, + COLOR_BTNFACE = 15, + COLOR_BTNSHADOW = 16, + COLOR_GRAYTEXT = 17, + COLOR_BTNTEXT = 18, + COLOR_INACTIVECAPTIONTEXT = 19, + COLOR_BTNHIGHLIGHT = 20, + + + COLOR_3DDKSHADOW = 21, + COLOR_3DLIGHT = 22, + COLOR_INFOTEXT = 23, + COLOR_INFOBK = 24, + + COLOR_DESKTOP = COLOR_BACKGROUND, + COLOR_3DFACE = COLOR_BTNFACE, + COLOR_3DSHADOW = COLOR_BTNSHADOW, + COLOR_3DHIGHLIGHT = COLOR_BTNHIGHLIGHT, + COLOR_3DHILIGHT = COLOR_BTNHIGHLIGHT, + COLOR_BTNHILIGHT = COLOR_BTNHIGHLIGHT, +} + +enum : int +{ + CW_USEDEFAULT = cast(int)0x80000000 +} + +/* + * Special value for CreateWindow, et al. + */ +version(D_Version2) +{ + mixin(" + enum : HWND + { + HWND_DESKTOP = cast(HWND)0, + }"); +} +else +{ + const HWND_DESKTOP = cast(HWND)0; +} + +export ATOM RegisterClassA(WNDCLASSA *lpWndClass); + +export HWND CreateWindowExA( + DWORD dwExStyle, + LPCSTR lpClassName, + LPCSTR lpWindowName, + DWORD dwStyle, + int X, + int Y, + int nWidth, + int nHeight, + HWND hWndParent , + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam); + + +HWND CreateWindowA( + LPCSTR lpClassName, + LPCSTR lpWindowName, + DWORD dwStyle, + int X, + int Y, + int nWidth, + int nHeight, + HWND hWndParent , + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam) +{ + return CreateWindowExA(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); +} + +/* + * Message structure + */ +struct MSG { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + DWORD time; + POINT pt; +} +alias MSG* PMSG, NPMSG, LPMSG; + +export +{ + BOOL GetMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); + BOOL TranslateMessage(MSG *lpMsg); + LONG DispatchMessageA(MSG *lpMsg); + BOOL PeekMessageA(MSG *lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); + HWND GetFocus(); +} + +export DWORD ExpandEnvironmentStringsA(LPCSTR lpSrc, LPSTR lpDst, DWORD nSize); + +export +{ + BOOL IsValidCodePage(UINT CodePage); + UINT GetACP(); + UINT GetOEMCP(); + //BOOL GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo); + BOOL IsDBCSLeadByte(BYTE TestChar); + BOOL IsDBCSLeadByteEx(UINT CodePage, BYTE TestChar); + int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cchMultiByte, LPWSTR lpWideCharStr, int cchWideChar); + int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cchMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar); +} + +export HANDLE CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName); +export HANDLE CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName); + +export BOOL GetMailslotInfo(HANDLE hMailslot, LPDWORD lpMaxMessageSize, LPDWORD lpNextSize, LPDWORD lpMessageCount, LPDWORD lpReadTimeout); +export BOOL SetMailslotInfo(HANDLE hMailslot, DWORD lReadTimeout); +export LPVOID MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, DWORD dwNumberOfBytesToMap); +export LPVOID MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, DWORD dwNumberOfBytesToMap, LPVOID lpBaseAddress); +export BOOL FlushViewOfFile(LPCVOID lpBaseAddress, DWORD dwNumberOfBytesToFlush); +export BOOL UnmapViewOfFile(LPCVOID lpBaseAddress); + +export HGDIOBJ GetStockObject(int); +export BOOL ShowWindow(HWND hWnd, int nCmdShow); + +/* Stock Logical Objects */ +enum +{ WHITE_BRUSH = 0, + LTGRAY_BRUSH = 1, + GRAY_BRUSH = 2, + DKGRAY_BRUSH = 3, + BLACK_BRUSH = 4, + NULL_BRUSH = 5, + HOLLOW_BRUSH = NULL_BRUSH, + WHITE_PEN = 6, + BLACK_PEN = 7, + NULL_PEN = 8, + OEM_FIXED_FONT = 10, + ANSI_FIXED_FONT = 11, + ANSI_VAR_FONT = 12, + SYSTEM_FONT = 13, + DEVICE_DEFAULT_FONT = 14, + DEFAULT_PALETTE = 15, + SYSTEM_FIXED_FONT = 16, + DEFAULT_GUI_FONT = 17, + STOCK_LAST = 17, +} + +/* + * ShowWindow() Commands + */ +enum +{ SW_HIDE = 0, + SW_SHOWNORMAL = 1, + SW_NORMAL = 1, + SW_SHOWMINIMIZED = 2, + SW_SHOWMAXIMIZED = 3, + SW_MAXIMIZE = 3, + SW_SHOWNOACTIVATE = 4, + SW_SHOW = 5, + SW_MINIMIZE = 6, + SW_SHOWMINNOACTIVE = 7, + SW_SHOWNA = 8, + SW_RESTORE = 9, + SW_SHOWDEFAULT = 10, + SW_MAX = 10, +} + +struct TEXTMETRICA +{ + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + BYTE tmFirstChar; + BYTE tmLastChar; + BYTE tmDefaultChar; + BYTE tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; +} + +export BOOL GetTextMetricsA(HDC, TEXTMETRICA*); + +/* + * Scroll Bar Constants + */ +enum +{ SB_HORZ = 0, + SB_VERT = 1, + SB_CTL = 2, + SB_BOTH = 3, +} + +/* + * Scroll Bar Commands + */ +enum +{ SB_LINEUP = 0, + SB_LINELEFT = 0, + SB_LINEDOWN = 1, + SB_LINERIGHT = 1, + SB_PAGEUP = 2, + SB_PAGELEFT = 2, + SB_PAGEDOWN = 3, + SB_PAGERIGHT = 3, + SB_THUMBPOSITION = 4, + SB_THUMBTRACK = 5, + SB_TOP = 6, + SB_LEFT = 6, + SB_BOTTOM = 7, + SB_RIGHT = 7, + SB_ENDSCROLL = 8, +} + +export int SetScrollPos(HWND hWnd, int nBar, int nPos, BOOL bRedraw); +export int GetScrollPos(HWND hWnd, int nBar); +export BOOL SetScrollRange(HWND hWnd, int nBar, int nMinPos, int nMaxPos, BOOL bRedraw); +export BOOL GetScrollRange(HWND hWnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos); +export BOOL ShowScrollBar(HWND hWnd, int wBar, BOOL bShow); +export BOOL EnableScrollBar(HWND hWnd, UINT wSBflags, UINT wArrows); + +/* + * LockWindowUpdate API + */ + +export BOOL LockWindowUpdate(HWND hWndLock); +export BOOL ScrollWindow(HWND hWnd, int XAmount, int YAmount, RECT* lpRect, RECT* lpClipRect); +export BOOL ScrollDC(HDC hDC, int dx, int dy, RECT* lprcScroll, RECT* lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate); +export int ScrollWindowEx(HWND hWnd, int dx, int dy, RECT* prcScroll, RECT* prcClip, HRGN hrgnUpdate, LPRECT prcUpdate, UINT flags); + +/* + * Virtual Keys, Standard Set + */ +enum +{ VK_LBUTTON = 0x01, + VK_RBUTTON = 0x02, + VK_CANCEL = 0x03, + VK_MBUTTON = 0x04, /* NOT contiguous with L & RBUTTON */ + + VK_BACK = 0x08, + VK_TAB = 0x09, + + VK_CLEAR = 0x0C, + VK_RETURN = 0x0D, + + VK_SHIFT = 0x10, + VK_CONTROL = 0x11, + VK_MENU = 0x12, + VK_PAUSE = 0x13, + VK_CAPITAL = 0x14, + + + VK_ESCAPE = 0x1B, + + VK_SPACE = 0x20, + VK_PRIOR = 0x21, + VK_NEXT = 0x22, + VK_END = 0x23, + VK_HOME = 0x24, + VK_LEFT = 0x25, + VK_UP = 0x26, + VK_RIGHT = 0x27, + VK_DOWN = 0x28, + VK_SELECT = 0x29, + VK_PRINT = 0x2A, + VK_EXECUTE = 0x2B, + VK_SNAPSHOT = 0x2C, + VK_INSERT = 0x2D, + VK_DELETE = 0x2E, + VK_HELP = 0x2F, + +/* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ +/* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ + + VK_LWIN = 0x5B, + VK_RWIN = 0x5C, + VK_APPS = 0x5D, + + VK_NUMPAD0 = 0x60, + VK_NUMPAD1 = 0x61, + VK_NUMPAD2 = 0x62, + VK_NUMPAD3 = 0x63, + VK_NUMPAD4 = 0x64, + VK_NUMPAD5 = 0x65, + VK_NUMPAD6 = 0x66, + VK_NUMPAD7 = 0x67, + VK_NUMPAD8 = 0x68, + VK_NUMPAD9 = 0x69, + VK_MULTIPLY = 0x6A, + VK_ADD = 0x6B, + VK_SEPARATOR = 0x6C, + VK_SUBTRACT = 0x6D, + VK_DECIMAL = 0x6E, + VK_DIVIDE = 0x6F, + VK_F1 = 0x70, + VK_F2 = 0x71, + VK_F3 = 0x72, + VK_F4 = 0x73, + VK_F5 = 0x74, + VK_F6 = 0x75, + VK_F7 = 0x76, + VK_F8 = 0x77, + VK_F9 = 0x78, + VK_F10 = 0x79, + VK_F11 = 0x7A, + VK_F12 = 0x7B, + VK_F13 = 0x7C, + VK_F14 = 0x7D, + VK_F15 = 0x7E, + VK_F16 = 0x7F, + VK_F17 = 0x80, + VK_F18 = 0x81, + VK_F19 = 0x82, + VK_F20 = 0x83, + VK_F21 = 0x84, + VK_F22 = 0x85, + VK_F23 = 0x86, + VK_F24 = 0x87, + + VK_NUMLOCK = 0x90, + VK_SCROLL = 0x91, + +/* + * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys. + * Used only as parameters to GetAsyncKeyState() and GetKeyState(). + * No other API or message will distinguish left and right keys in this way. + */ + VK_LSHIFT = 0xA0, + VK_RSHIFT = 0xA1, + VK_LCONTROL = 0xA2, + VK_RCONTROL = 0xA3, + VK_LMENU = 0xA4, + VK_RMENU = 0xA5, + + + VK_PROCESSKEY = 0xE5, + + + VK_ATTN = 0xF6, + VK_CRSEL = 0xF7, + VK_EXSEL = 0xF8, + VK_EREOF = 0xF9, + VK_PLAY = 0xFA, + VK_ZOOM = 0xFB, + VK_NONAME = 0xFC, + VK_PA1 = 0xFD, + VK_OEM_CLEAR = 0xFE, +} + +export LRESULT SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + +alias UINT (*LPOFNHOOKPROC) (HWND, UINT, WPARAM, LPARAM); + +struct OPENFILENAMEA { + DWORD lStructSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCSTR lpstrFilter; + LPSTR lpstrCustomFilter; + DWORD nMaxCustFilter; + DWORD nFilterIndex; + LPSTR lpstrFile; + DWORD nMaxFile; + LPSTR lpstrFileTitle; + DWORD nMaxFileTitle; + LPCSTR lpstrInitialDir; + LPCSTR lpstrTitle; + DWORD Flags; + WORD nFileOffset; + WORD nFileExtension; + LPCSTR lpstrDefExt; + LPARAM lCustData; + LPOFNHOOKPROC lpfnHook; + LPCSTR lpTemplateName; +} +alias OPENFILENAMEA *LPOPENFILENAMEA; + +struct OPENFILENAMEW { + DWORD lStructSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCWSTR lpstrFilter; + LPWSTR lpstrCustomFilter; + DWORD nMaxCustFilter; + DWORD nFilterIndex; + LPWSTR lpstrFile; + DWORD nMaxFile; + LPWSTR lpstrFileTitle; + DWORD nMaxFileTitle; + LPCWSTR lpstrInitialDir; + LPCWSTR lpstrTitle; + DWORD Flags; + WORD nFileOffset; + WORD nFileExtension; + LPCWSTR lpstrDefExt; + LPARAM lCustData; + LPOFNHOOKPROC lpfnHook; + LPCWSTR lpTemplateName; +} +alias OPENFILENAMEW *LPOPENFILENAMEW; + +BOOL GetOpenFileNameA(LPOPENFILENAMEA); +BOOL GetOpenFileNameW(LPOPENFILENAMEW); + +BOOL GetSaveFileNameA(LPOPENFILENAMEA); +BOOL GetSaveFileNameW(LPOPENFILENAMEW); + +short GetFileTitleA(LPCSTR, LPSTR, WORD); +short GetFileTitleW(LPCWSTR, LPWSTR, WORD); + +enum +{ + PM_NOREMOVE = 0x0000, + PM_REMOVE = 0x0001, + PM_NOYIELD = 0x0002, +} + +/* Bitmap Header Definition */ +struct BITMAP +{ + LONG bmType; + LONG bmWidth; + LONG bmHeight; + LONG bmWidthBytes; + WORD bmPlanes; + WORD bmBitsPixel; + LPVOID bmBits; +} +alias BITMAP* PBITMAP, NPBITMAP, LPBITMAP; + + +export HDC CreateCompatibleDC(HDC); + +export int GetObjectA(HGDIOBJ, int, LPVOID); +export int GetObjectW(HGDIOBJ, int, LPVOID); +export BOOL DeleteDC(HDC); + +struct LOGFONTA +{ + LONG lfHeight; + LONG lfWidth; + LONG lfEscapement; + LONG lfOrientation; + LONG lfWeight; + BYTE lfItalic; + BYTE lfUnderline; + BYTE lfStrikeOut; + BYTE lfCharSet; + BYTE lfOutPrecision; + BYTE lfClipPrecision; + BYTE lfQuality; + BYTE lfPitchAndFamily; + CHAR lfFaceName[32 ]; +} +alias LOGFONTA* PLOGFONTA, NPLOGFONTA, LPLOGFONTA; + +export HMENU LoadMenuA(HINSTANCE hInstance, LPCSTR lpMenuName); +export HMENU LoadMenuW(HINSTANCE hInstance, LPCWSTR lpMenuName); + +export HMENU GetSubMenu(HMENU hMenu, int nPos); + +export HBITMAP LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName); +export HBITMAP LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName); + +LPSTR MAKEINTRESOURCEA(int i) { return cast(LPSTR)(cast(DWORD)(cast(WORD)(i))); } + +export HFONT CreateFontIndirectA(LOGFONTA *); + +export BOOL MessageBeep(UINT uType); +export int ShowCursor(BOOL bShow); +export BOOL SetCursorPos(int X, int Y); +export HCURSOR SetCursor(HCURSOR hCursor); +export BOOL GetCursorPos(LPPOINT lpPoint); +export BOOL ClipCursor( RECT *lpRect); +export BOOL GetClipCursor(LPRECT lpRect); +export HCURSOR GetCursor(); +export BOOL CreateCaret(HWND hWnd, HBITMAP hBitmap , int nWidth, int nHeight); +export UINT GetCaretBlinkTime(); +export BOOL SetCaretBlinkTime(UINT uMSeconds); +export BOOL DestroyCaret(); +export BOOL HideCaret(HWND hWnd); +export BOOL ShowCaret(HWND hWnd); +export BOOL SetCaretPos(int X, int Y); +export BOOL GetCaretPos(LPPOINT lpPoint); +export BOOL ClientToScreen(HWND hWnd, LPPOINT lpPoint); +export BOOL ScreenToClient(HWND hWnd, LPPOINT lpPoint); +export int MapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints); +export HWND WindowFromPoint(POINT Point); +export HWND ChildWindowFromPoint(HWND hWndParent, POINT Point); + + +export BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, + int nReserved, HWND hWnd, RECT *prcRect); + +align (2) struct DLGTEMPLATE { + DWORD style; + DWORD dwExtendedStyle; + WORD cdit; + short x; + short y; + short cx; + short cy; +} +alias DLGTEMPLATE *LPDLGTEMPLATEA; +alias DLGTEMPLATE *LPDLGTEMPLATEW; + + +alias LPDLGTEMPLATEA LPDLGTEMPLATE; + +alias DLGTEMPLATE *LPCDLGTEMPLATEA; +alias DLGTEMPLATE *LPCDLGTEMPLATEW; + + +alias LPCDLGTEMPLATEA LPCDLGTEMPLATE; + + +export int DialogBoxParamA(HINSTANCE hInstance, LPCSTR lpTemplateName, + HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); +export int DialogBoxIndirectParamA(HINSTANCE hInstance, + LPCDLGTEMPLATEA hDialogTemplate, HWND hWndParent, DLGPROC lpDialogFunc, + LPARAM dwInitParam); + +enum : DWORD +{ + SRCCOPY = cast(DWORD)0x00CC0020, /* dest = source */ + SRCPAINT = cast(DWORD)0x00EE0086, /* dest = source OR dest */ + SRCAND = cast(DWORD)0x008800C6, /* dest = source AND dest */ + SRCINVERT = cast(DWORD)0x00660046, /* dest = source XOR dest */ + SRCERASE = cast(DWORD)0x00440328, /* dest = source AND (NOT dest) */ + NOTSRCCOPY = cast(DWORD)0x00330008, /* dest = (NOT source) */ + NOTSRCERASE = cast(DWORD)0x001100A6, /* dest = (NOT src) AND (NOT dest) */ + MERGECOPY = cast(DWORD)0x00C000CA, /* dest = (source AND pattern) */ + MERGEPAINT = cast(DWORD)0x00BB0226, /* dest = (NOT source) OR dest */ + PATCOPY = cast(DWORD)0x00F00021, /* dest = pattern */ + PATPAINT = cast(DWORD)0x00FB0A09, /* dest = DPSnoo */ + PATINVERT = cast(DWORD)0x005A0049, /* dest = pattern XOR dest */ + DSTINVERT = cast(DWORD)0x00550009, /* dest = (NOT dest) */ + BLACKNESS = cast(DWORD)0x00000042, /* dest = BLACK */ + WHITENESS = cast(DWORD)0x00FF0062, /* dest = WHITE */ +} + +enum +{ + SND_SYNC = 0x0000, /* play synchronously (default) */ + SND_ASYNC = 0x0001, /* play asynchronously */ + SND_NODEFAULT = 0x0002, /* silence (!default) if sound not found */ + SND_MEMORY = 0x0004, /* pszSound points to a memory file */ + SND_LOOP = 0x0008, /* loop the sound until next sndPlaySound */ + SND_NOSTOP = 0x0010, /* don't stop any currently playing sound */ + + SND_NOWAIT = 0x00002000, /* don't wait if the driver is busy */ + SND_ALIAS = 0x00010000, /* name is a registry alias */ + SND_ALIAS_ID = 0x00110000, /* alias is a predefined ID */ + SND_FILENAME = 0x00020000, /* name is file name */ + SND_RESOURCE = 0x00040004, /* name is resource name or atom */ + + SND_PURGE = 0x0040, /* purge non-static events for task */ + SND_APPLICATION = 0x0080, /* look for application specific association */ + + + SND_ALIAS_START = 0, /* alias base */ +} + +export BOOL PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound); +export BOOL PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound); + +export int GetClipBox(HDC, LPRECT); +export int GetClipRgn(HDC, HRGN); +export int GetMetaRgn(HDC, HRGN); +export HGDIOBJ GetCurrentObject(HDC, UINT); +export BOOL GetCurrentPositionEx(HDC, LPPOINT); +export int GetDeviceCaps(HDC, int); + +struct LOGPEN + { + UINT lopnStyle; + POINT lopnWidth; + COLORREF lopnColor; +} +alias LOGPEN* PLOGPEN, NPLOGPEN, LPLOGPEN; + +enum +{ + PS_SOLID = 0, + PS_DASH = 1, /* ------- */ + PS_DOT = 2, /* ....... */ + PS_DASHDOT = 3, /* _._._._ */ + PS_DASHDOTDOT = 4, /* _.._.._ */ + PS_NULL = 5, + PS_INSIDEFRAME = 6, + PS_USERSTYLE = 7, + PS_ALTERNATE = 8, + PS_STYLE_MASK = 0x0000000F, + + PS_ENDCAP_ROUND = 0x00000000, + PS_ENDCAP_SQUARE = 0x00000100, + PS_ENDCAP_FLAT = 0x00000200, + PS_ENDCAP_MASK = 0x00000F00, + + PS_JOIN_ROUND = 0x00000000, + PS_JOIN_BEVEL = 0x00001000, + PS_JOIN_MITER = 0x00002000, + PS_JOIN_MASK = 0x0000F000, + + PS_COSMETIC = 0x00000000, + PS_GEOMETRIC = 0x00010000, + PS_TYPE_MASK = 0x000F0000, +} + +export HPALETTE CreatePalette(LOGPALETTE *); +export HPEN CreatePen(int, int, COLORREF); +export HPEN CreatePenIndirect(LOGPEN *); +export HRGN CreatePolyPolygonRgn(POINT *, INT *, int, int); +export HBRUSH CreatePatternBrush(HBITMAP); +export HRGN CreateRectRgn(int, int, int, int); +export HRGN CreateRectRgnIndirect(RECT *); +export HRGN CreateRoundRectRgn(int, int, int, int, int, int); +export BOOL CreateScalableFontResourceA(DWORD, LPCSTR, LPCSTR, LPCSTR); +export BOOL CreateScalableFontResourceW(DWORD, LPCWSTR, LPCWSTR, LPCWSTR); + +COLORREF RGB(int r, int g, int b) +{ + return cast(COLORREF) + ((cast(BYTE)r|(cast(WORD)(cast(BYTE)g)<<8))|((cast(DWORD)cast(BYTE)b)<<16)); +} + +export BOOL LineTo(HDC, int, int); +export BOOL DeleteObject(HGDIOBJ); +export int FillRect(HDC hDC, RECT *lprc, HBRUSH hbr); + + +export BOOL EndDialog(HWND hDlg, int nResult); +export HWND GetDlgItem(HWND hDlg, int nIDDlgItem); + +export BOOL SetDlgItemInt(HWND hDlg, int nIDDlgItem, UINT uValue, BOOL bSigned); +export UINT GetDlgItemInt(HWND hDlg, int nIDDlgItem, BOOL *lpTranslated, + BOOL bSigned); + +export BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPCSTR lpString); +export BOOL SetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPCWSTR lpString); + +export UINT GetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPSTR lpString, int nMaxCount); +export UINT GetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount); + +export BOOL CheckDlgButton(HWND hDlg, int nIDButton, UINT uCheck); +export BOOL CheckRadioButton(HWND hDlg, int nIDFirstButton, int nIDLastButton, + int nIDCheckButton); + +export UINT IsDlgButtonChecked(HWND hDlg, int nIDButton); + +export HWND SetFocus(HWND hWnd); + +export int wsprintfA(LPSTR, LPCSTR, ...); +export int wsprintfW(LPWSTR, LPCWSTR, ...); + +enum : uint +{ + INFINITE = uint.max, + WAIT_OBJECT_0 = 0, +} + +export HANDLE CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName); +export HANDLE OpenSemaphoreA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName); +export BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount); + +struct COORD { + SHORT X; + SHORT Y; +} +alias COORD *PCOORD; + +struct SMALL_RECT { + SHORT Left; + SHORT Top; + SHORT Right; + SHORT Bottom; +} +alias SMALL_RECT *PSMALL_RECT; + +struct KEY_EVENT_RECORD { + BOOL bKeyDown; + WORD wRepeatCount; + WORD wVirtualKeyCode; + WORD wVirtualScanCode; + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } + DWORD dwControlKeyState; +} +alias KEY_EVENT_RECORD *PKEY_EVENT_RECORD; + +// +// ControlKeyState flags +// + +enum +{ + RIGHT_ALT_PRESSED = 0x0001, // the right alt key is pressed. + LEFT_ALT_PRESSED = 0x0002, // the left alt key is pressed. + RIGHT_CTRL_PRESSED = 0x0004, // the right ctrl key is pressed. + LEFT_CTRL_PRESSED = 0x0008, // the left ctrl key is pressed. + SHIFT_PRESSED = 0x0010, // the shift key is pressed. + NUMLOCK_ON = 0x0020, // the numlock light is on. + SCROLLLOCK_ON = 0x0040, // the scrolllock light is on. + CAPSLOCK_ON = 0x0080, // the capslock light is on. + ENHANCED_KEY = 0x0100, // the key is enhanced. +} + +struct MOUSE_EVENT_RECORD { + COORD dwMousePosition; + DWORD dwButtonState; + DWORD dwControlKeyState; + DWORD dwEventFlags; +} +alias MOUSE_EVENT_RECORD *PMOUSE_EVENT_RECORD; + +// +// ButtonState flags +// +enum +{ + FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001, + RIGHTMOST_BUTTON_PRESSED = 0x0002, + FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004, + FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008, + FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010, +} + +// +// EventFlags +// + +enum +{ + MOUSE_MOVED = 0x0001, + DOUBLE_CLICK = 0x0002, +} + +struct WINDOW_BUFFER_SIZE_RECORD { + COORD dwSize; +} +alias WINDOW_BUFFER_SIZE_RECORD *PWINDOW_BUFFER_SIZE_RECORD; + +struct MENU_EVENT_RECORD { + UINT dwCommandId; +} +alias MENU_EVENT_RECORD *PMENU_EVENT_RECORD; + +struct FOCUS_EVENT_RECORD { + BOOL bSetFocus; +} +alias FOCUS_EVENT_RECORD *PFOCUS_EVENT_RECORD; + +struct INPUT_RECORD { + WORD EventType; + union { + KEY_EVENT_RECORD KeyEvent; + MOUSE_EVENT_RECORD MouseEvent; + WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; + MENU_EVENT_RECORD MenuEvent; + FOCUS_EVENT_RECORD FocusEvent; + } +} +alias INPUT_RECORD *PINPUT_RECORD; + +// +// EventType flags: +// + +enum +{ + KEY_EVENT = 0x0001, // Event contains key event record + MOUSE_EVENT = 0x0002, // Event contains mouse event record + WINDOW_BUFFER_SIZE_EVENT = 0x0004, // Event contains window change event record + MENU_EVENT = 0x0008, // Event contains menu event record + FOCUS_EVENT = 0x0010, // event contains focus change +} + +struct CHAR_INFO { + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } + WORD Attributes; +} +alias CHAR_INFO *PCHAR_INFO; + +// +// Attributes flags: +// + +enum +{ + FOREGROUND_BLUE = 0x0001, // text color contains blue. + FOREGROUND_GREEN = 0x0002, // text color contains green. + FOREGROUND_RED = 0x0004, // text color contains red. + FOREGROUND_INTENSITY = 0x0008, // text color is intensified. + BACKGROUND_BLUE = 0x0010, // background color contains blue. + BACKGROUND_GREEN = 0x0020, // background color contains green. + BACKGROUND_RED = 0x0040, // background color contains red. + BACKGROUND_INTENSITY = 0x0080, // background color is intensified. +} + +struct CONSOLE_SCREEN_BUFFER_INFO { + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; + COORD dwMaximumWindowSize; +} +alias CONSOLE_SCREEN_BUFFER_INFO *PCONSOLE_SCREEN_BUFFER_INFO; + +struct CONSOLE_CURSOR_INFO { + DWORD dwSize; + BOOL bVisible; +} +alias CONSOLE_CURSOR_INFO *PCONSOLE_CURSOR_INFO; + +enum +{ + ENABLE_PROCESSED_INPUT = 0x0001, + ENABLE_LINE_INPUT = 0x0002, + ENABLE_ECHO_INPUT = 0x0004, + ENABLE_WINDOW_INPUT = 0x0008, + ENABLE_MOUSE_INPUT = 0x0010, +} + +enum +{ + ENABLE_PROCESSED_OUTPUT = 0x0001, + ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002, +} + +BOOL PeekConsoleInputA(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsRead); +BOOL PeekConsoleInputW(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsRead); +BOOL ReadConsoleInputA(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsRead); +BOOL ReadConsoleInputW(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsRead); +BOOL WriteConsoleInputA(HANDLE hConsoleInput, in INPUT_RECORD *lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsWritten); +BOOL WriteConsoleInputW(HANDLE hConsoleInput, in INPUT_RECORD *lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsWritten); +BOOL ReadConsoleOutputA(HANDLE hConsoleOutput, PCHAR_INFO lpBuffer, COORD dwBufferSize, COORD dwBufferCoord, PSMALL_RECT lpReadRegion); +BOOL ReadConsoleOutputW(HANDLE hConsoleOutput, PCHAR_INFO lpBuffer, COORD dwBufferSize, COORD dwBufferCoord, PSMALL_RECT lpReadRegion); +BOOL WriteConsoleOutputA(HANDLE hConsoleOutput, in CHAR_INFO *lpBuffer, COORD dwBufferSize, COORD dwBufferCoord, PSMALL_RECT lpWriteRegion); +BOOL WriteConsoleOutputW(HANDLE hConsoleOutput, in CHAR_INFO *lpBuffer, COORD dwBufferSize, COORD dwBufferCoord, PSMALL_RECT lpWriteRegion); +BOOL ReadConsoleOutputCharacterA(HANDLE hConsoleOutput, LPSTR lpCharacter, DWORD nLength, COORD dwReadCoord, LPDWORD lpNumberOfCharsRead); +BOOL ReadConsoleOutputCharacterW(HANDLE hConsoleOutput, LPWSTR lpCharacter, DWORD nLength, COORD dwReadCoord, LPDWORD lpNumberOfCharsRead); +BOOL ReadConsoleOutputAttribute(HANDLE hConsoleOutput, LPWORD lpAttribute, DWORD nLength, COORD dwReadCoord, LPDWORD lpNumberOfAttrsRead); +BOOL WriteConsoleOutputCharacterA(HANDLE hConsoleOutput, LPCSTR lpCharacter, DWORD nLength, COORD dwWriteCoord, LPDWORD lpNumberOfCharsWritten); +BOOL WriteConsoleOutputCharacterW(HANDLE hConsoleOutput, LPCWSTR lpCharacter, DWORD nLength, COORD dwWriteCoord, LPDWORD lpNumberOfCharsWritten); +BOOL WriteConsoleOutputAttribute(HANDLE hConsoleOutput, in WORD *lpAttribute, DWORD nLength, COORD dwWriteCoord, LPDWORD lpNumberOfAttrsWritten); +BOOL FillConsoleOutputCharacterA(HANDLE hConsoleOutput, CHAR cCharacter, DWORD nLength, COORD dwWriteCoord, LPDWORD lpNumberOfCharsWritten); +BOOL FillConsoleOutputCharacterW(HANDLE hConsoleOutput, WCHAR cCharacter, DWORD nLength, COORD dwWriteCoord, LPDWORD lpNumberOfCharsWritten); +BOOL FillConsoleOutputAttribute(HANDLE hConsoleOutput, WORD wAttribute, DWORD nLength, COORD dwWriteCoord, LPDWORD lpNumberOfAttrsWritten); +BOOL GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode); +BOOL GetNumberOfConsoleInputEvents(HANDLE hConsoleInput, LPDWORD lpNumberOfEvents); +BOOL GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); +COORD GetLargestConsoleWindowSize( HANDLE hConsoleOutput); +BOOL GetConsoleCursorInfo(HANDLE hConsoleOutput, PCONSOLE_CURSOR_INFO lpConsoleCursorInfo); +BOOL GetNumberOfConsoleMouseButtons( LPDWORD lpNumberOfMouseButtons); +BOOL SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode); +BOOL SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput); +BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput); +BOOL SetConsoleScreenBufferSize(HANDLE hConsoleOutput, COORD dwSize); +BOOL SetConsoleCursorPosition(HANDLE hConsoleOutput, COORD dwCursorPosition); +BOOL SetConsoleCursorInfo(HANDLE hConsoleOutput, in CONSOLE_CURSOR_INFO *lpConsoleCursorInfo); +BOOL ScrollConsoleScreenBufferA(HANDLE hConsoleOutput, in SMALL_RECT *lpScrollRectangle, in SMALL_RECT *lpClipRectangle, COORD dwDestinationOrigin, in CHAR_INFO *lpFill); +BOOL ScrollConsoleScreenBufferW(HANDLE hConsoleOutput, in SMALL_RECT *lpScrollRectangle, in SMALL_RECT *lpClipRectangle, COORD dwDestinationOrigin, in CHAR_INFO *lpFill); +BOOL SetConsoleWindowInfo(HANDLE hConsoleOutput, BOOL bAbsolute, in SMALL_RECT *lpConsoleWindow); +BOOL SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes); +alias BOOL(*PHANDLER_ROUTINE)(DWORD CtrlType); +BOOL SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add); +BOOL GenerateConsoleCtrlEvent( DWORD dwCtrlEvent, DWORD dwProcessGroupId); +BOOL AllocConsole(); +BOOL FreeConsole(); +DWORD GetConsoleTitleA(LPSTR lpConsoleTitle, DWORD nSize); +DWORD GetConsoleTitleW(LPWSTR lpConsoleTitle, DWORD nSize); +BOOL SetConsoleTitleA(LPCSTR lpConsoleTitle); +BOOL SetConsoleTitleW(LPCWSTR lpConsoleTitle); +BOOL ReadConsoleA(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, LPVOID lpReserved); +BOOL ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, LPVOID lpReserved); +BOOL WriteConsoleA(HANDLE hConsoleOutput, in void *lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved); +BOOL WriteConsoleW(HANDLE hConsoleOutput, in void *lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved); +HANDLE CreateConsoleScreenBuffer(DWORD dwDesiredAccess, DWORD dwShareMode, in SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwFlags, LPVOID lpScreenBufferData); +UINT GetConsoleCP(); +BOOL SetConsoleCP( UINT wCodePageID); +UINT GetConsoleOutputCP(); +BOOL SetConsoleOutputCP(UINT wCodePageID); + +enum +{ + CONSOLE_TEXTMODE_BUFFER = 1, +} + +enum +{ + SM_CXSCREEN = 0, + SM_CYSCREEN = 1, + SM_CXVSCROLL = 2, + SM_CYHSCROLL = 3, + SM_CYCAPTION = 4, + SM_CXBORDER = 5, + SM_CYBORDER = 6, + SM_CXDLGFRAME = 7, + SM_CYDLGFRAME = 8, + SM_CYVTHUMB = 9, + SM_CXHTHUMB = 10, + SM_CXICON = 11, + SM_CYICON = 12, + SM_CXCURSOR = 13, + SM_CYCURSOR = 14, + SM_CYMENU = 15, + SM_CXFULLSCREEN = 16, + SM_CYFULLSCREEN = 17, + SM_CYKANJIWINDOW = 18, + SM_MOUSEPRESENT = 19, + SM_CYVSCROLL = 20, + SM_CXHSCROLL = 21, + SM_DEBUG = 22, + SM_SWAPBUTTON = 23, + SM_RESERVED1 = 24, + SM_RESERVED2 = 25, + SM_RESERVED3 = 26, + SM_RESERVED4 = 27, + SM_CXMIN = 28, + SM_CYMIN = 29, + SM_CXSIZE = 30, + SM_CYSIZE = 31, + SM_CXFRAME = 32, + SM_CYFRAME = 33, + SM_CXMINTRACK = 34, + SM_CYMINTRACK = 35, + SM_CXDOUBLECLK = 36, + SM_CYDOUBLECLK = 37, + SM_CXICONSPACING = 38, + SM_CYICONSPACING = 39, + SM_MENUDROPALIGNMENT = 40, + SM_PENWINDOWS = 41, + SM_DBCSENABLED = 42, + SM_CMOUSEBUTTONS = 43, + + + SM_CXFIXEDFRAME = SM_CXDLGFRAME, + SM_CYFIXEDFRAME = SM_CYDLGFRAME, + SM_CXSIZEFRAME = SM_CXFRAME, + SM_CYSIZEFRAME = SM_CYFRAME, + + SM_SECURE = 44, + SM_CXEDGE = 45, + SM_CYEDGE = 46, + SM_CXMINSPACING = 47, + SM_CYMINSPACING = 48, + SM_CXSMICON = 49, + SM_CYSMICON = 50, + SM_CYSMCAPTION = 51, + SM_CXSMSIZE = 52, + SM_CYSMSIZE = 53, + SM_CXMENUSIZE = 54, + SM_CYMENUSIZE = 55, + SM_ARRANGE = 56, + SM_CXMINIMIZED = 57, + SM_CYMINIMIZED = 58, + SM_CXMAXTRACK = 59, + SM_CYMAXTRACK = 60, + SM_CXMAXIMIZED = 61, + SM_CYMAXIMIZED = 62, + SM_NETWORK = 63, + SM_CLEANBOOT = 67, + SM_CXDRAG = 68, + SM_CYDRAG = 69, + SM_SHOWSOUNDS = 70, + SM_CXMENUCHECK = 71, + SM_CYMENUCHECK = 72, + SM_SLOWMACHINE = 73, + SM_MIDEASTENABLED = 74, + SM_CMETRICS = 75, +} + +int GetSystemMetrics(int nIndex); + +enum : DWORD +{ + STILL_ACTIVE = (0x103), +} + +DWORD TlsAlloc(); +LPVOID TlsGetValue(DWORD); +BOOL TlsSetValue(DWORD, LPVOID); +BOOL TlsFree(DWORD); + +} diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..7584c6f --- /dev/null +++ b/license.txt @@ -0,0 +1,10 @@ +Copyright (c) 2008, The D Runtime Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/src/build-dmd.bat b/src/build-dmd.bat new file mode 100644 index 0000000..d2c0b98 --- /dev/null +++ b/src/build-dmd.bat @@ -0,0 +1,7 @@ +@echo off +set OLDHOME=%HOME% +set HOME=%CD% +make clean -fdmd-win32.mak +make lib install -fdmd-win32.mak +make clean -fdmd-win32.mak +set HOME=%OLDHOME% \ No newline at end of file diff --git a/src/build-dmd.sh b/src/build-dmd.sh new file mode 100644 index 0000000..d6be599 --- /dev/null +++ b/src/build-dmd.sh @@ -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 lib doc install -fdmd-posix.mak || goerror +make clean -fdmd-posix.mak || goerror +chmod 644 ../import/*.di || goerror + +export HOME=$OLDHOME diff --git a/src/compiler/dmd/aApply.d b/src/compiler/dmd/aApply.d new file mode 100644 index 0000000..f84b0d1 --- /dev/null +++ b/src/compiler/dmd/aApply.d @@ -0,0 +1,408 @@ +/** + * Part of the D programming language runtime library. + */ + +/* + * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.aApply; + +/* This code handles decoding UTF strings for foreach loops. + * There are 6 combinations of conversions between char, wchar, + * and dchar, and 2 of each of those. + */ + +private import util.utf; + +/********************************************** + */ + +// 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; +} diff --git a/src/compiler/dmd/aApplyR.d b/src/compiler/dmd/aApplyR.d new file mode 100644 index 0000000..081ae60 --- /dev/null +++ b/src/compiler/dmd/aApplyR.d @@ -0,0 +1,974 @@ +/** + * Part of the D programming language runtime library. + */ + +/* + * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +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 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); +} diff --git a/src/compiler/dmd/aaA.d b/src/compiler/dmd/aaA.d new file mode 100644 index 0000000..3c61b9a --- /dev/null +++ b/src/compiler/dmd/aaA.d @@ -0,0 +1,839 @@ +//_ aaA.d + +/** + * Part of the D programming language runtime library. + * Implementation of associative arrays. + */ + +/* + * Copyright (C) 2000-2008 by Digital Mars, http://www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.aaA; + +private +{ + import stdc.stdarg; + import stdc.string; + + enum BlkAttr : uint + { + FINALIZE = 0b0000_0001, + NO_SCAN = 0b0000_0010, + NO_MOVE = 0b0000_0100, + ALL_BITS = 0b1111_1111 + } + + extern (C) void* gc_malloc( size_t sz, uint ba = 0 ); + extern (C) void* gc_calloc( size_t sz, uint ba = 0 ); + extern (C) void gc_free( void* p ); +} + +// Auto-rehash and pre-allocate - Dave Fladebo + +static size_t[] prime_list = [ + 97UL, 389UL, + 1_543UL, 6_151UL, + 24_593UL, 98_317UL, + 393_241UL, 1_572_869UL, + 6_291_469UL, 25_165_843UL, + 100_663_319UL, 402_653_189UL, + 1_610_612_741UL, 4_294_967_291UL, +// 8_589_934_513UL, 17_179_869_143UL +]; + +/* 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; + auto keysize = aligntsize(keyti.tsize()); + + if (!aa.a) + aa.a = new BB(); + 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).length, nodes); + if (nodes > aa.a.b.length * 4) + { + _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); + } + + newb.nodes = aa.nodes; + newb.keyti = aa.keyti; + } + + *paa.a = newb; + } + return (*paa).a; +} + + +/******************************************** + * 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; +} diff --git a/src/compiler/dmd/adi.d b/src/compiler/dmd/adi.d new file mode 100644 index 0000000..908841b --- /dev/null +++ b/src/compiler/dmd/adi.d @@ -0,0 +1,626 @@ +//_ adi.d + +/** + * Part of the D programming language runtime library. + * Dynamic array property support routines + */ + +/* + * Copyright (C) 2000-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.adi; + +//debug=adi; // uncomment to turn on debugging printf's + +private +{ + debug(adi) import stdc.stdio; + import stdc.string; + import stdc.stdlib; + import util.utf; + + enum BlkAttr : uint + { + FINALIZE = 0b0000_0001, + NO_SCAN = 0b0000_0010, + NO_MOVE = 0b0000_0100, + ALL_BITS = 0b1111_1111 + } + + extern (C) void* gc_malloc( size_t sz, uint ba = 0 ); + extern (C) void* gc_calloc( size_t sz, uint ba = 0 ); + extern (C) void gc_free( void* p ); +} + + +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"; + wstring r; + + r = a.dup.reverse; + assert(r == "dcba"); + + a = "a\U00012356\U00012346c"; + r = a.dup.reverse; + assert(r == "c\U00012346\U00012356a"); + + a = "ab\U00012345c"; + r = a.dup.reverse; + assert(r == "c\U00012345ba"); +} + + +/********************************************** + * Support for array.reverse property. + */ + +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) + { + dchar[] 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) + { + dchar[] 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"); +} diff --git a/src/compiler/dmd/alloca.d b/src/compiler/dmd/alloca.d new file mode 100644 index 0000000..1e3d2f7 --- /dev/null +++ b/src/compiler/dmd/alloca.d @@ -0,0 +1,110 @@ +/*_ _alloca.d + * Copyright (C) 1990-2003 by Digital Mars, www.digitalmars.com + * All Rights Reserved + * Written by Walter Bright + */ + +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 ; + add EAX,3 ; + and EAX,0xFFFFFFFC ; // round up to dword + 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 ; + } +} diff --git a/src/compiler/dmd/arraybyte.d b/src/compiler/dmd/arraybyte.d new file mode 100644 index 0000000..373dec4 --- /dev/null +++ b/src/compiler/dmd/arraybyte.d @@ -0,0 +1,1890 @@ +/*************************** + * D programming language http://www.digitalmars.com/d/ + * Runtime support for byte array operations. + * Based on code originally written by Burton Radons. + * Placed in public domain. + */ + +/* Contains SSE2 and MMX versions of certain operations for char, byte, + * and ubyte ('a', 'g' and 'h' suffixes). + */ + +module rt.arraybyte; + +import util.cpuid; + +version (Unittest) +{ + /* This is so unit tests will test every CPU variant + */ + int cpuid; + const int CPUID_MAX = 4; + bool mmx() { return cpuid == 1 && util.cpuid.mmx(); } + bool sse() { return cpuid == 2 && util.cpuid.sse(); } + bool sse2() { return cpuid == 3 && util.cpuid.sse2(); } + bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); } +} +else +{ + alias util.cpuid.mmx mmx; + alias util.cpuid.sse sse; + alias util.cpuid.sse2 sse2; + alias 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 byte T; + +extern (C): + +/* ======================================================================== */ + + +/*********************** + * Computes: + * a[] = b[] + value + */ + +T[] _arraySliceExpAddSliceAssign_a(T[] a, T value, T[] b) +{ + return _arraySliceExpAddSliceAssign_g(a, value, b); +} + +T[] _arraySliceExpAddSliceAssign_h(T[] a, T value, T[] b) +{ + return _arraySliceExpAddSliceAssign_g(a, value, b); +} + +T[] _arraySliceExpAddSliceAssign_g(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpAddSliceAssign_g()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1088% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + uint l = cast(ubyte) value; + l |= (l << 8); + l |= (l << 16); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startaddsse2u: + add ESI, 64; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + movdqu XMM2, [EAX+32]; + movdqu XMM3, [EAX+48]; + add EAX, 64; + paddb XMM0, XMM4; + paddb XMM1, XMM4; + paddb XMM2, XMM4; + paddb XMM3, XMM4; + movdqu [ESI -64], XMM0; + movdqu [ESI+16-64], XMM1; + movdqu [ESI+32-64], XMM2; + movdqu [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startaddsse2a: + add ESI, 64; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + movdqa XMM2, [EAX+32]; + movdqa XMM3, [EAX+48]; + add EAX, 64; + paddb XMM0, XMM4; + paddb XMM1, XMM4; + paddb XMM2, XMM4; + paddb XMM3, XMM4; + movdqa [ESI -64], XMM0; + movdqa [ESI+16-64], XMM1; + movdqa [ESI+32-64], XMM2; + movdqa [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 1000% faster + if (mmx() && a.length >= 32) + { + auto n = aptr + (a.length & ~31); + + uint l = cast(ubyte) value; + l |= (l << 8); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd MM4, l; + pshufw MM4, MM4, 0; + + align 4; + startaddmmx: + add ESI, 32; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + add EAX, 32; + paddb MM0, MM4; + paddb MM1, MM4; + paddb MM2, MM4; + paddb MM3, MM4; + movq [ESI -32], MM0; + movq [ESI+8 -32], MM1; + movq [ESI+16-32], MM2; + movq [ESI+24-32], MM3; + cmp ESI, EDI; + jb startaddmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + /* trying to be fair and treat normal 32-bit cpu the same way as we do + * the SIMD units, with unrolled asm. There's not enough registers, + * really. + */ + else + if (a.length >= 4) + { + + auto n = aptr + (a.length & ~3); + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov CL, value; + + align 4; + startadd386: + add ESI, 4; + mov DX, [EAX]; + mov BX, [EAX+2]; + add EAX, 4; + add BL, CL; + add BH, CL; + add DL, CL; + add DH, CL; + mov [ESI -4], DX; + mov [ESI+2 -4], BX; + cmp ESI, EDI; + jb startadd386; + + mov aptr, ESI; + mov bptr, EAX; + } + + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ + value); + + return a; +} + +unittest +{ + printf("_arraySliceExpAddSliceAssign_g 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[] + 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + 6)) + { + printf("[%d]: %d != %d + 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + c[] + */ + +T[] _arraySliceSliceAddSliceAssign_a(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceAddSliceAssign_g(a, c, b); +} + +T[] _arraySliceSliceAddSliceAssign_h(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceAddSliceAssign_g(a, c, b); +} + +T[] _arraySliceSliceAddSliceAssign_g(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 +{ + //printf("_arraySliceSliceAddSliceAssign_g()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 5739% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) + { + version (log) printf("\tsse2 unaligned\n"); + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 8; + startaddlsse2u: + add ESI, 64; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + movdqu XMM2, [EAX+32]; + movdqu XMM3, [EAX+48]; + add EAX, 64; + movdqu XMM4, [ECX]; + movdqu XMM5, [ECX+16]; + movdqu XMM6, [ECX+32]; + movdqu XMM7, [ECX+48]; + add ECX, 64; + paddb XMM0, XMM4; + paddb XMM1, XMM5; + paddb XMM2, XMM6; + paddb XMM3, XMM7; + movdqu [ESI -64], XMM0; + movdqu [ESI+16-64], XMM1; + movdqu [ESI+32-64], XMM2; + movdqu [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startaddlsse2u; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + { + version (log) printf("\tsse2 aligned\n"); + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 8; + startaddlsse2a: + add ESI, 64; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + movdqa XMM2, [EAX+32]; + movdqa XMM3, [EAX+48]; + add EAX, 64; + movdqa XMM4, [ECX]; + movdqa XMM5, [ECX+16]; + movdqa XMM6, [ECX+32]; + movdqa XMM7, [ECX+48]; + add ECX, 64; + paddb XMM0, XMM4; + paddb XMM1, XMM5; + paddb XMM2, XMM6; + paddb XMM3, XMM7; + movdqa [ESI -64], XMM0; + movdqa [ESI+16-64], XMM1; + movdqa [ESI+32-64], XMM2; + movdqa [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startaddlsse2a; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + else + // MMX version is 4428% faster + if (mmx() && a.length >= 32) + { + version (log) printf("\tmmx\n"); + auto n = aptr + (a.length & ~31); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startaddlmmx: + add ESI, 32; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + add EAX, 32; + movq MM4, [ECX]; + movq MM5, [ECX+8]; + movq MM6, [ECX+16]; + movq MM7, [ECX+24]; + add ECX, 32; + paddb MM0, MM4; + paddb MM1, MM5; + paddb MM2, MM6; + paddb MM3, MM7; + movq [ESI -32], MM0; + movq [ESI+8 -32], MM1; + movq [ESI+16-32], MM2; + movq [ESI+24-32], MM3; + cmp ESI, EDI; + jb startaddlmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + version (log) if (aptr < aend) printf("\tbase\n"); + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ + *cptr++); + + return a; +} + +unittest +{ + printf("_arraySliceSliceAddSliceAssign_g 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]: %d != %d + %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += value + */ + +T[] _arrayExpSliceAddass_a(T[] a, T value) +{ + return _arrayExpSliceAddass_g(a, value); +} + +T[] _arrayExpSliceAddass_h(T[] a, T value) +{ + return _arrayExpSliceAddass_g(a, value); +} + +T[] _arrayExpSliceAddass_g(T[] a, T value) +{ + //printf("_arrayExpSliceAddass_g(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1578% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + uint l = cast(ubyte) value; + l |= (l << 8); + l |= (l << 16); + + if (((cast(uint) aptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startaddasssse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + movdqu XMM2, [ESI+32]; + movdqu XMM3, [ESI+48]; + add ESI, 64; + paddb XMM0, XMM4; + paddb XMM1, XMM4; + paddb XMM2, XMM4; + paddb XMM3, XMM4; + movdqu [ESI -64], XMM0; + movdqu [ESI+16-64], XMM1; + movdqu [ESI+32-64], XMM2; + movdqu [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startaddasssse2u; + + mov aptr, ESI; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startaddasssse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + movdqa XMM2, [ESI+32]; + movdqa XMM3, [ESI+48]; + add ESI, 64; + paddb XMM0, XMM4; + paddb XMM1, XMM4; + paddb XMM2, XMM4; + paddb XMM3, XMM4; + movdqa [ESI -64], XMM0; + movdqa [ESI+16-64], XMM1; + movdqa [ESI+32-64], XMM2; + movdqa [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startaddasssse2a; + + mov aptr, ESI; + } + } + } + else + // MMX version is 1721% faster + if (mmx() && a.length >= 32) + { + + auto n = aptr + (a.length & ~31); + + uint l = cast(ubyte) value; + l |= (l << 8); + + asm + { + mov ESI, aptr; + mov EDI, n; + movd MM4, l; + pshufw MM4, MM4, 0; + + align 8; + startaddassmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + add ESI, 32; + paddb MM0, MM4; + paddb MM1, MM4; + paddb MM2, MM4; + paddb MM3, MM4; + movq [ESI -32], MM0; + movq [ESI+8 -32], MM1; + movq [ESI+16-32], MM2; + movq [ESI+24-32], MM3; + cmp ESI, EDI; + jb startaddassmmx; + + emms; + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ += value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceAddass_g 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); + } + + a[] = c[]; + c[] += 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + 6)) + { + printf("[%d]: %d != %d + 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += b[] + */ + +T[] _arraySliceSliceAddass_a(T[] a, T[] b) +{ + return _arraySliceSliceAddass_g(a, b); +} + +T[] _arraySliceSliceAddass_h(T[] a, T[] b) +{ + return _arraySliceSliceAddass_g(a, b); +} + +T[] _arraySliceSliceAddass_g(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceAddass_g()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 4727% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 8; + startaddasslsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + movdqu XMM2, [ESI+32]; + movdqu XMM3, [ESI+48]; + add ESI, 64; + movdqu XMM4, [ECX]; + movdqu XMM5, [ECX+16]; + movdqu XMM6, [ECX+32]; + movdqu XMM7, [ECX+48]; + add ECX, 64; + paddb XMM0, XMM4; + paddb XMM1, XMM5; + paddb XMM2, XMM6; + paddb XMM3, XMM7; + movdqu [ESI -64], XMM0; + movdqu [ESI+16-64], XMM1; + movdqu [ESI+32-64], XMM2; + movdqu [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startaddasslsse2u; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 8; + startaddasslsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + movdqa XMM2, [ESI+32]; + movdqa XMM3, [ESI+48]; + add ESI, 64; + movdqa XMM4, [ECX]; + movdqa XMM5, [ECX+16]; + movdqa XMM6, [ECX+32]; + movdqa XMM7, [ECX+48]; + add ECX, 64; + paddb XMM0, XMM4; + paddb XMM1, XMM5; + paddb XMM2, XMM6; + paddb XMM3, XMM7; + movdqa [ESI -64], XMM0; + movdqa [ESI+16-64], XMM1; + movdqa [ESI+32-64], XMM2; + movdqa [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startaddasslsse2a; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + else + // MMX version is 3059% faster + if (mmx() && a.length >= 32) + { + + auto n = aptr + (a.length & ~31); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 8; + startaddasslmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + add ESI, 32; + movq MM4, [ECX]; + movq MM5, [ECX+8]; + movq MM6, [ECX+16]; + movq MM7, [ECX+24]; + add ECX, 32; + paddb MM0, MM4; + paddb MM1, MM5; + paddb MM2, MM6; + paddb MM3, MM7; + movq [ESI -32], MM0; + movq [ESI+8 -32], MM1; + movq [ESI+16-32], MM2; + movq [ESI+24-32], MM3; + cmp ESI, EDI; + jb startaddasslmmx; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ += *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceAddass_g 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); + } + + a[] = c[]; + c[] += b[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + b[i])) + { + printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + + +/*********************** + * Computes: + * a[] = b[] - value + */ + +T[] _arraySliceExpMinSliceAssign_a(T[] a, T value, T[] b) +{ + return _arraySliceExpMinSliceAssign_g(a, value, b); +} + +T[] _arraySliceExpMinSliceAssign_h(T[] a, T value, T[] b) +{ + return _arraySliceExpMinSliceAssign_g(a, value, b); +} + +T[] _arraySliceExpMinSliceAssign_g(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMinSliceAssign_g()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1189% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + uint l = cast(ubyte) value; + l |= (l << 8); + l |= (l << 16); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startsubsse2u: + add ESI, 64; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + movdqu XMM2, [EAX+32]; + movdqu XMM3, [EAX+48]; + add EAX, 64; + psubb XMM0, XMM4; + psubb XMM1, XMM4; + psubb XMM2, XMM4; + psubb XMM3, XMM4; + movdqu [ESI -64], XMM0; + movdqu [ESI+16-64], XMM1; + movdqu [ESI+32-64], XMM2; + movdqu [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsubsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startsubsse2a: + add ESI, 64; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + movdqa XMM2, [EAX+32]; + movdqa XMM3, [EAX+48]; + add EAX, 64; + psubb XMM0, XMM4; + psubb XMM1, XMM4; + psubb XMM2, XMM4; + psubb XMM3, XMM4; + movdqa [ESI -64], XMM0; + movdqa [ESI+16-64], XMM1; + movdqa [ESI+32-64], XMM2; + movdqa [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsubsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 1079% faster + if (mmx() && a.length >= 32) + { + auto n = aptr + (a.length & ~31); + + uint l = cast(ubyte) value; + l |= (l << 8); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd MM4, l; + pshufw MM4, MM4, 0; + + align 4; + startsubmmx: + add ESI, 32; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + add EAX, 32; + psubb MM0, MM4; + psubb MM1, MM4; + psubb MM2, MM4; + psubb MM3, MM4; + movq [ESI -32], MM0; + movq [ESI+8 -32], MM1; + movq [ESI+16-32], MM2; + movq [ESI+24-32], MM3; + cmp ESI, EDI; + jb startsubmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + // trying to be fair and treat normal 32-bit cpu the same way as we do the SIMD units, with unrolled asm. There's not enough registers, really. + else + if (a.length >= 4) + { + auto n = aptr + (a.length & ~3); + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov CL, value; + + align 4; + startsub386: + add ESI, 4; + mov DX, [EAX]; + mov BX, [EAX+2]; + add EAX, 4; + sub BL, CL; + sub BH, CL; + sub DL, CL; + sub DH, CL; + mov [ESI -4], DX; + mov [ESI+2 -4], BX; + cmp ESI, EDI; + jb startsub386; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ - value); + + return a; +} + +unittest +{ + printf("_arraySliceExpMinSliceAssign_g 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); + } + + a[] = c[]; + c[] = b[] - 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(b[i] - 6)) + { + printf("[%d]: %d != %d - 6\n", i, c[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = value - b[] + */ + +T[] _arrayExpSliceMinSliceAssign_a(T[] a, T[] b, T value) +{ + return _arrayExpSliceMinSliceAssign_g(a, b, value); +} + +T[] _arrayExpSliceMinSliceAssign_h(T[] a, T[] b, T value) +{ + return _arrayExpSliceMinSliceAssign_g(a, b, value); +} + +T[] _arrayExpSliceMinSliceAssign_g(T[] a, T[] b, T value) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arrayExpSliceMinSliceAssign_g()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 8748% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + uint l = cast(ubyte) value; + l |= (l << 8); + l |= (l << 16); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startsubrsse2u: + add ESI, 64; + movdqa XMM5, XMM4; + movdqa XMM6, XMM4; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + psubb XMM5, XMM0; + psubb XMM6, XMM1; + movdqu [ESI -64], XMM5; + movdqu [ESI+16-64], XMM6; + movdqa XMM5, XMM4; + movdqa XMM6, XMM4; + movdqu XMM2, [EAX+32]; + movdqu XMM3, [EAX+48]; + add EAX, 64; + psubb XMM5, XMM2; + psubb XMM6, XMM3; + movdqu [ESI+32-64], XMM5; + movdqu [ESI+48-64], XMM6; + cmp ESI, EDI; + jb startsubrsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startsubrsse2a: + add ESI, 64; + movdqa XMM5, XMM4; + movdqa XMM6, XMM4; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + psubb XMM5, XMM0; + psubb XMM6, XMM1; + movdqa [ESI -64], XMM5; + movdqa [ESI+16-64], XMM6; + movdqa XMM5, XMM4; + movdqa XMM6, XMM4; + movdqa XMM2, [EAX+32]; + movdqa XMM3, [EAX+48]; + add EAX, 64; + psubb XMM5, XMM2; + psubb XMM6, XMM3; + movdqa [ESI+32-64], XMM5; + movdqa [ESI+48-64], XMM6; + cmp ESI, EDI; + jb startsubrsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 7397% faster + if (mmx() && a.length >= 32) + { + auto n = aptr + (a.length & ~31); + + uint l = cast(ubyte) value; + l |= (l << 8); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd MM4, l; + pshufw MM4, MM4, 0; + + align 4; + startsubrmmx: + add ESI, 32; + movq MM5, MM4; + movq MM6, MM4; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + psubb MM5, MM0; + psubb MM6, MM1; + movq [ESI -32], MM5; + movq [ESI+8 -32], MM6; + movq MM5, MM4; + movq MM6, MM4; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + add EAX, 32; + psubb MM5, MM2; + psubb MM6, MM3; + movq [ESI+16-32], MM5; + movq [ESI+24-32], MM6; + cmp ESI, EDI; + jb startsubrmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + + } + + while (aptr < aend) + *aptr++ = cast(T)(value - *bptr++); + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinSliceAssign_g 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); + } + + a[] = c[]; + c[] = 6 - b[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(6 - b[i])) + { + printf("[%d]: %d != 6 - %d\n", i, c[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - c[] + */ + +T[] _arraySliceSliceMinSliceAssign_a(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMinSliceAssign_g(a, c, b); +} + +T[] _arraySliceSliceMinSliceAssign_h(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMinSliceAssign_g(a, c, b); +} + +T[] _arraySliceSliceMinSliceAssign_g(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 +{ + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 5756% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 8; + startsublsse2u: + add ESI, 64; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + movdqu XMM2, [EAX+32]; + movdqu XMM3, [EAX+48]; + add EAX, 64; + movdqu XMM4, [ECX]; + movdqu XMM5, [ECX+16]; + movdqu XMM6, [ECX+32]; + movdqu XMM7, [ECX+48]; + add ECX, 64; + psubb XMM0, XMM4; + psubb XMM1, XMM5; + psubb XMM2, XMM6; + psubb XMM3, XMM7; + movdqu [ESI -64], XMM0; + movdqu [ESI+16-64], XMM1; + movdqu [ESI+32-64], XMM2; + movdqu [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsublsse2u; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 8; + startsublsse2a: + add ESI, 64; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + movdqa XMM2, [EAX+32]; + movdqa XMM3, [EAX+48]; + add EAX, 64; + movdqa XMM4, [ECX]; + movdqa XMM5, [ECX+16]; + movdqa XMM6, [ECX+32]; + movdqa XMM7, [ECX+48]; + add ECX, 64; + psubb XMM0, XMM4; + psubb XMM1, XMM5; + psubb XMM2, XMM6; + psubb XMM3, XMM7; + movdqa [ESI -64], XMM0; + movdqa [ESI+16-64], XMM1; + movdqa [ESI+32-64], XMM2; + movdqa [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsublsse2a; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + else + // MMX version is 4428% faster + if (mmx() && a.length >= 32) + { + auto n = aptr + (a.length & ~31); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 8; + startsublmmx: + add ESI, 32; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + add EAX, 32; + movq MM4, [ECX]; + movq MM5, [ECX+8]; + movq MM6, [ECX+16]; + movq MM7, [ECX+24]; + add ECX, 32; + psubb MM0, MM4; + psubb MM1, MM5; + psubb MM2, MM6; + psubb MM3, MM7; + movq [ESI -32], MM0; + movq [ESI+8 -32], MM1; + movq [ESI+16-32], MM2; + movq [ESI+24-32], MM3; + cmp ESI, EDI; + jb startsublmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ - *cptr++); + + return a; +} + +unittest +{ + printf("_arraySliceSliceMinSliceAssign_g 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]: %d != %d - %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= value + */ + +T[] _arrayExpSliceMinass_a(T[] a, T value) +{ + return _arrayExpSliceMinass_g(a, value); +} + +T[] _arrayExpSliceMinass_h(T[] a, T value) +{ + return _arrayExpSliceMinass_g(a, value); +} + +T[] _arrayExpSliceMinass_g(T[] a, T value) +{ + //printf("_arrayExpSliceMinass_g(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1577% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + uint l = cast(ubyte) value; + l |= (l << 8); + l |= (l << 16); + + if (((cast(uint) aptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startsubasssse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + movdqu XMM2, [ESI+32]; + movdqu XMM3, [ESI+48]; + add ESI, 64; + psubb XMM0, XMM4; + psubb XMM1, XMM4; + psubb XMM2, XMM4; + psubb XMM3, XMM4; + movdqu [ESI -64], XMM0; + movdqu [ESI+16-64], XMM1; + movdqu [ESI+32-64], XMM2; + movdqu [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsubasssse2u; + + mov aptr, ESI; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 8; + startsubasssse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + movdqa XMM2, [ESI+32]; + movdqa XMM3, [ESI+48]; + add ESI, 64; + psubb XMM0, XMM4; + psubb XMM1, XMM4; + psubb XMM2, XMM4; + psubb XMM3, XMM4; + movdqa [ESI -64], XMM0; + movdqa [ESI+16-64], XMM1; + movdqa [ESI+32-64], XMM2; + movdqa [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsubasssse2a; + + mov aptr, ESI; + } + } + } + else + // MMX version is 1577% faster + if (mmx() && a.length >= 32) + { + + auto n = aptr + (a.length & ~31); + + uint l = cast(ubyte) value; + l |= (l << 8); + + asm + { + mov ESI, aptr; + mov EDI, n; + movd MM4, l; + pshufw MM4, MM4, 0; + + align 8; + startsubassmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + add ESI, 32; + psubb MM0, MM4; + psubb MM1, MM4; + psubb MM2, MM4; + psubb MM3, MM4; + movq [ESI -32], MM0; + movq [ESI+8 -32], MM1; + movq [ESI+16-32], MM2; + movq [ESI+24-32], MM3; + cmp ESI, EDI; + jb startsubassmmx; + + emms; + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ -= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinass_g 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); + } + + a[] = c[]; + c[] -= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %d != %d - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= b[] + */ + +T[] _arraySliceSliceMinass_a(T[] a, T[] b) +{ + return _arraySliceSliceMinass_g(a, b); +} + +T[] _arraySliceSliceMinass_h(T[] a, T[] b) +{ + return _arraySliceSliceMinass_g(a, b); +} + +T[] _arraySliceSliceMinass_g(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMinass_g()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 4800% faster + if (sse2() && a.length >= 64) + { + auto n = aptr + (a.length & ~63); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 8; + startsubasslsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + movdqu XMM2, [ESI+32]; + movdqu XMM3, [ESI+48]; + add ESI, 64; + movdqu XMM4, [ECX]; + movdqu XMM5, [ECX+16]; + movdqu XMM6, [ECX+32]; + movdqu XMM7, [ECX+48]; + add ECX, 64; + psubb XMM0, XMM4; + psubb XMM1, XMM5; + psubb XMM2, XMM6; + psubb XMM3, XMM7; + movdqu [ESI -64], XMM0; + movdqu [ESI+16-64], XMM1; + movdqu [ESI+32-64], XMM2; + movdqu [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsubasslsse2u; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 8; + startsubasslsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + movdqa XMM2, [ESI+32]; + movdqa XMM3, [ESI+48]; + add ESI, 64; + movdqa XMM4, [ECX]; + movdqa XMM5, [ECX+16]; + movdqa XMM6, [ECX+32]; + movdqa XMM7, [ECX+48]; + add ECX, 64; + psubb XMM0, XMM4; + psubb XMM1, XMM5; + psubb XMM2, XMM6; + psubb XMM3, XMM7; + movdqa [ESI -64], XMM0; + movdqa [ESI+16-64], XMM1; + movdqa [ESI+32-64], XMM2; + movdqa [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsubasslsse2a; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + else + // MMX version is 3107% faster + if (mmx() && a.length >= 32) + { + + auto n = aptr + (a.length & ~31); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 8; + startsubasslmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + add ESI, 32; + movq MM4, [ECX]; + movq MM5, [ECX+8]; + movq MM6, [ECX+16]; + movq MM7, [ECX+24]; + add ECX, 32; + psubb MM0, MM4; + psubb MM1, MM5; + psubb MM2, MM6; + psubb MM3, MM7; + movq [ESI -32], MM0; + movq [ESI+8 -32], MM1; + movq [ESI+16-32], MM2; + movq [ESI+24-32], MM3; + cmp ESI, EDI; + jb startsubasslmmx; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ -= *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMinass_g 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); + } + + a[] = c[]; + c[] -= b[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - b[i])) + { + printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} diff --git a/src/compiler/dmd/arraycast.d b/src/compiler/dmd/arraycast.d new file mode 100644 index 0000000..c58c49a --- /dev/null +++ b/src/compiler/dmd/arraycast.d @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +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); + } +} + +} diff --git a/src/compiler/dmd/arraycat.d b/src/compiler/dmd/arraycat.d new file mode 100644 index 0000000..f68c72b --- /dev/null +++ b/src/compiler/dmd/arraycat.d @@ -0,0 +1,61 @@ +/** + * Part of the D programming language runtime library. + */ + +/* + * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.arraycat; + +private +{ + import stdc.string; + debug import 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; +} diff --git a/src/compiler/dmd/arraydouble.d b/src/compiler/dmd/arraydouble.d new file mode 100644 index 0000000..c7c7504 --- /dev/null +++ b/src/compiler/dmd/arraydouble.d @@ -0,0 +1,1714 @@ +/*************************** + * D programming language http://www.digitalmars.com/d/ + * Runtime support for double array operations. + * Based on code originally written by Burton Radons. + * Placed in public domain. + */ + +module rt.arraydouble; + +private import util.cpuid; + +version (Unittest) +{ + /* This is so unit tests will test every CPU variant + */ + int cpuid; + const int CPUID_MAX = 5; + bool mmx() { return cpuid == 1 && util.cpuid.mmx(); } + bool sse() { return cpuid == 2 && util.cpuid.sse(); } + bool sse2() { return cpuid == 3 && util.cpuid.sse2(); } + bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); } +} +else +{ + alias util.cpuid.mmx mmx; + alias util.cpuid.sse sse; + alias util.cpuid.sse2 sse2; + alias 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); +} + +/* Performance figures measured by Burton Radons + */ + +alias double T; + +extern (C): + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + c[] + */ + +T[] _arraySliceSliceAddSliceAssign_d(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 +{ + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 333% faster + if (sse2() && b.length >= 16) + { + auto n = aptr + (b.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; // left operand + mov ECX, cptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movupd XMM0, [EAX]; + movupd XMM1, [EAX+16]; + movupd XMM2, [EAX+32]; + movupd XMM3, [EAX+48]; + add EAX, 64; + movupd XMM4, [ECX]; + movupd XMM5, [ECX+16]; + movupd XMM6, [ECX+32]; + movupd XMM7, [ECX+48]; + add ESI, 64; + addpd XMM0, XMM4; + addpd XMM1, XMM5; + addpd XMM2, XMM6; + addpd XMM3, XMM7; + add ECX, 64; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + // Handle remainder + while (aptr < aend) + *aptr++ = *bptr++ + *cptr++; + + return a; +} + + +unittest +{ + printf("_arraySliceSliceAddSliceAssign_d 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]: %g != %g + %g\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - c[] + */ + +T[] _arraySliceSliceMinSliceAssign_d(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 +{ + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 324% faster + if (sse2() && b.length >= 8) + { + auto n = aptr + (b.length & ~7); + + // Unaligned case + asm + { + mov EAX, bptr; // left operand + mov ECX, cptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movupd XMM0, [EAX]; + movupd XMM1, [EAX+16]; + movupd XMM2, [EAX+32]; + movupd XMM3, [EAX+48]; + add EAX, 64; + movupd XMM4, [ECX]; + movupd XMM5, [ECX+16]; + movupd XMM6, [ECX+32]; + movupd XMM7, [ECX+48]; + add ESI, 64; + subpd XMM0, XMM4; + subpd XMM1, XMM5; + subpd XMM2, XMM6; + subpd XMM3, XMM7; + add ECX, 64; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + // Handle remainder + while (aptr < aend) + *aptr++ = *bptr++ - *cptr++; + + return a; +} + + +unittest +{ + printf("_arraySliceSliceMinSliceAssign_d 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]: %g != %g - %g\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + value + */ + +T[] _arraySliceExpAddSliceAssign_d(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpAddSliceAssign_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 305% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movsd XMM4, value; + shufpd XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movupd XMM0, [EAX]; + movupd XMM1, [EAX+16]; + movupd XMM2, [EAX+32]; + movupd XMM3, [EAX+48]; + add EAX, 64; + addpd XMM0, XMM4; + addpd XMM1, XMM4; + addpd XMM2, XMM4; + addpd XMM3, XMM4; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ + value; + + return a; +} + +unittest +{ + printf("_arraySliceExpAddSliceAssign_d 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[] + 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + 6)) + { + printf("[%d]: %g != %g + 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += value + */ + +T[] _arrayExpSliceAddass_d(T[] a, T value) +{ + //printf("_arrayExpSliceAddass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 version is 114% faster + if (sse2() && a.length >= 8) + { + auto n = cast(T*)((cast(uint)aend) & ~7); + if (aptr < n) + + // Unaligned case + asm + { + mov ESI, aptr; + mov EDI, n; + movsd XMM4, value; + shufpd XMM4, XMM4, 0; + + align 8; + startsseloopa: + movupd XMM0, [ESI]; + movupd XMM1, [ESI+16]; + movupd XMM2, [ESI+32]; + movupd XMM3, [ESI+48]; + add ESI, 64; + addpd XMM0, XMM4; + addpd XMM1, XMM4; + addpd XMM2, XMM4; + addpd XMM3, XMM4; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopa; + + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ += value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceAddass_d 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); + } + + a[] = c[]; + c[] += 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + 6)) + { + printf("[%d]: %g != %g + 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += b[] + */ + +T[] _arraySliceSliceAddass_d(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceAddass_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 183% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov ECX, bptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movupd XMM0, [ESI]; + movupd XMM1, [ESI+16]; + movupd XMM2, [ESI+32]; + movupd XMM3, [ESI+48]; + add ESI, 64; + movupd XMM4, [ECX]; + movupd XMM5, [ECX+16]; + movupd XMM6, [ECX+32]; + movupd XMM7, [ECX+48]; + add ECX, 64; + addpd XMM0, XMM4; + addpd XMM1, XMM5; + addpd XMM2, XMM6; + addpd XMM3, XMM7; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ += *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceAddass_d 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); + } + + a[] = c[]; + c[] += b[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + b[i])) + { + printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - value + */ + +T[] _arraySliceExpMinSliceAssign_d(T[] a, T value, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMinSliceAssign_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 305% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movsd XMM4, value; + shufpd XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movupd XMM0, [EAX]; + movupd XMM1, [EAX+16]; + movupd XMM2, [EAX+32]; + movupd XMM3, [EAX+48]; + add EAX, 64; + subpd XMM0, XMM4; + subpd XMM1, XMM4; + subpd XMM2, XMM4; + subpd XMM3, XMM4; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ - value; + + return a; +} + +unittest +{ + printf("_arraySliceExpMinSliceAssign_d 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[] - 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = value - b[] + */ + +T[] _arrayExpSliceMinSliceAssign_d(T[] a, T[] b, T value) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arrayExpSliceMinSliceAssign_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 66% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movsd XMM4, value; + shufpd XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movapd XMM5, XMM4; + movapd XMM6, XMM4; + movupd XMM0, [EAX]; + movupd XMM1, [EAX+16]; + movupd XMM2, [EAX+32]; + movupd XMM3, [EAX+48]; + add EAX, 64; + subpd XMM5, XMM0; + subpd XMM6, XMM1; + movupd [ESI+ 0-64], XMM5; + movupd [ESI+16-64], XMM6; + movapd XMM5, XMM4; + movapd XMM6, XMM4; + subpd XMM5, XMM2; + subpd XMM6, XMM3; + movupd [ESI+32-64], XMM5; + movupd [ESI+48-64], XMM6; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = value - *bptr++; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinSliceAssign_d 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[] = 6 - a[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(6 - a[i])) + { + printf("[%d]: %g != 6 - %g\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= value + */ + +T[] _arrayExpSliceMinass_d(T[] a, T value) +{ + //printf("_arrayExpSliceMinass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 version is 115% faster + if (sse2() && a.length >= 8) + { + auto n = cast(T*)((cast(uint)aend) & ~7); + if (aptr < n) + + // Unaligned case + asm + { + mov ESI, aptr; + mov EDI, n; + movsd XMM4, value; + shufpd XMM4, XMM4, 0; + + align 8; + startsseloopa: + movupd XMM0, [ESI]; + movupd XMM1, [ESI+16]; + movupd XMM2, [ESI+32]; + movupd XMM3, [ESI+48]; + add ESI, 64; + subpd XMM0, XMM4; + subpd XMM1, XMM4; + subpd XMM2, XMM4; + subpd XMM3, XMM4; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopa; + + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ -= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinass_d 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); + } + + a[] = c[]; + c[] -= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= b[] + */ + +T[] _arraySliceSliceMinass_d(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMinass_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 183% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov ECX, bptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movupd XMM0, [ESI]; + movupd XMM1, [ESI+16]; + movupd XMM2, [ESI+32]; + movupd XMM3, [ESI+48]; + add ESI, 64; + movupd XMM4, [ECX]; + movupd XMM5, [ECX+16]; + movupd XMM6, [ECX+32]; + movupd XMM7, [ECX+48]; + add ECX, 64; + subpd XMM0, XMM4; + subpd XMM1, XMM5; + subpd XMM2, XMM6; + subpd XMM3, XMM7; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ -= *bptr++; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinass_d 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); + } + + a[] = c[]; + c[] -= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] * value + */ + +T[] _arraySliceExpMulSliceAssign_d(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMulSliceAssign_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 304% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movsd XMM4, value; + shufpd XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movupd XMM0, [EAX]; + movupd XMM1, [EAX+16]; + movupd XMM2, [EAX+32]; + movupd XMM3, [EAX+48]; + add EAX, 64; + mulpd XMM0, XMM4; + mulpd XMM1, XMM4; + mulpd XMM2, XMM4; + mulpd XMM3, XMM4; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ * value; + + return a; +} + +unittest +{ + printf("_arraySliceExpMulSliceAssign_d 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[] * 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] * 6)) + { + printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] * c[] + */ + +T[] _arraySliceSliceMulSliceAssign_d(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 +{ + //printf("_arraySliceSliceMulSliceAssign_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 329% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov EAX, bptr; // left operand + mov ECX, cptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movupd XMM0, [EAX]; + movupd XMM1, [EAX+16]; + movupd XMM2, [EAX+32]; + movupd XMM3, [EAX+48]; + add ESI, 64; + movupd XMM4, [ECX]; + movupd XMM5, [ECX+16]; + movupd XMM6, [ECX+32]; + movupd XMM7, [ECX+48]; + add EAX, 64; + mulpd XMM0, XMM4; + mulpd XMM1, XMM5; + mulpd XMM2, XMM6; + mulpd XMM3, XMM7; + add ECX, 64; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ * *cptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMulSliceAssign_d 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]: %g != %g * %g\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] *= value + */ + +T[] _arrayExpSliceMulass_d(T[] a, T value) +{ + //printf("_arrayExpSliceMulass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 version is 109% faster + if (sse2() && a.length >= 8) + { + auto n = cast(T*)((cast(uint)aend) & ~7); + if (aptr < n) + + // Unaligned case + asm + { + mov ESI, aptr; + mov EDI, n; + movsd XMM4, value; + shufpd XMM4, XMM4, 0; + + align 8; + startsseloopa: + movupd XMM0, [ESI]; + movupd XMM1, [ESI+16]; + movupd XMM2, [ESI+32]; + movupd XMM3, [ESI+48]; + add ESI, 64; + mulpd XMM0, XMM4; + mulpd XMM1, XMM4; + mulpd XMM2, XMM4; + mulpd XMM3, XMM4; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopa; + + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ *= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMulass_d 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); + } + + a[] = c[]; + c[] *= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] * 6)) + { + printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] *= b[] + */ + +T[] _arraySliceSliceMulass_d(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMulass_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 version is 205% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov ECX, bptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movupd XMM0, [ESI]; + movupd XMM1, [ESI+16]; + movupd XMM2, [ESI+32]; + movupd XMM3, [ESI+48]; + add ESI, 64; + movupd XMM4, [ECX]; + movupd XMM5, [ECX+16]; + movupd XMM6, [ECX+32]; + movupd XMM7, [ECX+48]; + add ECX, 64; + mulpd XMM0, XMM4; + mulpd XMM1, XMM5; + mulpd XMM2, XMM6; + mulpd XMM3, XMM7; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ *= *bptr++; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMulass_d 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); + } + + a[] = c[]; + c[] *= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] * 6)) + { + printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] / value + */ + +T[] _arraySliceExpDivSliceAssign_d(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpDivSliceAssign_d()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + /* Multiplying by the reciprocal is faster, but does + * not produce as accurate an answer. + */ + T recip = cast(T)1 / value; + + version (D_InlineAsm_X86) + { + // SSE2 version is 299% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movsd XMM4, recip; + //movsd XMM4, value + //rcpsd XMM4, XMM4 + shufpd XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movupd XMM0, [EAX]; + movupd XMM1, [EAX+16]; + movupd XMM2, [EAX+32]; + movupd XMM3, [EAX+48]; + add EAX, 64; + mulpd XMM0, XMM4; + mulpd XMM1, XMM4; + mulpd XMM2, XMM4; + mulpd XMM3, XMM4; + //divpd XMM0, XMM4; + //divpd XMM1, XMM4; + //divpd XMM2, XMM4; + //divpd XMM3, XMM4; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + { + *aptr++ = *bptr++ / value; + //*aptr++ = *bptr++ * recip; + } + + return a; +} + +unittest +{ + printf("_arraySliceExpDivSliceAssign_d 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[] / 8; + + for (int i = 0; i < dim; i++) + { + //printf("[%d]: %g ?= %g / 8\n", i, c[i], a[i]); + if (c[i] != cast(T)(a[i] / 8)) + { + printf("[%d]: %g != %g / 8\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] /= value + */ + +T[] _arrayExpSliceDivass_d(T[] a, T value) +{ + //printf("_arrayExpSliceDivass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + /* Multiplying by the reciprocal is faster, but does + * not produce as accurate an answer. + */ + T recip = cast(T)1 / value; + + version (D_InlineAsm_X86) + { + // SSE2 version is 65% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + // Unaligned case + asm + { + mov ESI, aptr; + mov EDI, n; + movsd XMM4, recip; + //movsd XMM4, value + //rcpsd XMM4, XMM4 + shufpd XMM4, XMM4, 0; + + align 8; + startsseloopa: + movupd XMM0, [ESI]; + movupd XMM1, [ESI+16]; + movupd XMM2, [ESI+32]; + movupd XMM3, [ESI+48]; + add ESI, 64; + mulpd XMM0, XMM4; + mulpd XMM1, XMM4; + mulpd XMM2, XMM4; + mulpd XMM3, XMM4; + //divpd XMM0, XMM4; + //divpd XMM1, XMM4; + //divpd XMM2, XMM4; + //divpd XMM3, XMM4; + movupd [ESI+ 0-64], XMM0; + movupd [ESI+16-64], XMM1; + movupd [ESI+32-64], XMM2; + movupd [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopa; + + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ *= recip; + + return a; +} + + +unittest +{ + printf("_arrayExpSliceDivass_d 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); + } + + a[] = c[]; + c[] /= 8; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] / 8)) + { + printf("[%d]: %g != %g / 8\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= b[] * value + */ + +T[] _arraySliceExpMulSliceMinass_d(T[] a, T value, T[] b) +{ + return _arraySliceExpMulSliceAddass_d(a, -value, b); +} + +/*********************** + * Computes: + * a[] += b[] * value + */ + +T[] _arraySliceExpMulSliceAddass_d(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_d 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]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]); + if (c[i] != cast(T)(b[i] + a[i] * 6)) + { + printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]); + assert(0); + } + } + } + } +} diff --git a/src/compiler/dmd/arrayfloat.d b/src/compiler/dmd/arrayfloat.d new file mode 100644 index 0000000..f5588e8 --- /dev/null +++ b/src/compiler/dmd/arrayfloat.d @@ -0,0 +1,2303 @@ +/*************************** + * D programming language http://www.digitalmars.com/d/ + * Runtime support for float array operations. + * Based on code originally written by Burton Radons. + * Placed in public domain. + */ + +module rt.arrayfloat; + +private import util.cpuid; + +version (Unittest) +{ + /* This is so unit tests will test every CPU variant + */ + int cpuid; + const int CPUID_MAX = 5; + bool mmx() { return cpuid == 1 && util.cpuid.mmx(); } + bool sse() { return cpuid == 2 && util.cpuid.sse(); } + bool sse2() { return cpuid == 3 && util.cpuid.sse2(); } + bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); } +} +else +{ + alias util.cpuid.mmx mmx; + alias util.cpuid.sse sse; + alias util.cpuid.sse2 sse2; + alias 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 float T; + +extern (C): + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + c[] + */ + +T[] _arraySliceSliceAddSliceAssign_f(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 +{ + //printf("_arraySliceSliceAddSliceAssign_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 834% faster + if (sse() && b.length >= 16) + { + version (log) printf("\tsse unaligned\n"); + auto n = aptr + (b.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; // left operand + mov ECX, cptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movups XMM0, [EAX]; + movups XMM1, [EAX+16]; + movups XMM2, [EAX+32]; + movups XMM3, [EAX+48]; + add EAX, 64; + movups XMM4, [ECX]; + movups XMM5, [ECX+16]; + movups XMM6, [ECX+32]; + movups XMM7, [ECX+48]; + add ESI, 64; + addps XMM0, XMM4; + addps XMM1, XMM5; + addps XMM2, XMM6; + addps XMM3, XMM7; + add ECX, 64; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + // 3DNow! version is only 13% faster + if (amd3dnow() && b.length >= 8) + { + version (log) printf("\tamd3dnow\n"); + auto n = aptr + (b.length & ~7); + + asm + { + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + mov EAX, bptr; // left operand + mov ECX, cptr; // right operand + + align 4; + start3dnow: + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + pfadd MM0, [ECX]; + pfadd MM1, [ECX+8]; + pfadd MM2, [ECX+16]; + pfadd MM3, [ECX+24]; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ECX, 32; + add ESI, 32; + add EAX, 32; + cmp ESI, EDI; + jb start3dnow; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + // Handle remainder + version (log) if (aptr < aend) printf("\tbase\n"); + while (aptr < aend) + *aptr++ = *bptr++ + *cptr++; + + return a; +} + + +unittest +{ + printf("_arraySliceSliceAddSliceAssign_f 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]: %g != %g + %g\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - c[] + */ + +T[] _arraySliceSliceMinSliceAssign_f(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 +{ + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 834% faster + if (sse() && b.length >= 16) + { + auto n = aptr + (b.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; // left operand + mov ECX, cptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movups XMM0, [EAX]; + movups XMM1, [EAX+16]; + movups XMM2, [EAX+32]; + movups XMM3, [EAX+48]; + add EAX, 64; + movups XMM4, [ECX]; + movups XMM5, [ECX+16]; + movups XMM6, [ECX+32]; + movups XMM7, [ECX+48]; + add ESI, 64; + subps XMM0, XMM4; + subps XMM1, XMM5; + subps XMM2, XMM6; + subps XMM3, XMM7; + add ECX, 64; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + // 3DNow! version is only 13% faster + if (amd3dnow() && b.length >= 8) + { + auto n = aptr + (b.length & ~7); + + asm + { + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + mov EAX, bptr; // left operand + mov ECX, cptr; // right operand + + align 4; + start3dnow: + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + pfsub MM0, [ECX]; + pfsub MM1, [ECX+8]; + pfsub MM2, [ECX+16]; + pfsub MM3, [ECX+24]; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ECX, 32; + add ESI, 32; + add EAX, 32; + cmp ESI, EDI; + jb start3dnow; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + // Handle remainder + while (aptr < aend) + *aptr++ = *bptr++ - *cptr++; + + return a; +} + + +unittest +{ + printf("_arraySliceSliceMinSliceAssign_f 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]: %g != %gd - %g\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + value + */ + +T[] _arraySliceExpAddSliceAssign_f(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpAddSliceAssign_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 665% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movss XMM4, value; + shufps XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movups XMM0, [EAX]; + movups XMM1, [EAX+16]; + movups XMM2, [EAX+32]; + movups XMM3, [EAX+48]; + add EAX, 64; + addps XMM0, XMM4; + addps XMM1, XMM4; + addps XMM2, XMM4; + addps XMM3, XMM4; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + // 3DNow! version is 69% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + ulong w = *cast(uint *) &value; + ulong v = w | (w << 32L); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movq MM4, qword ptr [v]; + + align 8; + start3dnow: + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + pfadd MM0, MM4; + pfadd MM1, MM4; + pfadd MM2, MM4; + pfadd MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + add EAX, 32; + cmp ESI, EDI; + jb start3dnow; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ + value; + + return a; +} + +unittest +{ + printf("_arraySliceExpAddSliceAssign_f 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[] + 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + 6)) + { + printf("[%d]: %g != %g + 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += value + */ + +T[] _arrayExpSliceAddass_f(T[] a, T value) +{ + //printf("_arrayExpSliceAddass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE version is 302% faster + if (sse() && a.length >= 16) + { + // align pointer + auto n = cast(T*)((cast(uint)aptr + 15) & ~15); + while (aptr < n) + *aptr++ += value; + n = cast(T*)((cast(uint)aend) & ~15); + if (aptr < n) + + // Aligned case + asm + { + mov ESI, aptr; + mov EDI, n; + movss XMM4, value; + shufps XMM4, XMM4, 0; + + align 8; + startsseloopa: + movaps XMM0, [ESI]; + movaps XMM1, [ESI+16]; + movaps XMM2, [ESI+32]; + movaps XMM3, [ESI+48]; + add ESI, 64; + addps XMM0, XMM4; + addps XMM1, XMM4; + addps XMM2, XMM4; + addps XMM3, XMM4; + movaps [ESI+ 0-64], XMM0; + movaps [ESI+16-64], XMM1; + movaps [ESI+32-64], XMM2; + movaps [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopa; + + mov aptr, ESI; + } + } + else + // 3DNow! version is 63% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + ulong w = *cast(uint *) &value; + ulong v = w | (w << 32L); + + asm + { + mov ESI, dword ptr [aptr]; + mov EDI, dword ptr [n]; + movq MM4, qword ptr [v]; + + align 8; + start3dnow: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + pfadd MM0, MM4; + pfadd MM1, MM4; + pfadd MM2, MM4; + pfadd MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + cmp ESI, EDI; + jb start3dnow; + + emms; + mov dword ptr [aptr], ESI; + } + } + } + + while (aptr < aend) + *aptr++ += value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceAddass_f 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); + } + + a[] = c[]; + c[] += 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + 6)) + { + printf("[%d]: %g != %g + 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += b[] + */ + +T[] _arraySliceSliceAddass_f(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceAddass_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 468% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov ECX, bptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movups XMM0, [ESI]; + movups XMM1, [ESI+16]; + movups XMM2, [ESI+32]; + movups XMM3, [ESI+48]; + add ESI, 64; + movups XMM4, [ECX]; + movups XMM5, [ECX+16]; + movups XMM6, [ECX+32]; + movups XMM7, [ECX+48]; + add ECX, 64; + addps XMM0, XMM4; + addps XMM1, XMM5; + addps XMM2, XMM6; + addps XMM3, XMM7; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + // 3DNow! version is 57% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, dword ptr [aptr]; // destination operand + mov EDI, dword ptr [n]; // end comparison + mov ECX, dword ptr [bptr]; // right operand + + align 4; + start3dnow: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + pfadd MM0, [ECX]; + pfadd MM1, [ECX+8]; + pfadd MM2, [ECX+16]; + pfadd MM3, [ECX+24]; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + add ECX, 32; + cmp ESI, EDI; + jb start3dnow; + + emms; + mov dword ptr [aptr], ESI; + mov dword ptr [bptr], ECX; + } + } + } + + while (aptr < aend) + *aptr++ += *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceAddass_f 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); + } + + a[] = c[]; + c[] += b[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + b[i])) + { + printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - value + */ + +T[] _arraySliceExpMinSliceAssign_f(T[] a, T value, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMinSliceAssign_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 622% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movss XMM4, value; + shufps XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movups XMM0, [EAX]; + movups XMM1, [EAX+16]; + movups XMM2, [EAX+32]; + movups XMM3, [EAX+48]; + add EAX, 64; + subps XMM0, XMM4; + subps XMM1, XMM4; + subps XMM2, XMM4; + subps XMM3, XMM4; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + // 3DNow! version is 67% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + T[2] w; + + w[0] = w[1] = value; + + asm + { + mov ESI, dword ptr [aptr]; + mov EDI, dword ptr [n]; + mov EAX, dword ptr [bptr]; + movq MM4, qword ptr [w]; + + align 8; + start3dnow: + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + pfsub MM0, MM4; + pfsub MM1, MM4; + pfsub MM2, MM4; + pfsub MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + add EAX, 32; + cmp ESI, EDI; + jb start3dnow; + + emms; + mov dword ptr [aptr], ESI; + mov dword ptr [bptr], EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ - value; + + return a; +} + +unittest +{ + printf("_arraySliceExpMinSliceAssign_f 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[] - 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = value - b[] + */ + +T[] _arrayExpSliceMinSliceAssign_f(T[] a, T[] b, T value) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arrayExpSliceMinSliceAssign_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 690% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movss XMM4, value; + shufps XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movaps XMM5, XMM4; + movaps XMM6, XMM4; + movups XMM0, [EAX]; + movups XMM1, [EAX+16]; + movups XMM2, [EAX+32]; + movups XMM3, [EAX+48]; + add EAX, 64; + subps XMM5, XMM0; + subps XMM6, XMM1; + movups [ESI+ 0-64], XMM5; + movups [ESI+16-64], XMM6; + movaps XMM5, XMM4; + movaps XMM6, XMM4; + subps XMM5, XMM2; + subps XMM6, XMM3; + movups [ESI+32-64], XMM5; + movups [ESI+48-64], XMM6; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + // 3DNow! version is 67% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + ulong w = *cast(uint *) &value; + ulong v = w | (w << 32L); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movq MM4, qword ptr [v]; + + align 8; + start3dnow: + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + pfsubr MM0, MM4; + pfsubr MM1, MM4; + pfsubr MM2, MM4; + pfsubr MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + add EAX, 32; + cmp ESI, EDI; + jb start3dnow; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = value - *bptr++; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinSliceAssign_f 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[] = 6 - a[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(6 - a[i])) + { + printf("[%d]: %g != 6 - %g\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= value + */ + +T[] _arrayExpSliceMinass_f(T[] a, T value) +{ + //printf("_arrayExpSliceMinass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE version is 304% faster + if (sse() && a.length >= 16) + { + // align pointer + auto n = cast(T*)((cast(uint)aptr + 15) & ~15); + while (aptr < n) + *aptr++ -= value; + n = cast(T*)((cast(uint)aend) & ~15); + if (aptr < n) + + // Aligned case + asm + { + mov ESI, aptr; + mov EDI, n; + movss XMM4, value; + shufps XMM4, XMM4, 0; + + align 8; + startsseloopa: + movaps XMM0, [ESI]; + movaps XMM1, [ESI+16]; + movaps XMM2, [ESI+32]; + movaps XMM3, [ESI+48]; + add ESI, 64; + subps XMM0, XMM4; + subps XMM1, XMM4; + subps XMM2, XMM4; + subps XMM3, XMM4; + movaps [ESI+ 0-64], XMM0; + movaps [ESI+16-64], XMM1; + movaps [ESI+32-64], XMM2; + movaps [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopa; + + mov aptr, ESI; + } + } + else + // 3DNow! version is 63% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + ulong w = *cast(uint *) &value; + ulong v = w | (w << 32L); + + asm + { + mov ESI, dword ptr [aptr]; + mov EDI, dword ptr [n]; + movq MM4, qword ptr [v]; + + align 8; + start: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + pfsub MM0, MM4; + pfsub MM1, MM4; + pfsub MM2, MM4; + pfsub MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + cmp ESI, EDI; + jb start; + + emms; + mov dword ptr [aptr], ESI; + } + } + } + + while (aptr < aend) + *aptr++ -= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceminass_f 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); + } + + a[] = c[]; + c[] -= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= b[] + */ + +T[] _arraySliceSliceMinass_f(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMinass_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 468% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov ECX, bptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movups XMM0, [ESI]; + movups XMM1, [ESI+16]; + movups XMM2, [ESI+32]; + movups XMM3, [ESI+48]; + add ESI, 64; + movups XMM4, [ECX]; + movups XMM5, [ECX+16]; + movups XMM6, [ECX+32]; + movups XMM7, [ECX+48]; + add ECX, 64; + subps XMM0, XMM4; + subps XMM1, XMM5; + subps XMM2, XMM6; + subps XMM3, XMM7; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + // 3DNow! version is 57% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, dword ptr [aptr]; // destination operand + mov EDI, dword ptr [n]; // end comparison + mov ECX, dword ptr [bptr]; // right operand + + align 4; + start: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + pfsub MM0, [ECX]; + pfsub MM1, [ECX+8]; + pfsub MM2, [ECX+16]; + pfsub MM3, [ECX+24]; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + add ECX, 32; + cmp ESI, EDI; + jb start; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ -= *bptr++; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinass_f 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); + } + + a[] = c[]; + c[] -= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] * value + */ + +T[] _arraySliceExpMulSliceAssign_f(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMulSliceAssign_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 607% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movss XMM4, value; + shufps XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movups XMM0, [EAX]; + movups XMM1, [EAX+16]; + movups XMM2, [EAX+32]; + movups XMM3, [EAX+48]; + add EAX, 64; + mulps XMM0, XMM4; + mulps XMM1, XMM4; + mulps XMM2, XMM4; + mulps XMM3, XMM4; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + // 3DNow! version is 69% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + ulong w = *cast(uint *) &value; + ulong v = w | (w << 32L); + + asm + { + mov ESI, dword ptr [aptr]; + mov EDI, dword ptr [n]; + mov EAX, dword ptr [bptr]; + movq MM4, qword ptr [v]; + + align 8; + start: + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + pfmul MM0, MM4; + pfmul MM1, MM4; + pfmul MM2, MM4; + pfmul MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + add EAX, 32; + cmp ESI, EDI; + jb start; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ * value; + + return a; +} + +unittest +{ + printf("_arraySliceExpMulSliceAssign_f 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[] * 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] * 6)) + { + printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] * c[] + */ + +T[] _arraySliceSliceMulSliceAssign_f(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 +{ + //printf("_arraySliceSliceMulSliceAssign_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 833% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; // left operand + mov ECX, cptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movups XMM0, [EAX]; + movups XMM1, [EAX+16]; + movups XMM2, [EAX+32]; + movups XMM3, [EAX+48]; + add ESI, 64; + movups XMM4, [ECX]; + movups XMM5, [ECX+16]; + movups XMM6, [ECX+32]; + movups XMM7, [ECX+48]; + add EAX, 64; + mulps XMM0, XMM4; + mulps XMM1, XMM5; + mulps XMM2, XMM6; + mulps XMM3, XMM7; + add ECX, 64; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + // 3DNow! version is only 13% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, dword ptr [aptr]; // destination operand + mov EDI, dword ptr [n]; // end comparison + mov EAX, dword ptr [bptr]; // left operand + mov ECX, dword ptr [cptr]; // right operand + + align 4; + start: + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + pfmul MM0, [ECX]; + pfmul MM1, [ECX+8]; + pfmul MM2, [ECX+16]; + pfmul MM3, [ECX+24]; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ECX, 32; + add ESI, 32; + add EAX, 32; + cmp ESI, EDI; + jb start; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ * *cptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMulSliceAssign_f 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]: %g != %g * %g\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] *= value + */ + +T[] _arrayExpSliceMulass_f(T[] a, T value) +{ + //printf("_arrayExpSliceMulass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE version is 303% faster + if (sse() && a.length >= 16) + { + // align pointer + auto n = cast(T*)((cast(uint)aptr + 15) & ~15); + while (aptr < n) + *aptr++ *= value; + n = cast(T*)((cast(uint)aend) & ~15); + if (aptr < n) + + // Aligned case + asm + { + mov ESI, aptr; + mov EDI, n; + movss XMM4, value; + shufps XMM4, XMM4, 0; + + align 8; + startsseloopa: + movaps XMM0, [ESI]; + movaps XMM1, [ESI+16]; + movaps XMM2, [ESI+32]; + movaps XMM3, [ESI+48]; + add ESI, 64; + mulps XMM0, XMM4; + mulps XMM1, XMM4; + mulps XMM2, XMM4; + mulps XMM3, XMM4; + movaps [ESI+ 0-64], XMM0; + movaps [ESI+16-64], XMM1; + movaps [ESI+32-64], XMM2; + movaps [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopa; + + mov aptr, ESI; + } + } + else + // 3DNow! version is 63% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + ulong w = *cast(uint *) &value; + ulong v = w | (w << 32L); + + asm + { + mov ESI, dword ptr [aptr]; + mov EDI, dword ptr [n]; + movq MM4, qword ptr [v]; + + align 8; + start: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + pfmul MM0, MM4; + pfmul MM1, MM4; + pfmul MM2, MM4; + pfmul MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + cmp ESI, EDI; + jb start; + + emms; + mov dword ptr [aptr], ESI; + } + } + } + + while (aptr < aend) + *aptr++ *= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMulass_f 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); + } + + a[] = c[]; + c[] *= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] * 6)) + { + printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] *= b[] + */ + +T[] _arraySliceSliceMulass_f(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMulass_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE version is 525% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov ECX, bptr; // right operand + mov ESI, aptr; // destination operand + mov EDI, n; // end comparison + + align 8; + startsseloopb: + movups XMM0, [ESI]; + movups XMM1, [ESI+16]; + movups XMM2, [ESI+32]; + movups XMM3, [ESI+48]; + add ESI, 64; + movups XMM4, [ECX]; + movups XMM5, [ECX+16]; + movups XMM6, [ECX+32]; + movups XMM7, [ECX+48]; + add ECX, 64; + mulps XMM0, XMM4; + mulps XMM1, XMM5; + mulps XMM2, XMM6; + mulps XMM3, XMM7; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopb; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + // 3DNow! version is 57% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, dword ptr [aptr]; // destination operand + mov EDI, dword ptr [n]; // end comparison + mov ECX, dword ptr [bptr]; // right operand + + align 4; + start: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + pfmul MM0, [ECX]; + pfmul MM1, [ECX+8]; + pfmul MM2, [ECX+16]; + pfmul MM3, [ECX+24]; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + add ECX, 32; + cmp ESI, EDI; + jb start; + + emms; + mov dword ptr [aptr], ESI; + mov dword ptr [bptr], ECX; + } + } + } + + while (aptr < aend) + *aptr++ *= *bptr++; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMulass_f 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); + } + + a[] = c[]; + c[] *= 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] * 6)) + { + printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] / value + */ + +T[] _arraySliceExpDivSliceAssign_f(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpDivSliceAssign_f()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + /* Multiplying by the reciprocal is faster, but does + * not produce as accurate an answer. + */ + T recip = cast(T)1 / value; + + version (D_InlineAsm_X86) + { + // SSE version is 587% faster + if (sse() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + // Unaligned case + asm + { + mov EAX, bptr; + mov ESI, aptr; + mov EDI, n; + movss XMM4, recip; + //movss XMM4, value + //rcpss XMM4, XMM4 + shufps XMM4, XMM4, 0; + + align 8; + startsseloop: + add ESI, 64; + movups XMM0, [EAX]; + movups XMM1, [EAX+16]; + movups XMM2, [EAX+32]; + movups XMM3, [EAX+48]; + add EAX, 64; + mulps XMM0, XMM4; + mulps XMM1, XMM4; + mulps XMM2, XMM4; + mulps XMM3, XMM4; + //divps XMM0, XMM4; + //divps XMM1, XMM4; + //divps XMM2, XMM4; + //divps XMM3, XMM4; + movups [ESI+ 0-64], XMM0; + movups [ESI+16-64], XMM1; + movups [ESI+32-64], XMM2; + movups [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloop; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + // 3DNow! version is 72% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + T[2] w = void; + + w[0] = recip; + w[1] = recip; + + asm + { + mov ESI, dword ptr [aptr]; + mov EDI, dword ptr [n]; + mov EAX, dword ptr [bptr]; + movq MM4, qword ptr [w]; + + align 8; + start: + movq MM0, [EAX]; + movq MM1, [EAX+8]; + movq MM2, [EAX+16]; + movq MM3, [EAX+24]; + pfmul MM0, MM4; + pfmul MM1, MM4; + pfmul MM2, MM4; + pfmul MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + add EAX, 32; + cmp ESI, EDI; + jb start; + + emms; + mov dword ptr [aptr], ESI; + mov dword ptr [bptr], EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ * recip; + + return a; +} + +unittest +{ + printf("_arraySliceExpDivSliceAssign_f 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[] / 8; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] / 8)) + { + printf("[%d]: %g != %g / 8\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] /= value + */ + +T[] _arrayExpSliceDivass_f(T[] a, T value) +{ + //printf("_arrayExpSliceDivass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + /* Multiplying by the reciprocal is faster, but does + * not produce as accurate an answer. + */ + T recip = cast(T)1 / value; + + version (D_InlineAsm_X86) + { + // SSE version is 245% faster + if (sse() && a.length >= 16) + { + // align pointer + auto n = cast(T*)((cast(uint)aptr + 15) & ~15); + while (aptr < n) + *aptr++ *= recip; + n = cast(T*)((cast(uint)aend) & ~15); + if (aptr < n) + + // Aligned case + asm + { + mov ESI, aptr; + mov EDI, n; + movss XMM4, recip; + //movss XMM4, value + //rcpss XMM4, XMM4 + shufps XMM4, XMM4, 0; + + align 8; + startsseloopa: + movaps XMM0, [ESI]; + movaps XMM1, [ESI+16]; + movaps XMM2, [ESI+32]; + movaps XMM3, [ESI+48]; + add ESI, 64; + mulps XMM0, XMM4; + mulps XMM1, XMM4; + mulps XMM2, XMM4; + mulps XMM3, XMM4; + //divps XMM0, XMM4; + //divps XMM1, XMM4; + //divps XMM2, XMM4; + //divps XMM3, XMM4; + movaps [ESI+ 0-64], XMM0; + movaps [ESI+16-64], XMM1; + movaps [ESI+32-64], XMM2; + movaps [ESI+48-64], XMM3; + cmp ESI, EDI; + jb startsseloopa; + + mov aptr, ESI; + } + } + else + // 3DNow! version is 57% faster + if (amd3dnow() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + T[2] w = void; + + w[0] = w[1] = recip; + + asm + { + mov ESI, dword ptr [aptr]; + mov EDI, dword ptr [n]; + movq MM4, qword ptr [w]; + + align 8; + start: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + movq MM2, [ESI+16]; + movq MM3, [ESI+24]; + pfmul MM0, MM4; + pfmul MM1, MM4; + pfmul MM2, MM4; + pfmul MM3, MM4; + movq [ESI], MM0; + movq [ESI+8], MM1; + movq [ESI+16], MM2; + movq [ESI+24], MM3; + add ESI, 32; + cmp ESI, EDI; + jb start; + + emms; + mov dword ptr [aptr], ESI; + } + } + } + + while (aptr < aend) + *aptr++ *= recip; + + return a; +} + +unittest +{ + printf("_arrayExpSliceDivass_f 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); + } + + a[] = c[]; + c[] /= 8; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] / 8)) + { + printf("[%d]: %g != %g / 8\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= b[] * value + */ + +T[] _arraySliceExpMulSliceMinass_f(T[] a, T value, T[] b) +{ + return _arraySliceExpMulSliceAddass_f(a, -value, b); +} + +/*********************** + * Computes: + * a[] += b[] * value + */ + +T[] _arraySliceExpMulSliceAddass_f(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_f 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]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]); + if (c[i] != cast(T)(b[i] + a[i] * 6)) + { + printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]); + assert(0); + } + } + } + } +} diff --git a/src/compiler/dmd/arrayint.d b/src/compiler/dmd/arrayint.d new file mode 100644 index 0000000..c4f0892 --- /dev/null +++ b/src/compiler/dmd/arrayint.d @@ -0,0 +1,2427 @@ +/*************************** + * D programming language http://www.digitalmars.com/d/ + * Runtime support for byte array operations. + * Based on code originally written by Burton Radons. + * Placed in public domain. + */ + +/* Contains MMX versions of certain operations for dchar, int, + * and uint ('w', 'i' and 'k' suffixes). + */ + +module rt.arrayint; + +private import util.cpuid; + +version (Unittest) +{ + /* This is so unit tests will test every CPU variant + */ + int cpuid; + const int CPUID_MAX = 4; + bool mmx() { return cpuid == 1 && util.cpuid.mmx(); } + bool sse() { return cpuid == 2 && util.cpuid.sse(); } + bool sse2() { return cpuid == 3 && util.cpuid.sse2(); } + bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); } +} +else +{ + alias util.cpuid.mmx mmx; + alias util.cpuid.sse sse; + alias util.cpuid.sse2 sse2; + alias 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 int T; + +extern (C): + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + value + */ + +T[] _arraySliceExpAddSliceAssign_w(T[] a, T value, T[] b) +{ + return _arraySliceExpAddSliceAssign_i(a, value, b); +} + +T[] _arraySliceExpAddSliceAssign_k(T[] a, T value, T[] b) +{ + return _arraySliceExpAddSliceAssign_i(a, value, b); +} + +T[] _arraySliceExpAddSliceAssign_i(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpAddSliceAssign_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 380% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = value; + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + paddd XMM0, XMM2; + paddd XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + paddd XMM0, XMM2; + paddd XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 298% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movq MM2, l; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + add EAX, 16; + paddd MM0, MM2; + paddd MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + else + if (a.length >= 2) + { + auto n = aptr + (a.length & ~1); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov EDX, value; + + align 4; + start386: + add ESI, 8; + mov EBX, [EAX]; + mov ECX, [EAX+4]; + add EAX, 8; + add EBX, EDX; + add ECX, EDX; + mov [ESI -8], EBX; + mov [ESI+4-8], ECX; + cmp ESI, EDI; + jb start386; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ + value; + + return a; +} + +unittest +{ + printf("_arraySliceExpAddSliceAssign_i 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[] + 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + 6)) + { + printf("[%d]: %d != %d + 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + c[] + */ + +T[] _arraySliceSliceAddSliceAssign_w(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceAddSliceAssign_i(a, c, b); +} + +T[] _arraySliceSliceAddSliceAssign_k(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceAddSliceAssign_i(a, c, b); +} + +T[] _arraySliceSliceAddSliceAssign_i(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 +{ + //printf("_arraySliceSliceAddSliceAssign_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1710% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM2, [ECX]; + movdqu XMM1, [EAX+16]; + movdqu XMM3, [ECX+16]; + add EAX, 32; + add ECX, 32; + paddd XMM0, XMM2; + paddd XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM2, [ECX]; + movdqa XMM1, [EAX+16]; + movdqa XMM3, [ECX+16]; + add EAX, 32; + add ECX, 32; + paddd XMM0, XMM2; + paddd XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + else + // MMX version is 995% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM2, [ECX]; + movq MM1, [EAX+8]; + movq MM3, [ECX+8]; + add EAX, 16; + add ECX, 16; + paddd MM0, MM2; + paddd MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + +normal: + while (aptr < aend) + *aptr++ = *bptr++ + *cptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceAddSliceAssign_i 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]: %d != %d + %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += value + */ + +T[] _arrayExpSliceAddass_w(T[] a, T value) +{ + return _arrayExpSliceAddass_i(a, value); +} + +T[] _arrayExpSliceAddass_k(T[] a, T value) +{ + return _arrayExpSliceAddass_i(a, value); +} + +T[] _arrayExpSliceAddass_i(T[] a, T value) +{ + //printf("_arrayExpSliceAddass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 83% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = value; + + if (((cast(uint) aptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + add ESI, 32; + paddd XMM0, XMM2; + paddd XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + add ESI, 32; + paddd XMM0, XMM2; + paddd XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + } + } + } + else + // MMX version is 81% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); + + asm + { + mov ESI, aptr; + mov EDI, n; + movq MM2, l; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + add ESI, 16; + paddd MM0, MM2; + paddd MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + } + } + else + if (a.length >= 2) + { + auto n = aptr + (a.length & ~1); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EDX, value; + + align 4; + start386: + mov EBX, [ESI]; + mov ECX, [ESI+4]; + add ESI, 8; + add EBX, EDX; + add ECX, EDX; + mov [ESI -8], EBX; + mov [ESI+4-8], ECX; + cmp ESI, EDI; + jb start386; + + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ += value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceAddass_i 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); + } + + a[] = c[]; + a[] += 6; + + for (int i = 0; i < dim; i++) + { + if (a[i] != cast(T)(c[i] + 6)) + { + printf("[%d]: %d != %d + 6\n", i, a[i], c[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += b[] + */ + +T[] _arraySliceSliceAddass_w(T[] a, T[] b) +{ + return _arraySliceSliceAddass_i(a, b); +} + +T[] _arraySliceSliceAddass_k(T[] a, T[] b) +{ + return _arraySliceSliceAddass_i(a, b); +} + +T[] _arraySliceSliceAddass_i(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceAddass_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 695% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2u: + movdqu XMM0, [ESI]; + movdqu XMM2, [ECX]; + movdqu XMM1, [ESI+16]; + movdqu XMM3, [ECX+16]; + add ESI, 32; + add ECX, 32; + paddd XMM0, XMM2; + paddd XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2a: + movdqa XMM0, [ESI]; + movdqa XMM2, [ECX]; + movdqa XMM1, [ESI+16]; + movdqa XMM3, [ECX+16]; + add ESI, 32; + add ECX, 32; + paddd XMM0, XMM2; + paddd XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + else + // MMX version is 471% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM2, [ECX]; + movq MM1, [ESI+8]; + movq MM3, [ECX+8]; + add ESI, 16; + add ECX, 16; + paddd MM0, MM2; + paddd MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } + } + +normal: + while (aptr < aend) + *aptr++ += *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceAddass_i 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); + } + + b[] = c[]; + c[] += a[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(b[i] + a[i])) + { + printf("[%d]: %d != %d + %d\n", i, c[i], b[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - value + */ + +T[] _arraySliceExpMinSliceAssign_w(T[] a, T value, T[] b) +{ + return _arraySliceExpMinSliceAssign_i(a, value, b); +} + +T[] _arraySliceExpMinSliceAssign_k(T[] a, T value, T[] b) +{ + return _arraySliceExpMinSliceAssign_i(a, value, b); +} + +T[] _arraySliceExpMinSliceAssign_i(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMinSliceAssign_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 400% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = value; + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 315% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movq MM2, l; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + add EAX, 16; + psubd MM0, MM2; + psubd MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + else + if (a.length >= 2) + { + auto n = aptr + (a.length & ~1); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov EDX, value; + + align 4; + start386: + add ESI, 8; + mov EBX, [EAX]; + mov ECX, [EAX+4]; + add EAX, 8; + sub EBX, EDX; + sub ECX, EDX; + mov [ESI -8], EBX; + mov [ESI+4-8], ECX; + cmp ESI, EDI; + jb start386; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ - value; + + return a; +} + +unittest +{ + printf("_arraySliceExpMinSliceAssign_i 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[] - 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %d != %d - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = value - b[] + */ + +T[] _arrayExpSliceMinSliceAssign_w(T[] a, T[] b, T value) +{ + return _arrayExpSliceMinSliceAssign_i(a, b, value); +} + +T[] _arrayExpSliceMinSliceAssign_k(T[] a, T[] b, T value) +{ + return _arrayExpSliceMinSliceAssign_i(a, b, value); +} + +T[] _arrayExpSliceMinSliceAssign_i(T[] a, T[] b, T value) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arrayExpSliceMinSliceAssign_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1812% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = value; + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 4; + startaddsse2u: + add ESI, 32; + movdqu XMM2, [EAX]; + movdqu XMM3, [EAX+16]; + movdqa XMM0, XMM4; + movdqa XMM1, XMM4; + add EAX, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM4, l; + pshufd XMM4, XMM4, 0; + + align 4; + startaddsse2a: + add ESI, 32; + movdqa XMM2, [EAX]; + movdqa XMM3, [EAX+16]; + movdqa XMM0, XMM4; + movdqa XMM1, XMM4; + add EAX, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 1077% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movq MM4, l; + + align 4; + startmmx: + add ESI, 16; + movq MM2, [EAX]; + movq MM3, [EAX+8]; + movq MM0, MM4; + movq MM1, MM4; + add EAX, 16; + psubd MM0, MM2; + psubd MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = value - *bptr++; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinSliceAssign_i 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[] = 6 - a[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(6 - a[i])) + { + printf("[%d]: %d != 6 - %d\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - c[] + */ + +T[] _arraySliceSliceMinSliceAssign_w(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMinSliceAssign_i(a, c, b); +} + +T[] _arraySliceSliceMinSliceAssign_k(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMinSliceAssign_i(a, c, b); +} + +T[] _arraySliceSliceMinSliceAssign_i(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 +{ + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1721% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM2, [ECX]; + movdqu XMM1, [EAX+16]; + movdqu XMM3, [ECX+16]; + add EAX, 32; + add ECX, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM2, [ECX]; + movdqa XMM1, [EAX+16]; + movdqa XMM3, [ECX+16]; + add EAX, 32; + add ECX, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + else + // MMX version is 1002% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM2, [ECX]; + movq MM1, [EAX+8]; + movq MM3, [ECX+8]; + add EAX, 16; + add ECX, 16; + psubd MM0, MM2; + psubd MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ - *cptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMinSliceAssign_i 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]: %d != %d - %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= value + */ + +T[] _arrayExpSliceMinass_w(T[] a, T value) +{ + return _arrayExpSliceMinass_i(a, value); +} + +T[] _arrayExpSliceMinass_k(T[] a, T value) +{ + return _arrayExpSliceMinass_i(a, value); +} + +T[] _arrayExpSliceMinass_i(T[] a, T value) +{ + //printf("_arrayExpSliceMinass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 81% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = value; + + if (((cast(uint) aptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + add ESI, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + add ESI, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + } + } + } + else + // MMX version is 81% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); + + asm + { + mov ESI, aptr; + mov EDI, n; + movq MM2, l; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + add ESI, 16; + psubd MM0, MM2; + psubd MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + } + } + else + if (a.length >= 2) + { + auto n = aptr + (a.length & ~1); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EDX, value; + + align 4; + start386: + mov EBX, [ESI]; + mov ECX, [ESI+4]; + add ESI, 8; + sub EBX, EDX; + sub ECX, EDX; + mov [ESI -8], EBX; + mov [ESI+4-8], ECX; + cmp ESI, EDI; + jb start386; + + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ -= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinass_i 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); + } + + a[] = c[]; + a[] -= 6; + + for (int i = 0; i < dim; i++) + { + if (a[i] != cast(T)(c[i] - 6)) + { + printf("[%d]: %d != %d - 6\n", i, a[i], c[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= b[] + */ + +T[] _arraySliceSliceMinass_w(T[] a, T[] b) +{ + return _arraySliceSliceMinass_i(a, b); +} + +T[] _arraySliceSliceMinass_k(T[] a, T[] b) +{ + return _arraySliceSliceMinass_i(a, b); +} + +T[] _arraySliceSliceMinass_i(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMinass_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 731% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2u: + movdqu XMM0, [ESI]; + movdqu XMM2, [ECX]; + movdqu XMM1, [ESI+16]; + movdqu XMM3, [ECX+16]; + add ESI, 32; + add ECX, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2a: + movdqa XMM0, [ESI]; + movdqa XMM2, [ECX]; + movdqa XMM1, [ESI+16]; + movdqa XMM3, [ECX+16]; + add ESI, 32; + add ECX, 32; + psubd XMM0, XMM2; + psubd XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + else + // MMX version is 441% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM2, [ECX]; + movq MM1, [ESI+8]; + movq MM3, [ECX+8]; + add ESI, 16; + add ECX, 16; + psubd MM0, MM2; + psubd MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ -= *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMinass_i 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); + } + + b[] = c[]; + c[] -= a[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(b[i] - a[i])) + { + printf("[%d]: %d != %d - %d\n", i, c[i], b[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] * value + */ + +T[] _arraySliceExpMulSliceAssign_w(T[] a, T value, T[] b) +{ + return _arraySliceExpMulSliceAssign_i(a, value, b); +} + +T[] _arraySliceExpMulSliceAssign_k(T[] a, T value, T[] b) +{ + return _arraySliceExpMulSliceAssign_i(a, value, b); +} + +T[] _arraySliceExpMulSliceAssign_i(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMulSliceAssign_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (none) // multiplying a pair is not supported by MMX + { + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1380% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = value; + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + pmuludq XMM0, XMM2; + pmuludq XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + pmuludq XMM0, XMM2; + pmuludq XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + { + // MMX version is 1380% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movq MM2, l; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + add EAX, 16; + pmuludq MM0, MM2; // only multiplies low 32 bits + pmuludq MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ * value; + + return a; +} + +unittest +{ + printf("_arraySliceExpMulSliceAssign_s 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[] * 6; + + for (int i = 0; i < dim; i++) + { + //printf("[%d]: %d ?= %d * 6\n", i, c[i], a[i]); + if (c[i] != cast(T)(a[i] * 6)) + { + printf("[%d]: %d != %d * 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] * c[] + */ + +T[] _arraySliceSliceMulSliceAssign_w(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMulSliceAssign_i(a, c, b); +} + +T[] _arraySliceSliceMulSliceAssign_k(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMulSliceAssign_i(a, c, b); +} + +T[] _arraySliceSliceMulSliceAssign_i(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 +{ + //printf("_arraySliceSliceMulSliceAssign_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (none) + { + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 1407% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM2, [ECX]; + movdqu XMM1, [EAX+16]; + movdqu XMM3, [ECX+16]; + add EAX, 32; + add ECX, 32; + pmuludq XMM0, XMM2; + pmuludq XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM2, [ECX]; + movdqa XMM1, [EAX+16]; + movdqa XMM3, [ECX+16]; + add EAX, 32; + add ECX, 32; + pmuludq XMM0, XMM2; + pmuludq XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + else + // MMX version is 1029% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM2, [ECX]; + movq MM1, [EAX+8]; + movq MM3, [ECX+8]; + add EAX, 16; + add ECX, 16; + pmuludq MM0, MM2; + pmuludq MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + } + + while (aptr < aend) + *aptr++ = *bptr++ * *cptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMulSliceAssign_i 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]: %d != %d * %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] *= value + */ + +T[] _arrayExpSliceMulass_w(T[] a, T value) +{ + return _arrayExpSliceMulass_i(a, value); +} + +T[] _arrayExpSliceMulass_k(T[] a, T value) +{ + return _arrayExpSliceMulass_i(a, value); +} + +T[] _arrayExpSliceMulass_i(T[] a, T value) +{ + //printf("_arrayExpSliceMulass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (none) + { + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 400% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = value; + + if (((cast(uint) aptr) & 15) != 0) + { + asm + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + add ESI, 32; + pmuludq XMM0, XMM2; + pmuludq XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + } + } + else + { + asm + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + add ESI, 32; + pmuludq XMM0, XMM2; + pmuludq XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + } + } + } + else + // MMX version is 402% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); + + asm + { + mov ESI, aptr; + mov EDI, n; + movq MM2, l; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + add ESI, 16; + pmuludq MM0, MM2; + pmuludq MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + } + } + } + } + + while (aptr < aend) + *aptr++ *= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMulass_i 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); + } + + b[] = a[]; + a[] *= 6; + + for (int i = 0; i < dim; i++) + { + if (a[i] != cast(T)(b[i] * 6)) + { + printf("[%d]: %d != %d * 6\n", i, a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] *= b[] + */ + +T[] _arraySliceSliceMulass_w(T[] a, T[] b) +{ + return _arraySliceSliceMulass_i(a, b); +} + +T[] _arraySliceSliceMulass_k(T[] a, T[] b) +{ + return _arraySliceSliceMulass_i(a, b); +} + +T[] _arraySliceSliceMulass_i(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMulass_i()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (none) + { + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 873% faster + if (sse2() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2u: + movdqu XMM0, [ESI]; + movdqu XMM2, [ECX]; + movdqu XMM1, [ESI+16]; + movdqu XMM3, [ECX+16]; + add ESI, 32; + add ECX, 32; + pmuludq XMM0, XMM2; + pmuludq XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2a: + movdqa XMM0, [ESI]; + movdqa XMM2, [ECX]; + movdqa XMM1, [ESI+16]; + movdqa XMM3, [ECX+16]; + add ESI, 32; + add ECX, 32; + pmuludq XMM0, XMM2; + pmuludq XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } +/+ BUG: comment out this section until we figure out what is going + wrong with the invalid pshufd instructions. + + else + // MMX version is 573% faster + if (mmx() && a.length >= 4) + { + auto n = aptr + (a.length & ~3); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM2, [ECX]; + movq MM1, [ESI+8]; + movq MM3, [ECX+8]; + pxor MM4, MM4; + pxor MM5, MM5; + punpckldq MM4, MM0; + punpckldq MM5, MM2; + add ESI, 16; + add ECX, 16; + pmuludq MM4, MM5; + pshufd MM4, MM4, 8; // ? + movq [ESI -16], MM4; + pxor MM4, MM4; + pxor MM5, MM5; + punpckldq MM4, MM1; + punpckldq MM5, MM3; + pmuludq MM4, MM5; + pshufd MM4, MM4, 8; // ? + movq [ESI+8-16], MM4; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } ++/ + } + } + + while (aptr < aend) + *aptr++ *= *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMulass_i 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); + } + + b[] = a[]; + a[] *= c[]; + + for (int i = 0; i < dim; i++) + { + if (a[i] != cast(T)(b[i] * c[i])) + { + printf("[%d]: %d != %d * %d\n", i, a[i], b[i], c[i]); + assert(0); + } + } + } + } +} diff --git a/src/compiler/dmd/arrayreal.d b/src/compiler/dmd/arrayreal.d new file mode 100644 index 0000000..2dda218 --- /dev/null +++ b/src/compiler/dmd/arrayreal.d @@ -0,0 +1,234 @@ +/*************************** + * D programming language http://www.digitalmars.com/d/ + * Runtime support for double array operations. + * Placed in public domain. + */ + +module rt.arrayreal; + +import util.cpuid; + +version (Unittest) +{ + /* This is so unit tests will test every CPU variant + */ + int cpuid; + const int CPUID_MAX = 1; + bool mmx() { return cpuid == 1 && util.cpuid.mmx(); } + bool sse() { return cpuid == 2 && util.cpuid.sse(); } + bool sse2() { return cpuid == 3 && util.cpuid.sse2(); } + bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); } +} +else +{ + alias util.cpuid.mmx mmx; + alias util.cpuid.sse sse; + alias util.cpuid.sse2 sse2; + alias 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); + } + } + } + } +} diff --git a/src/compiler/dmd/arrayshort.d b/src/compiler/dmd/arrayshort.d new file mode 100644 index 0000000..0208d89 --- /dev/null +++ b/src/compiler/dmd/arrayshort.d @@ -0,0 +1,2300 @@ +/*************************** + * D programming language http://www.digitalmars.com/d/ + * Runtime support for byte array operations. + * Based on code originally written by Burton Radons. + * Placed in public domain. + */ + +/* Contains SSE2 and MMX versions of certain operations for wchar, short, + * and ushort ('u', 's' and 't' suffixes). + */ + +module rt.arrayshort; + +private import util.cpuid; + +version (Unittest) +{ + /* This is so unit tests will test every CPU variant + */ + int cpuid; + const int CPUID_MAX = 4; + bool mmx() { return cpuid == 1 && util.cpuid.mmx(); } + bool sse() { return cpuid == 2 && util.cpuid.sse(); } + bool sse2() { return cpuid == 3 && util.cpuid.sse2(); } + bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); } +} +else +{ + alias util.cpuid.mmx mmx; + alias util.cpuid.sse sse; + alias util.cpuid.sse2 sse2; + alias util.cpuid.sse2 sse2; +} + +//version = log; + +bool disjoint(T)(T[] a, T[] b) +{ + return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr); +} + +alias short T; + +extern (C): + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + value + */ + +T[] _arraySliceExpAddSliceAssign_u(T[] a, T value, T[] b) +{ + return _arraySliceExpAddSliceAssign_s(a, value, b); +} + +T[] _arraySliceExpAddSliceAssign_t(T[] a, T value, T[] b) +{ + return _arraySliceExpAddSliceAssign_s(a, value, b); +} + +T[] _arraySliceExpAddSliceAssign_s(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpAddSliceAssign_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 3343% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + uint l = cast(ushort) value; + l |= (l << 16); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + paddw XMM0, XMM2; + paddw XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + paddw XMM0, XMM2; + paddw XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 3343% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = cast(ushort) value; + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd MM2, l; + pshufw MM2, MM2, 0; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + add EAX, 16; + paddw MM0, MM2; + paddw MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ + value); + + return a; +} + +unittest +{ + printf("_arraySliceExpAddSliceAssign_s 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[] + 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] + 6)) + { + printf("[%d]: %d != %d + 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] + c[] + */ + +T[] _arraySliceSliceAddSliceAssign_u(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceAddSliceAssign_s(a, c, b); +} + +T[] _arraySliceSliceAddSliceAssign_t(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceAddSliceAssign_s(a, c, b); +} + +T[] _arraySliceSliceAddSliceAssign_s(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 +{ + //printf("_arraySliceSliceAddSliceAssign_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 3777% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + movdqu XMM2, [ECX]; + movdqu XMM3, [ECX+16]; + add ECX, 32; + paddw XMM0, XMM2; + paddw XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + movdqa XMM2, [ECX]; + movdqa XMM3, [ECX+16]; + add ECX, 32; + paddw XMM0, XMM2; + paddw XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + else + // MMX version is 2068% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + add EAX, 16; + movq MM2, [ECX]; + movq MM3, [ECX+8]; + add ECX, 16; + paddw MM0, MM2; + paddw MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ + *cptr++); + + return a; +} + +unittest +{ + printf("_arraySliceSliceAddSliceAssign_s 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]: %d != %d + %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += value + */ + +T[] _arrayExpSliceAddass_u(T[] a, T value) +{ + return _arrayExpSliceAddass_s(a, value); +} + +T[] _arrayExpSliceAddass_t(T[] a, T value) +{ + return _arrayExpSliceAddass_s(a, value); +} + +T[] _arrayExpSliceAddass_s(T[] a, T value) +{ + //printf("_arrayExpSliceAddass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 832% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + uint l = cast(ushort) value; + l |= (l << 16); + + if (((cast(uint) aptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + add ESI, 32; + paddw XMM0, XMM2; + paddw XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + add ESI, 32; + paddw XMM0, XMM2; + paddw XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + } + } + } + else + // MMX version is 826% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = cast(ushort) value; + + asm + { + mov ESI, aptr; + mov EDI, n; + movd MM2, l; + pshufw MM2, MM2, 0; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + add ESI, 16; + paddw MM0, MM2; + paddw MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ += value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceAddass_s 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); + } + + a[] = c[]; + a[] += 6; + + for (int i = 0; i < dim; i++) + { + if (a[i] != cast(T)(c[i] + 6)) + { + printf("[%d]: %d != %d + 6\n", i, a[i], c[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] += b[] + */ + +T[] _arraySliceSliceAddass_u(T[] a, T[] b) +{ + return _arraySliceSliceAddass_s(a, b); +} + +T[] _arraySliceSliceAddass_t(T[] a, T[] b) +{ + return _arraySliceSliceAddass_s(a, b); +} + +T[] _arraySliceSliceAddass_s(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceAddass_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 2085% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + add ESI, 32; + movdqu XMM2, [ECX]; + movdqu XMM3, [ECX+16]; + add ECX, 32; + paddw XMM0, XMM2; + paddw XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + add ESI, 32; + movdqa XMM2, [ECX]; + movdqa XMM3, [ECX+16]; + add ECX, 32; + paddw XMM0, XMM2; + paddw XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + else + // MMX version is 1022% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + start: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + add ESI, 16; + movq MM2, [ECX]; + movq MM3, [ECX+8]; + add ECX, 16; + paddw MM0, MM2; + paddw MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb start; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ += *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceAddass_s 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); + } + + b[] = c[]; + c[] += a[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(b[i] + a[i])) + { + printf("[%d]: %d != %d + %d\n", i, c[i], b[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - value + */ + +T[] _arraySliceExpMinSliceAssign_u(T[] a, T value, T[] b) +{ + return _arraySliceExpMinSliceAssign_s(a, value, b); +} + +T[] _arraySliceExpMinSliceAssign_t(T[] a, T value, T[] b) +{ + return _arraySliceExpMinSliceAssign_s(a, value, b); +} + +T[] _arraySliceExpMinSliceAssign_s(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMinSliceAssign_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 3695% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + uint l = cast(ushort) value; + l |= (l << 16); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + psubw XMM0, XMM2; + psubw XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + psubw XMM0, XMM2; + psubw XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 3049% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = cast(ushort) value; + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd MM2, l; + pshufw MM2, MM2, 0; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + add EAX, 16; + psubw MM0, MM2; + psubw MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ - value); + + return a; +} + +unittest +{ + printf("_arraySliceExpMinSliceAssign_s 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[] - 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] - 6)) + { + printf("[%d]: %d != %d - 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = value - b[] + */ + +T[] _arrayExpSliceMinSliceAssign_u(T[] a, T[] b, T value) +{ + return _arrayExpSliceMinSliceAssign_s(a, b, value); +} + +T[] _arrayExpSliceMinSliceAssign_t(T[] a, T[] b, T value) +{ + return _arrayExpSliceMinSliceAssign_s(a, b, value); +} + +T[] _arrayExpSliceMinSliceAssign_s(T[] a, T[] b, T value) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arrayExpSliceMinSliceAssign_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 4995% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + uint l = cast(ushort) value; + l |= (l << 16); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + + align 4; + startaddsse2u: + movd XMM2, l; + pshufd XMM2, XMM2, 0; + movd XMM3, l; + pshufd XMM3, XMM3, 0; + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + psubw XMM2, XMM0; + psubw XMM3, XMM1; + movdqu [ESI -32], XMM2; + movdqu [ESI+16-32], XMM3; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + + align 4; + startaddsse2a: + movd XMM2, l; + pshufd XMM2, XMM2, 0; + movd XMM3, l; + pshufd XMM3, XMM3, 0; + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + psubw XMM2, XMM0; + psubw XMM3, XMM1; + movdqa [ESI -32], XMM2; + movdqa [ESI+16-32], XMM3; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 4562% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = cast(ushort) value; + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd MM4, l; + pshufw MM4, MM4, 0; + + align 4; + startmmx: + add ESI, 16; + movq MM2, [EAX]; + movq MM3, [EAX+8]; + movq MM0, MM4; + movq MM1, MM4; + add EAX, 16; + psubw MM0, MM2; + psubw MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(value - *bptr++); + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinSliceAssign_s 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[] = 6 - a[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(6 - a[i])) + { + printf("[%d]: %d != 6 - %d\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] - c[] + */ + +T[] _arraySliceSliceMinSliceAssign_u(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMinSliceAssign_s(a, c, b); +} + +T[] _arraySliceSliceMinSliceAssign_t(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMinSliceAssign_s(a, c, b); +} + +T[] _arraySliceSliceMinSliceAssign_s(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 +{ + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 4129% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + movdqu XMM2, [ECX]; + movdqu XMM3, [ECX+16]; + add ECX, 32; + psubw XMM0, XMM2; + psubw XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + movdqa XMM2, [ECX]; + movdqa XMM3, [ECX+16]; + add ECX, 32; + psubw XMM0, XMM2; + psubw XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + else + // MMX version is 2018% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + add EAX, 16; + movq MM2, [ECX]; + movq MM3, [ECX+8]; + add ECX, 16; + psubw MM0, MM2; + psubw MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ - *cptr++); + + return a; +} + +unittest +{ + printf("_arraySliceSliceMinSliceAssign_s 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]: %d != %d - %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= value + */ + +T[] _arrayExpSliceMinass_u(T[] a, T value) +{ + return _arrayExpSliceMinass_s(a, value); +} + +T[] _arrayExpSliceMinass_t(T[] a, T value) +{ + return _arrayExpSliceMinass_s(a, value); +} + +T[] _arrayExpSliceMinass_s(T[] a, T value) +{ + //printf("_arrayExpSliceMinass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 835% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + uint l = cast(ushort) value; + l |= (l << 16); + + if (((cast(uint) aptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + add ESI, 32; + psubw XMM0, XMM2; + psubw XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2u; + + mov aptr, ESI; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startaddsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + add ESI, 32; + psubw XMM0, XMM2; + psubw XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startaddsse2a; + + mov aptr, ESI; + } + } + } + else + // MMX version is 835% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = cast(ushort) value; + + asm + { + mov ESI, aptr; + mov EDI, n; + movd MM2, l; + pshufw MM2, MM2, 0; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + add ESI, 16; + psubw MM0, MM2; + psubw MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ -= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMinass_s 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); + } + + a[] = c[]; + a[] -= 6; + + for (int i = 0; i < dim; i++) + { + if (a[i] != cast(T)(c[i] - 6)) + { + printf("[%d]: %d != %d - 6\n", i, a[i], c[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] -= b[] + */ + +T[] _arraySliceSliceMinass_u(T[] a, T[] b) +{ + return _arraySliceSliceMinass_s(a, b); +} + +T[] _arraySliceSliceMinass_t(T[] a, T[] b) +{ + return _arraySliceSliceMinass_s(a, b); +} + +T[] _arraySliceSliceMinass_s(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMinass_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 2121% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm // unaligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + add ESI, 32; + movdqu XMM2, [ECX]; + movdqu XMM3, [ECX+16]; + add ECX, 32; + psubw XMM0, XMM2; + psubw XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + { + asm // aligned case + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + add ESI, 32; + movdqa XMM2, [ECX]; + movdqa XMM3, [ECX+16]; + add ECX, 32; + psubw XMM0, XMM2; + psubw XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + else + // MMX version is 1116% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + start: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + add ESI, 16; + movq MM2, [ECX]; + movq MM3, [ECX+8]; + add ECX, 16; + psubw MM0, MM2; + psubw MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb start; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ -= *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMinass_s 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); + } + + b[] = c[]; + c[] -= a[]; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(b[i] - a[i])) + { + printf("[%d]: %d != %d - %d\n", i, c[i], b[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] * value + */ + +T[] _arraySliceExpMulSliceAssign_u(T[] a, T value, T[] b) +{ + return _arraySliceExpMulSliceAssign_s(a, value, b); +} + +T[] _arraySliceExpMulSliceAssign_t(T[] a, T value, T[] b) +{ + return _arraySliceExpMulSliceAssign_s(a, value, b); +} + +T[] _arraySliceExpMulSliceAssign_s(T[] a, T value, T[] b) +in +{ + assert(a.length == b.length); + assert(disjoint(a, b)); +} +body +{ + //printf("_arraySliceExpMulSliceAssign_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 3733% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + uint l = cast(ushort) value; + l |= l << 16; + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM1, [EAX+16]; + add EAX, 32; + pmullw XMM0, XMM2; + pmullw XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, EAX; + } + } + else + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM1, [EAX+16]; + add EAX, 32; + pmullw XMM0, XMM2; + pmullw XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, EAX; + } + } + } + else + // MMX version is 3733% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = cast(ushort) value; + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + movd MM2, l; + pshufw MM2, MM2, 0; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM1, [EAX+8]; + add EAX, 16; + pmullw MM0, MM2; + pmullw MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ * value); + + return a; +} + +unittest +{ + printf("_arraySliceExpMulSliceAssign_s 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[] * 6; + + for (int i = 0; i < dim; i++) + { + if (c[i] != cast(T)(a[i] * 6)) + { + printf("[%d]: %d != %d * 6\n", i, c[i], a[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] = b[] * c[] + */ + +T[] _arraySliceSliceMulSliceAssign_u(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMulSliceAssign_s(a, c, b); +} + +T[] _arraySliceSliceMulSliceAssign_t(T[] a, T[] c, T[] b) +{ + return _arraySliceSliceMulSliceAssign_s(a, c, b); +} + +T[] _arraySliceSliceMulSliceAssign_s(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 +{ + //printf("_arraySliceSliceMulSliceAssign_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + auto cptr = c.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 2515% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2u: + add ESI, 32; + movdqu XMM0, [EAX]; + movdqu XMM2, [ECX]; + movdqu XMM1, [EAX+16]; + movdqu XMM3, [ECX+16]; + add EAX, 32; + add ECX, 32; + pmullw XMM0, XMM2; + pmullw XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + else + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startsse2a: + add ESI, 32; + movdqa XMM0, [EAX]; + movdqa XMM2, [ECX]; + movdqa XMM1, [EAX+16]; + movdqa XMM3, [ECX+16]; + add EAX, 32; + add ECX, 32; + pmullw XMM0, XMM2; + pmullw XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + else + // MMX version is 2515% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov EAX, bptr; + mov ECX, cptr; + + align 4; + startmmx: + add ESI, 16; + movq MM0, [EAX]; + movq MM2, [ECX]; + movq MM1, [EAX+8]; + movq MM3, [ECX+8]; + add EAX, 16; + add ECX, 16; + pmullw MM0, MM2; + pmullw MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, EAX; + mov cptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ = cast(T)(*bptr++ * *cptr++); + + return a; +} + +unittest +{ + printf("_arraySliceSliceMulSliceAssign_s 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]: %d != %d * %d\n", i, c[i], a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] *= value + */ + +T[] _arrayExpSliceMulass_u(T[] a, T value) +{ + return _arrayExpSliceMulass_s(a, value); +} + +T[] _arrayExpSliceMulass_t(T[] a, T value) +{ + return _arrayExpSliceMulass_s(a, value); +} + +T[] _arrayExpSliceMulass_s(T[] a, T value) +{ + //printf("_arrayExpSliceMulass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value); + auto aptr = a.ptr; + auto aend = aptr + a.length; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 2044% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + uint l = cast(ushort) value; + l |= l << 16; + + if (((cast(uint) aptr) & 15) != 0) + { + asm + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startsse2u: + movdqu XMM0, [ESI]; + movdqu XMM1, [ESI+16]; + add ESI, 32; + pmullw XMM0, XMM2; + pmullw XMM1, XMM2; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + } + } + else + { + asm + { + mov ESI, aptr; + mov EDI, n; + movd XMM2, l; + pshufd XMM2, XMM2, 0; + + align 4; + startsse2a: + movdqa XMM0, [ESI]; + movdqa XMM1, [ESI+16]; + add ESI, 32; + pmullw XMM0, XMM2; + pmullw XMM1, XMM2; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + } + } + } + else + // MMX version is 2056% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + uint l = cast(ushort) value; + + asm + { + mov ESI, aptr; + mov EDI, n; + movd MM2, l; + pshufw MM2, MM2, 0; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM1, [ESI+8]; + add ESI, 16; + pmullw MM0, MM2; + pmullw MM1, MM2; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + } + } + } + + while (aptr < aend) + *aptr++ *= value; + + return a; +} + +unittest +{ + printf("_arrayExpSliceMulass_s 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); + } + + b[] = a[]; + a[] *= 6; + + for (int i = 0; i < dim; i++) + { + if (a[i] != cast(T)(b[i] * 6)) + { + printf("[%d]: %d != %d * 6\n", i, a[i], b[i]); + assert(0); + } + } + } + } +} + + +/* ======================================================================== */ + +/*********************** + * Computes: + * a[] *= b[] + */ + +T[] _arraySliceSliceMulass_u(T[] a, T[] b) +{ + return _arraySliceSliceMulass_s(a, b); +} + +T[] _arraySliceSliceMulass_t(T[] a, T[] b) +{ + return _arraySliceSliceMulass_s(a, b); +} + +T[] _arraySliceSliceMulass_s(T[] a, T[] b) +in +{ + assert (a.length == b.length); + assert (disjoint(a, b)); +} +body +{ + //printf("_arraySliceSliceMulass_s()\n"); + auto aptr = a.ptr; + auto aend = aptr + a.length; + auto bptr = b.ptr; + + version (D_InlineAsm_X86) + { + // SSE2 aligned version is 2519% faster + if (sse2() && a.length >= 16) + { + auto n = aptr + (a.length & ~15); + + if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2u: + movdqu XMM0, [ESI]; + movdqu XMM2, [ECX]; + movdqu XMM1, [ESI+16]; + movdqu XMM3, [ECX+16]; + add ESI, 32; + add ECX, 32; + pmullw XMM0, XMM2; + pmullw XMM1, XMM3; + movdqu [ESI -32], XMM0; + movdqu [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2u; + + mov aptr, ESI; + mov bptr, ECX; + } + } + else + { + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startsse2a: + movdqa XMM0, [ESI]; + movdqa XMM2, [ECX]; + movdqa XMM1, [ESI+16]; + movdqa XMM3, [ECX+16]; + add ESI, 32; + add ECX, 32; + pmullw XMM0, XMM2; + pmullw XMM1, XMM3; + movdqa [ESI -32], XMM0; + movdqa [ESI+16-32], XMM1; + cmp ESI, EDI; + jb startsse2a; + + mov aptr, ESI; + mov bptr, ECX; + } + } + } + else + // MMX version is 1712% faster + if (mmx() && a.length >= 8) + { + auto n = aptr + (a.length & ~7); + + asm + { + mov ESI, aptr; + mov EDI, n; + mov ECX, bptr; + + align 4; + startmmx: + movq MM0, [ESI]; + movq MM2, [ECX]; + movq MM1, [ESI+8]; + movq MM3, [ECX+8]; + add ESI, 16; + add ECX, 16; + pmullw MM0, MM2; + pmullw MM1, MM3; + movq [ESI -16], MM0; + movq [ESI+8-16], MM1; + cmp ESI, EDI; + jb startmmx; + + emms; + mov aptr, ESI; + mov bptr, ECX; + } + } + } + + while (aptr < aend) + *aptr++ *= *bptr++; + + return a; +} + +unittest +{ + printf("_arraySliceSliceMulass_s 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); + } + + b[] = a[]; + a[] *= c[]; + + for (int i = 0; i < dim; i++) + { + if (a[i] != cast(T)(b[i] * c[i])) + { + printf("[%d]: %d != %d * %d\n", i, a[i], b[i], c[i]); + assert(0); + } + } + } + } +} diff --git a/src/compiler/dmd/cast_.d b/src/compiler/dmd/cast_.d new file mode 100644 index 0000000..f7c7d91 --- /dev/null +++ b/src/compiler/dmd/cast_.d @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +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); +} diff --git a/src/compiler/dmd/cmath2.d b/src/compiler/dmd/cmath2.d new file mode 100644 index 0000000..5028fe9 --- /dev/null +++ b/src/compiler/dmd/cmath2.d @@ -0,0 +1,218 @@ + +// Copyright (C) 2001-2003 by Digital Mars +// All Rights Reserved +// www.digitalmars.com + +// Runtime support for complex arithmetic code generation +// (for linux) + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.cmath2; + +private import 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 ; + } +} diff --git a/src/compiler/dmd/compiler.d b/src/compiler/dmd/compiler.d new file mode 100644 index 0000000..3bea599 --- /dev/null +++ b/src/compiler/dmd/compiler.d @@ -0,0 +1,36 @@ + +/* Written by Walter Bright + * www.digitalmars.com + * Placed into Public Domain + */ + +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; +} diff --git a/src/compiler/dmd/complex.c b/src/compiler/dmd/complex.c new file mode 100644 index 0000000..57fb113 --- /dev/null +++ b/src/compiler/dmd/complex.c @@ -0,0 +1,107 @@ +/* + * Placed into the public domain. + * Written by Walter Bright + * www.digitalmars.com + */ + + +#include + +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; +} diff --git a/src/compiler/dmd/cover.d b/src/compiler/dmd/cover.d new file mode 100644 index 0000000..fd33161 --- /dev/null +++ b/src/compiler/dmd/cover.d @@ -0,0 +1,370 @@ +/** + * Code coverage analyzer. + * + * Bugs: + * $(UL + * $(LI the execution counters are 32 bits in size, and can overflow) + * $(LI inline asm statements are not counted) + * ) + * + * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. All rights reserved. + * License: BSD style: $(LICENSE) + * Authors: Walter Bright, Sean Kelly + */ + +module rt. cover; + +private +{ + version( Windows ) + import sys.windows.windows; + else version( Posix ) + import stdc.posix.unistd; + import bitmanip; + import stdc.stdio; + import 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 + { + char[] filename; + BitArray valid; + uint[] data; + } + + Cover[] gdata; + char[] srcpath; + char[] dstpath; + bool merge; +} + + +/** + * Set path to where source files are located. + * + * Params: + * pathname = The new path name. + */ +extern (C) void dmd_coverSourcePath( char[] pathname ) +{ + srcpath = pathname; +} + + +/** + * Set path to where listing files are to be written. + * + * Params: + * pathname = The new path name. + */ +extern (C) void dmd_coverDestPath( char[] 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( char[] 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( 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( (c.filename ~ ".lst").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 ); + } +} + + +char[] appendFN( char[] path, char[] name ) +{ + version( Windows ) + const char sep = '\\'; + else + const char sep = '/'; + + char[] dest = path; + + if( dest && dest[$ - 1] != sep ) + dest ~= sep; + dest ~= name; + return dest; +} + + +bool readFile( char[] name, inout char[] buf ) +{ + version( Windows ) + { + wchar* 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( linux ) + { + 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[] string, int tabsize = 8 ) +{ + const dchar LS = '\u2028'; // UTF line separator + const dchar PS = '\u2029'; // UTF paragraph separator + + bool changes = false; + char[] result = string; + int column; + int nspaces; + + foreach( size_t i, dchar c; string ) + { + switch( c ) + { + case '\t': + nspaces = tabsize - (column % tabsize); + if( !changes ) + { + changes = true; + result = null; + result.length = string.length + nspaces - 1; + result.length = i + nspaces; + result[0 .. i] = string[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; +} diff --git a/src/compiler/dmd/critical.c b/src/compiler/dmd/critical.c new file mode 100644 index 0000000..a77d1f7 --- /dev/null +++ b/src/compiler/dmd/critical.c @@ -0,0 +1,159 @@ +/* + * Placed into the Public Domain + * written by Walter Bright, Digital Mars + * www.digitalmars.com + */ + +/* ================================= Win32 ============================ */ + +#if _WIN32 + +#include + +/****************************************** + * 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 + +#include +#include +#include + +/****************************************** + * Enter/exit critical section. + */ + +/* We don't initialize critical sections unless we actually need them. + * So keep a linked list of the ones we do use, and in the static destructor + * code, walk the list and release them. + */ + +typedef struct D_CRITICAL_SECTION +{ + struct D_CRITICAL_SECTION *next; + pthread_mutex_t cs; +} D_CRITICAL_SECTION; + +static D_CRITICAL_SECTION *dcs_list; +static D_CRITICAL_SECTION critical_section; +static pthread_mutexattr_t _criticals_attr; + +void _STI_critical_init(void); +void _STD_critical_term(void); + +void _d_criticalenter(D_CRITICAL_SECTION *dcs) +{ + if (!dcs_list) + { _STI_critical_init(); + atexit(_STD_critical_term); + } + //printf("_d_criticalenter(dcs = x%x)\n", dcs); + if (!dcs->next) + { + pthread_mutex_lock(&critical_section.cs); + if (!dcs->next) // if, in the meantime, another thread didn't set it + { + dcs->next = dcs_list; + dcs_list = dcs; + pthread_mutex_init(&dcs->cs, &_criticals_attr); + } + pthread_mutex_unlock(&critical_section.cs); + } + pthread_mutex_lock(&dcs->cs); +} + +void _d_criticalexit(D_CRITICAL_SECTION *dcs) +{ + //printf("_d_criticalexit(dcs = x%x)\n", dcs); + pthread_mutex_unlock(&dcs->cs); +} + +void _STI_critical_init() +{ + if (!dcs_list) + { //printf("_STI_critical_init()\n"); + pthread_mutexattr_init(&_criticals_attr); + pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE_NP); + + // The global critical section doesn't need to be recursive + pthread_mutex_init(&critical_section.cs, 0); + dcs_list = &critical_section; + } +} + +void _STD_critical_term() +{ + if (dcs_list) + { //printf("_STI_critical_term()\n"); + while (dcs_list) + { + //printf("\tlooping... %x\n", dcs_list); + pthread_mutex_destroy(&dcs_list->cs); + dcs_list = dcs_list->next; + } + } +} + +#endif diff --git a/src/compiler/dmd/deh.c b/src/compiler/dmd/deh.c new file mode 100644 index 0000000..12c2fd9 --- /dev/null +++ b/src/compiler/dmd/deh.c @@ -0,0 +1,657 @@ +// +// Copyright (c) 1999-2003 by Digital Mars, www.digitalmars.com +// All Rights Reserved +// Written by Walter Bright + +// Exception handling support + +#include +#include +#include +#include + +/* ======================== Win32 =============================== */ + +#if _WIN32 + +#include +#include + +//#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 D9Exception7__ClassZ; + +#define _Class_9Exception D9Exception7__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_9Exception; + } + + 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) +{ + Exception *exc; + + exc = (Exception *)_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_9Exception, "Integer Divide by Zero"); + break; + + case STATUS_FLOAT_DIVIDE_BY_ZERO: + pti = _d_create_exception_object(&_Class_9Exception, "Float Divide by Zero"); + break; + + case STATUS_ACCESS_VIOLATION: + pti = _d_create_exception_object(&_Class_9Exception, "Access Violation"); + break; + + case STATUS_STACK_OVERFLOW: + pti = _d_create_exception_object(&_Class_9Exception, "Stack Overflow"); + break; + + // convert all other exception codes into a Win32Exception + default: + pti = _d_create_exception_object(&_Class_9Exception, "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 D9Exception7__ClassZ; + +#define _Class_9Exception D9Exception7__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 diff --git a/src/compiler/dmd/deh2.d b/src/compiler/dmd/deh2.d new file mode 100644 index 0000000..54ae17f --- /dev/null +++ b/src/compiler/dmd/deh2.d @@ -0,0 +1,308 @@ +/* + * Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module rt.deh2; + +// Exception handling support for linux + +//debug=1; + +extern (C) +{ + extern void* _deh_beg; + extern 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; + + asm + { + push EBX ; + mov EBX,blockaddr ; + push EBP ; + mov EBP,regebp ; + call EBX ; + pop EBP ; + pop EBX ; + } + } + } + } +} diff --git a/src/compiler/dmd/dmain2.d b/src/compiler/dmd/dmain2.d new file mode 100644 index 0000000..9527929 --- /dev/null +++ b/src/compiler/dmd/dmain2.d @@ -0,0 +1,304 @@ +/* + * 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 util.console; + import stdc.stddef; + import stdc.stdlib; + import stdc.string; +} + +version( Windows ) +{ + 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 functions must be defined for any D program linked + * against this library. + */ +extern (C) void onAssertError( char[] file, size_t line ); +extern (C) void onAssertErrorMsg( char[] file, size_t line, char[] msg ); +extern (C) void onArrayBoundsError( char[] file, size_t line ); +extern (C) void onSwitchError( char[] file, size_t line ); +extern (C) bool runModuleUnitTests(); + +// this function is called from the utf module +//extern (C) void onUnicodeError( char[] msg, size_t idx ); + +/*********************************** + * These are internal callbacks for various language errors. + */ +extern (C) void _d_assert( char[] file, uint line ) +{ + onAssertError( file, line ); +} + +extern (C) static void _d_assert_msg( char[] msg, char[] file, uint line ) +{ + onAssertErrorMsg( file, line, msg ); +} + +extern (C) void _d_array_bounds( char[] file, uint line ) +{ + onArrayBoundsError( file, line ); +} + +extern (C) void _d_switch_error( char[] file, uint line ) +{ + onSwitchError( file, line ); +} + +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( Exception ) ExceptionHandler; + +extern (C) bool rt_init( ExceptionHandler dg = null ) +{ + _d_criticalInit(); + + try + { + gc_init(); + version (Windows) + _minit(); + _moduleCtor(); + return true; + } + catch( Exception 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( Exception 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 (Exception 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.toString)("\n"); + } + else + { + // fprintf(stderr, "%.*s\n", e.toString()); + console (e.classinfo.name)(": ")(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(); + 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; +} diff --git a/src/compiler/dmd/invariant_.d b/src/compiler/dmd/invariant_.d new file mode 100644 index 0000000..f5a3c50 --- /dev/null +++ b/src/compiler/dmd/invariant_.d @@ -0,0 +1,25 @@ +/* + * Placed into the Public Domain + * written by Walter Bright + * www.digitalmars.com + */ +module rt.invariant_; + +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); +} diff --git a/src/compiler/dmd/lifetime.d b/src/compiler/dmd/lifetime.d new file mode 100644 index 0000000..55861b0 --- /dev/null +++ b/src/compiler/dmd/lifetime.d @@ -0,0 +1,1051 @@ +/** + * This module contains all functions related to an object's lifetime: + * allocation, resizing, deallocation, and finalization. + * + * Copyright: Copyright (C) 2004-2007 Digital Mars, www.digitalmars.com. + * All rights reserved. + * License: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + * Authors: Walter Bright, Sean Kelly + */ +module rt.lifetime; + + +private +{ + import stdc.stdlib; + import stdc.string; + import stdc.stdarg; + debug(PRINTF) import stdc.stdio; +} + + +private +{ + enum BlkAttr : uint + { + FINALIZE = 0b0000_0001, + NO_SCAN = 0b0000_0010, + NO_MOVE = 0b0000_0100, + ALL_BITS = 0b1111_1111 + } + + struct BlkInfo + { + void* base; + size_t size; + uint attr; + } + + extern (C) uint gc_getAttr( void* p ); + extern (C) uint gc_setAttr( void* p, uint a ); + extern (C) uint gc_clrAttr( void* p, uint a ); + + extern (C) void* gc_malloc( size_t sz, uint ba = 0 ); + extern (C) void* gc_calloc( size_t sz, uint ba = 0 ); + extern (C) size_t gc_extend( void* p, size_t mx, size_t sz ); + extern (C) void gc_free( void* p ); + + extern (C) void* gc_addrOf( void* p ); + extern (C) size_t gc_sizeOf( void* p ); + extern (C) BlkInfo gc_query( void* p ); + + extern (C) void onFinalizeError( ClassInfo c, Exception e ); + extern (C) void onOutOfMemoryError(); + + extern (C) void _d_monitordelete(Object h, bool det = true); + + enum + { + PAGESIZE = 4096 + } + + alias bool function(Object) CollectHandler; + CollectHandler collectHandler = null; +} + + +/** + * + */ +extern (C) Object _d_newclass(ClassInfo ci) +{ + void* p; + + debug(PRINTF) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name); + if (ci.flags & 1) // if COM object + { /* COM objects are not garbage collected, they are reference counted + * using AddRef() and Release(). They get free'd by C's free() + * function called by Release() when Release()'s reference count goes + * to zero. + */ + p = malloc(ci.init.length); + if (!p) + onOutOfMemoryError(); + } + else + { + p = gc_malloc(ci.init.length, + BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0)); + debug(PRINTF) printf(" p = %p\n", p); + } + + debug(PRINTF) + { + printf("p = %p\n", p); + printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length); + printf("vptr = %p\n", *cast(void**) ci.init); + printf("vtbl[0] = %p\n", (*cast(void***) ci.init)[0]); + printf("vtbl[1] = %p\n", (*cast(void***) ci.init)[1]); + printf("init[0] = %x\n", (cast(uint*) ci.init)[0]); + printf("init[1] = %x\n", (cast(uint*) ci.init)[1]); + printf("init[2] = %x\n", (cast(uint*) ci.init)[2]); + printf("init[3] = %x\n", (cast(uint*) ci.init)[3]); + printf("init[4] = %x\n", (cast(uint*) ci.init)[4]); + } + + // initialize it + (cast(byte*) p)[0 .. ci.init.length] = ci.init[]; + + debug(PRINTF) printf("initialization done\n"); + return cast(Object) p; +} + + +/** + * + */ +extern (C) void _d_delinterface(void** p) +{ + if (*p) + { + Interface* pi = **cast(Interface ***)*p; + Object o = cast(Object)(*p - pi.offset); + + _d_delclass(&o); + *p = null; + } +} + + +// used for deletion +private extern (D) alias void (*fp_t)(Object); + + +/** + * + */ +extern (C) void _d_delclass(Object* p) +{ + if (*p) + { + debug(PRINTF) printf("_d_delclass(%p)\n", *p); + + ClassInfo **pc = cast(ClassInfo **)*p; + if (*pc) + { + ClassInfo c = **pc; + + rt_finalize(cast(void*) *p); + + if (c.deallocator) + { + fp_t fp = cast(fp_t)c.deallocator; + (*fp)(*p); // call deallocator + *p = null; + return; + } + } + else + { + rt_finalize(cast(void*) *p); + } + gc_free(cast(void*) *p); + *p = null; + } +} + + +/** + * Allocate a new array of length elements. + * ti is the type of the resulting array, or pointer to element. + * (For when the array is initialized to 0) + */ +extern (C) ulong _d_newarrayT(TypeInfo ti, size_t length) +{ + void* p; + ulong result; + auto size = ti.next.tsize(); // array element size + + debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size); + if (length == 0 || size == 0) + result = 0; + else + { + version (D_InlineAsm_X86) + { + asm + { + mov EAX,size ; + mul EAX,length ; + mov size,EAX ; + jc Loverflow ; + } + } + else + size *= length; + p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); + debug(PRINTF) printf(" p = %p\n", p); + memset(p, 0, size); + result = cast(ulong)length + (cast(ulong)cast(uint)p << 32); + } + return result; + +Loverflow: + onOutOfMemoryError(); +} + +/** + * For when the array has a non-zero initializer. + */ +extern (C) ulong _d_newarrayiT(TypeInfo ti, size_t length) +{ + ulong result; + auto size = ti.next.tsize(); // array element size + + debug(PRINTF) printf("_d_newarrayiT(length = %d, size = %d)\n", length, size); + + if (length == 0 || size == 0) + result = 0; + else + { + auto initializer = ti.next.init(); + auto isize = initializer.length; + auto q = initializer.ptr; + version (D_InlineAsm_X86) + { + asm + { + mov EAX,size ; + mul EAX,length ; + mov size,EAX ; + jc Loverflow ; + } + } + else + size *= length; + auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); + debug(PRINTF) printf(" p = %p\n", p); + if (isize == 1) + memset(p, *cast(ubyte*)q, size); + else if (isize == int.sizeof) + { + int init = *cast(int*)q; + size /= int.sizeof; + for (size_t u = 0; u < size; u++) + { + (cast(int*)p)[u] = init; + } + } + else + { + for (size_t u = 0; u < size; u += isize) + { + memcpy(p + u, q, isize); + } + } + va_end(q); + result = cast(ulong)length + (cast(ulong)cast(uint)p << 32); + } + return result; + +Loverflow: + onOutOfMemoryError(); +} + +/** + * + */ +extern (C) ulong _d_newarraymT(TypeInfo ti, int ndims, ...) +{ + ulong result; + + debug(PRINTF) printf("_d_newarraymT(ndims = %d)\n", ndims); + if (ndims == 0) + result = 0; + else + { va_list q; + va_start!(int)(q, ndims); + + void[] foo(TypeInfo ti, size_t* pdim, int ndims) + { + size_t dim = *pdim; + void[] p; + + debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims); + if (ndims == 1) + { + auto r = _d_newarrayT(ti, dim); + p = *cast(void[]*)(&r); + } + else + { + p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim]; + for (int i = 0; i < dim; i++) + { + (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1); + } + } + return p; + } + + size_t* pdim = cast(size_t *)q; + result = cast(ulong)foo(ti, pdim, ndims); + debug(PRINTF) printf("result = %llx\n", result); + + version (none) + { + for (int i = 0; i < ndims; i++) + { + printf("index %d: %d\n", i, va_arg!(int)(q)); + } + } + va_end(q); + } + return result; +} + + +/** + * + */ +extern (C) ulong _d_newarraymiT(TypeInfo ti, int ndims, ...) +{ + ulong result; + + debug(PRINTF) printf("_d_newarraymiT(ndims = %d)\n", ndims); + if (ndims == 0) + result = 0; + else + { + va_list q; + va_start!(int)(q, ndims); + + void[] foo(TypeInfo ti, size_t* pdim, int ndims) + { + size_t dim = *pdim; + void[] p; + + if (ndims == 1) + { + auto r = _d_newarrayiT(ti, dim); + p = *cast(void[]*)(&r); + } + else + { + p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim]; + for (int i = 0; i < dim; i++) + { + (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1); + } + } + return p; + } + + size_t* pdim = cast(size_t *)q; + result = cast(ulong)foo(ti, pdim, ndims); + debug(PRINTF) printf("result = %llx\n", result); + + version (none) + { + for (int i = 0; i < ndims; i++) + { + printf("index %d: %d\n", i, va_arg!(int)(q)); + printf("init = %d\n", va_arg!(int)(q)); + } + } + va_end(q); + } + return result; +} + + +/** + * + */ +struct Array +{ + size_t length; + byte* data; +} + + +/** + * + */ +void* _d_allocmemory(size_t nbytes) +{ + return gc_malloc(nbytes); +} + + +/** + * + */ +extern (C) void _d_delarray(Array *p) +{ + if (p) + { + assert(!p.length || p.data); + + if (p.data) + gc_free(p.data); + p.data = null; + p.length = 0; + } +} + + +/** + * + */ +extern (C) void _d_delmemory(void* *p) +{ + if (*p) + { + gc_free(*p); + *p = null; + } +} + + +/** + * + */ +extern (C) void _d_callinterfacefinalizer(void *p) +{ + if (p) + { + Interface *pi = **cast(Interface ***)p; + Object o = cast(Object)(p - pi.offset); + rt_finalize(cast(void*)o); + } +} + + +/** + * + */ +extern (C) void _d_callfinalizer(void* p) +{ + rt_finalize( p ); +} + + +/** + * + */ +extern (C) void rt_setCollectHandler(CollectHandler h) +{ + collectHandler = h; +} + + +/** + * + */ +extern (C) void rt_finalize(void* p, bool det = true) +{ + debug(PRINTF) printf("rt_finalize(p = %p)\n", p); + + if (p) // not necessary if called from gc + { + ClassInfo** pc = cast(ClassInfo**)p; + + if (*pc) + { + ClassInfo c = **pc; + + try + { + if (det || collectHandler is null || collectHandler(cast(Object)p)) + { + do + { + if (c.destructor) + { + fp_t fp = cast(fp_t)c.destructor; + (*fp)(cast(Object)p); // call destructor + } + c = c.base; + } while (c); + } + if ((cast(void**)p)[1]) // if monitor is not null + _d_monitordelete(cast(Object)p, det); + } + catch (Exception e) + { + onFinalizeError(**pc, e); + } + finally + { + *pc = null; // zero vptr + } + } + } +} + + +/** + * Resize dynamic arrays with 0 initializers. + */ +extern (C) byte[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, Array *p) +in +{ + assert(ti); + assert(!p.length || p.data); +} +body +{ + byte* newdata; + size_t sizeelem = ti.next.tsize(); + + debug(PRINTF) + { + printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength); + if (p) + printf("\tp.data = %p, p.length = %d\n", p.data, p.length); + } + + if (newlength) + { + version (D_InlineAsm_X86) + { + size_t newsize = void; + + asm + { + mov EAX, newlength; + mul EAX, sizeelem; + mov newsize, EAX; + jc Loverflow; + } + } + else + { + size_t newsize = sizeelem * newlength; + + if (newsize / newlength != sizeelem) + goto Loverflow; + } + + debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength); + + if (p.data) + { + newdata = p.data; + if (newlength > p.length) + { + size_t size = p.length * sizeelem; + auto info = gc_query(p.data); + + if (info.size <= newsize || info.base != p.data) + { + if (info.size >= PAGESIZE && info.base == p.data) + { // Try to extend in-place + auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size); + if (u) + { + goto L1; + } + } + newdata = cast(byte *)gc_malloc(newsize + 1, info.attr); + newdata[0 .. size] = p.data[0 .. size]; + } + L1: + newdata[size .. newsize] = 0; + } + } + else + { + newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); + } + } + else + { + newdata = p.data; + } + + p.data = newdata; + p.length = newlength; + return newdata[0 .. newlength]; + +Loverflow: + onOutOfMemoryError(); +} + + +/** + * Resize arrays for non-zero initializers. + * p pointer to array lvalue to be updated + * newlength new .length property of array + * sizeelem size of each element of array + * initsize size of initializer + * ... initializer + */ +extern (C) byte[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, Array *p) +in +{ + assert(!p.length || p.data); +} +body +{ + byte* newdata; + size_t sizeelem = ti.next.tsize(); + void[] initializer = ti.next.init(); + size_t initsize = initializer.length; + + assert(sizeelem); + assert(initsize); + assert(initsize <= sizeelem); + assert((sizeelem / initsize) * initsize == sizeelem); + + debug(PRINTF) + { + printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize); + if (p) + printf("\tp.data = %p, p.length = %d\n", p.data, p.length); + } + + if (newlength) + { + version (D_InlineAsm_X86) + { + size_t newsize = void; + + asm + { + mov EAX,newlength ; + mul EAX,sizeelem ; + mov newsize,EAX ; + jc Loverflow ; + } + } + else + { + size_t newsize = sizeelem * newlength; + + if (newsize / newlength != sizeelem) + goto Loverflow; + } + debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength); + + size_t size = p.length * sizeelem; + + if (p.data) + { + newdata = p.data; + if (newlength > p.length) + { + auto info = gc_query(p.data); + + if (info.size <= newsize || info.base != p.data) + { + if (info.size >= PAGESIZE && info.base == p.data) + { // Try to extend in-place + auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size); + if (u) + { + goto L1; + } + } + newdata = cast(byte *)gc_malloc(newsize + 1, info.attr); + newdata[0 .. size] = p.data[0 .. size]; + L1: ; + } + } + } + else + { + newdata = cast(byte *)gc_malloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); + } + + auto q = initializer.ptr; // pointer to initializer + + if (newsize > size) + { + if (initsize == 1) + { + debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q); + newdata[size .. newsize] = *(cast(byte*)q); + } + else + { + for (size_t u = size; u < newsize; u += initsize) + { + memcpy(newdata + u, q, initsize); + } + } + } + } + else + { + newdata = p.data; + } + + p.data = newdata; + p.length = newlength; + return newdata[0 .. newlength]; + +Loverflow: + onOutOfMemoryError(); +} + + +/** + * Append y[] to array x[]. + * size is size of each array element. + */ +extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y) +{ + auto sizeelem = ti.next.tsize(); // array element size + auto info = gc_query(px.data); + auto length = px.length; + auto newlength = length + y.length; + auto newsize = newlength * sizeelem; + + if (info.size < newsize || info.base != px.data) + { byte* newdata; + + if (info.size >= PAGESIZE && info.base == px.data) + { // Try to extend in-place + auto u = gc_extend(px.data, (newsize + 1) - info.size, (newsize + 1) - info.size); + if (u) + { + goto L1; + } + } + newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr); + memcpy(newdata, px.data, length * sizeelem); + px.data = newdata; + } + L1: + px.length = newlength; + memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem); + return *cast(long*)px; +} + + +/** + * + */ +size_t newCapacity(size_t newlength, size_t size) +{ + version(none) + { + size_t newcap = newlength * size; + } + else + { + /* + * Better version by Dave Fladebo: + * This uses an inverse logorithmic algorithm to pre-allocate a bit more + * space for larger arrays. + * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most + * common cases, memory allocation is 1 to 1. The small overhead added + * doesn't affect small array perf. (it's virtually the same as + * current). + * - Larger arrays have some space pre-allocated. + * - As the arrays grow, the relative pre-allocated space shrinks. + * - The logorithmic algorithm allocates relatively more space for + * mid-size arrays, making it very fast for medium arrays (for + * mid-to-large arrays, this turns out to be quite a bit faster than the + * equivalent realloc() code in C, on Linux at least. Small arrays are + * just as fast as GCC). + * - Perhaps most importantly, overall memory usage and stress on the GC + * is decreased significantly for demanding environments. + */ + size_t newcap = newlength * size; + size_t newext = 0; + + if (newcap > PAGESIZE) + { + //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0))); + + // redo above line using only integer math + + static int log2plus1(size_t c) + { int i; + + if (c == 0) + i = -1; + else + for (i = 1; c >>= 1; i++) + { + } + return i; + } + + /* The following setting for mult sets how much bigger + * the new size will be over what is actually needed. + * 100 means the same size, more means proportionally more. + * More means faster but more memory consumption. + */ + //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap)); + long mult = 100 + (1000L * size) / log2plus1(newcap); + + // testing shows 1.02 for large arrays is about the point of diminishing return + if (mult < 102) + mult = 102; + newext = cast(size_t)((newcap * mult) / 100); + newext -= newext % size; + debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size); + } + newcap = newext > newcap ? newext : newcap; + debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size); + } + return newcap; +} + + +/** + * + */ +extern (C) byte[] _d_arrayappendcT(TypeInfo ti, inout byte[] x, ...) +{ + auto sizeelem = ti.next.tsize(); // array element size + auto info = gc_query(x.ptr); + auto length = x.length; + auto newlength = length + 1; + auto newsize = newlength * sizeelem; + + assert(info.size == 0 || length * sizeelem <= info.size); + + debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size); + + if (info.size <= newsize || info.base != x.ptr) + { byte* newdata; + + if (info.size >= PAGESIZE && info.base == x.ptr) + { // Try to extend in-place + auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size); + if (u) + { + goto L1; + } + } + debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size); + auto newcap = newCapacity(newlength, sizeelem); + assert(newcap >= newlength * sizeelem); + newdata = cast(byte *)gc_malloc(newcap + 1, info.attr); + memcpy(newdata, x.ptr, length * sizeelem); + (cast(void**)(&x))[1] = newdata; + } + L1: + byte *argp = cast(byte *)(&ti + 2); + + *cast(size_t *)&x = newlength; + x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem]; + assert((cast(size_t)x.ptr & 15) == 0); + assert(gc_sizeOf(x.ptr) > x.length * sizeelem); + return x; +} + + +/** + * + */ +extern (C) byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y) +out (result) +{ + auto sizeelem = ti.next.tsize(); // array element size + debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr); + assert(result.length == x.length + y.length); + for (size_t i = 0; i < x.length * sizeelem; i++) + assert((cast(byte*)result)[i] == (cast(byte*)x)[i]); + for (size_t i = 0; i < y.length * sizeelem; i++) + assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]); + + size_t cap = gc_sizeOf(result.ptr); + assert(!cap || cap > result.length * sizeelem); +} +body +{ + version (none) + { + /* Cannot use this optimization because: + * char[] a, b; + * char c = 'a'; + * b = a ~ c; + * c = 'b'; + * will change the contents of b. + */ + if (!y.length) + return x; + if (!x.length) + return y; + } + + debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr); + auto sizeelem = ti.next.tsize(); // array element size + debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem); + size_t xlen = x.length * sizeelem; + size_t ylen = y.length * sizeelem; + size_t len = xlen + ylen; + + if (!len) + return null; + + byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); + memcpy(p, x.ptr, xlen); + memcpy(p + xlen, y.ptr, ylen); + p[len] = 0; + return p[0 .. x.length + y.length]; +} + + +/** + * + */ +extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...) +{ void* a; + size_t length; + byte[]* p; + uint i; + byte[] b; + auto size = ti.next.tsize(); // array element size + + p = cast(byte[]*)(&n + 1); + + for (i = 0; i < n; i++) + { + b = *p++; + length += b.length; + } + if (!length) + return null; + + a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); + p = cast(byte[]*)(&n + 1); + + uint j = 0; + for (i = 0; i < n; i++) + { + b = *p++; + if (b.length) + { + memcpy(a + j, b.ptr, b.length * size); + j += b.length * size; + } + } + + byte[] result; + *cast(int *)&result = length; // jam length + (cast(void **)&result)[1] = a; // jam ptr + return result; +} + + +/** + * + */ +extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...) +{ + auto sizeelem = ti.next.tsize(); // array element size + void* result; + + debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length); + if (length == 0 || sizeelem == 0) + result = null; + else + { + result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); + + va_list q; + va_start!(size_t)(q, length); + + size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1); + + if (stacksize == sizeelem) + { + memcpy(result, q, length * sizeelem); + } + else + { + for (size_t i = 0; i < length; i++) + { + memcpy(result + i * sizeelem, q, sizeelem); + q += stacksize; + } + } + + va_end(q); + } + return result; +} + + +/** + * Support for array.dup property. + */ +struct Array2 +{ + size_t length; + void* ptr; +} + + +/** + * + */ +extern (C) long _adDupT(TypeInfo ti, Array2 a) +out (result) +{ + auto sizeelem = ti.next.tsize(); // array element size + assert(memcmp((*cast(Array2*)&result).ptr, a.ptr, a.length * sizeelem) == 0); +} +body +{ + Array2 r; + + if (a.length) + { + auto sizeelem = ti.next.tsize(); // array element size + auto size = a.length * sizeelem; + r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); + r.length = a.length; + memcpy(r.ptr, a.ptr, size); + } + return *cast(long*)(&r); +} + + +unittest +{ + int[] a; + int[] b; + int i; + + a = new int[3]; + a[0] = 1; a[1] = 2; a[2] = 3; + b = a.dup; + assert(b.length == 3); + for (i = 0; i < 3; i++) + assert(b[i] == i + 1); +} diff --git a/src/compiler/dmd/llmath.d b/src/compiler/dmd/llmath.d new file mode 100644 index 0000000..b85e087 --- /dev/null +++ b/src/compiler/dmd/llmath.d @@ -0,0 +1,295 @@ +// llmath.d +// Copyright (C) 1993-2003 by Digital Mars, www.digitalmars.com +// All Rights Reserved +// Written by Walter Bright + +module rt.llmath; + +// Compiler runtime support for 64 bit longs + +extern (C): + + +/*************************************** + * Unsigned long divide. + * Input: + * [EDX,EAX],[ECX,EBX] + * Output: + * [EDX,EAX] = [EDX,EAX] / [ECX,EBX] + * [ECX,EBX] = [EDX,EAX] % [ECX,EBX] + * ESI,EDI destroyed + */ + +void __ULDIV__() +{ + asm + { + naked ; + test ECX,ECX ; + jz uldiv ; + + push EBP ; + + // left justify [ECX,EBX] and leave count of shifts + 1 in EBP + + mov EBP,1 ; // at least 1 shift + test ECX,ECX ; // left justified? + js L1 ; // yes + jnz L2 ; + add EBP,8 ; + mov CH,CL ; + mov CL,BH ; + mov BH,BL ; + xor BL,BL ; // [ECX,EBX] <<= 8 + test ECX,ECX ; + js L1 ; + even ; +L2: inc EBP ; // another shift + shl EBX,1 ; + rcl ECX,1 ; // [ECX,EBX] <<= 1 + jno L2 ; // not left justified yet + +L1: mov ESI,ECX ; + mov EDI,EBX ; // [ESI,EDI] = divisor + + mov ECX,EDX ; + mov EBX,EAX ; // [ECX,EBX] = [EDX,EAX] + xor EAX,EAX ; + cdq ; // [EDX,EAX] = 0 + even ; +L4: cmp ESI,ECX ; // is [ECX,EBX] > [ESI,EDI]? + ja L3 ; // yes + jb L5 ; // definitely less than + cmp EDI,EBX ; // check low order word + ja L3 ; +L5: sub EBX,EDI ; + sbb ECX,ESI ; // [ECX,EBX] -= [ESI,EDI] + stc ; // rotate in a 1 +L3: rcl EAX,1 ; + rcl EDX,1 ; // [EDX,EAX] = ([EDX,EAX] << 1) + C + shr ESI,1 ; + rcr EDI,1 ; // [ESI,EDI] >>= 1 + dec EBP ; // control count + jne L4 ; + pop EBP ; + ret ; + +div0: mov EAX,-1 ; + cwd ; // quotient is -1 +// xor ECX,ECX ; +// mov EBX,ECX ; // remainder is 0 (ECX and EBX already 0) + 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 ; + } +} + + +/*************************************** + * 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 real adjust = cast(real)0x800_0000_0000_0000 * 0x10; + +real __U64_LDBL() +{ + 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 short roundTo0 = 0xFBF; + +ulong __DBLULLNG() +{ + // BUG: should handle NAN's and overflows + 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 + asm + { naked ; + sub ESP,16 ; + fstcw 8[ESP] ; + fldcw roundTo0 ; + fistp qword ptr [ESP] ; + fldcw 8[ESP] ; + pop EAX ; + add ESP,12 ; + ret ; + } +} diff --git a/src/compiler/dmd/mars.h b/src/compiler/dmd/mars.h new file mode 100644 index 0000000..9990fff --- /dev/null +++ b/src/compiler/dmd/mars.h @@ -0,0 +1,104 @@ + +/* + * Placed into the Public Domain + * written by Walter Bright, Digital Mars + * www.digitalmars.com + */ + +/* + * Modified by Sean Kelly for use with Tango. + */ + +#include + +#if __cplusplus +extern "C" { +#endif + +struct ClassInfo; +struct Vtbl; + +typedef struct Vtbl +{ + size_t len; + void **vptr; +} Vtbl; + +typedef struct Interface +{ + struct ClassInfo *classinfo; + struct Vtbl vtbl; + int offset; +} Interface; + +typedef struct Object +{ + void **vptr; + void *monitor; +} Object; + +typedef struct ClassInfo +{ + Object object; + + size_t initlen; + void *init; + + size_t namelen; + char *name; + + Vtbl vtbl; + + size_t interfacelen; + Interface *interfaces; + + struct ClassInfo *baseClass; + + void *destructor; + void *invariant; + + int flags; +} ClassInfo; + +typedef struct Exception +{ + Object object; + + size_t msglen; + char* msg; + + size_t filelen; + char* file; + + size_t line; + + struct Interface *info; + struct Exception *next; +} Exception; + +typedef struct Array +{ + size_t length; + void *ptr; +} Array; + +typedef struct Delegate +{ + void *thisptr; + void (*funcptr)(); +} Delegate; + +void _d_monitorenter(Object *h); +void _d_monitorexit(Object *h); + +int _d_isbaseof(ClassInfo *b, ClassInfo *c); +Object *_d_dynamic_cast(Object *o, ClassInfo *ci); + +Object * _d_newclass(ClassInfo *ci); +void _d_delclass(Object **p); + +void _d_OutOfMemory(); + +#if __cplusplus +} +#endif diff --git a/src/compiler/dmd/memory.d b/src/compiler/dmd/memory.d new file mode 100644 index 0000000..7ed28b6 --- /dev/null +++ b/src/compiler/dmd/memory.d @@ -0,0 +1,155 @@ +/** + * This module exposes functionality for inspecting and manipulating memory. + * + * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. + * All rights reserved. + * License: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + * Authors: Walter Bright, Sean Kelly + */ +module rt.memory; + + +private +{ + version( linux ) + { + version = SimpleLibcStackEnd; + + version( SimpleLibcStackEnd ) + { + extern (C) extern void* __libc_stack_end; + } + } +} + + +/** + * + */ +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 + { + 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 int _xi_a; // &_xi_a just happens to be start of data segment + extern int _edata; // &_edata is start of BSS segment + extern int _end; // &_end is past end of BSS + } + } + else version( linux ) + { + extern (C) + { + extern int _data; + extern int __data_start; + extern int _end; + extern int _data_start__; + extern int _data_end__; + extern int _bss_start__; + extern int _bss_end__; + extern int __fini_array_end; + } + + alias __data_start Data_Start; + alias _end Data_End; + } + + alias void delegate( void*, void* ) scanFn; +} + + +/** + * + */ +extern (C) void rt_scanStaticData( scanFn scan ) +{ + version( Windows ) + { + scan( &_xi_a, &_end ); + } + else version( linux ) + { + scan( &__data_start, &_end ); + } + else + { + static assert( false, "Operating system not supported." ); + } +} diff --git a/src/compiler/dmd/memset.d b/src/compiler/dmd/memset.d new file mode 100644 index 0000000..ebe6586 --- /dev/null +++ b/src/compiler/dmd/memset.d @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2004 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ +module rt.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; +} diff --git a/src/compiler/dmd/minit.asm b/src/compiler/dmd/minit.asm new file mode 100644 index 0000000..4bf977d --- /dev/null +++ b/src/compiler/dmd/minit.asm @@ -0,0 +1,79 @@ +;_ minit.asm +; Written by Walter Bright +; Digital Mars +; http://www.digitalmars.com/d/ +; Placed into the Public Domain + +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 diff --git a/src/compiler/dmd/minit.obj b/src/compiler/dmd/minit.obj new file mode 100644 index 0000000000000000000000000000000000000000..bd328c5d8143bee2280cb9e84a2090052ce4deca GIT binary patch literal 319 zcmZn=VGzp9D@iTNOU#MM&CJUz(Mv4O6`W?lz`*9>9^@Yyz~tu36yeY8=IaE+uFOus z!ORizOY;~2skAL1GjGI<6&!%7AQRxZXB5Ee5R<0=S?jf-(P zgvG%Qk!4|EfwCAFIN8CnnbHir+>A$NaWF9bXZ+9fpE+_C69Z2~k0^sse0*+xN@-4N zW?ou;d}2{iVkN`<349C;?Cd}pkkc6$7)mDy0ZE`~@$q@3IXS5nAi?eq76yhzj29Pj zF|dMVfkePUMFw^dXBUXr0U|m@L8SJfgD;pCgII?(=Sng>VH9Cve8MKe#QcOuh=~zs R5W^EOF(yX+E+z(s5&*owO921? literal 0 HcmV?d00001 diff --git a/src/compiler/dmd/monitor.c b/src/compiler/dmd/monitor.c new file mode 100644 index 0000000..52f6003 --- /dev/null +++ b/src/compiler/dmd/monitor.c @@ -0,0 +1,208 @@ +// D programming language runtime library +// Public Domain +// written by Walter Bright, Digital Mars +// www.digitalmars.com + +// This is written in C because nobody has written a pthreads interface +// to D yet. + + +#include +#include +#include + +#if _WIN32 +#elif linux +#define USE_PTHREADS 1 +#else +#endif + +#if _WIN32 +#include +#endif + +#if USE_PTHREADS +#include +#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 + +// Includes attribute fixes from David Friedman's GDC port + +static pthread_mutex_t _monitor_critsec; +static pthread_mutexattr_t _monitors_attr; + +void _STI_monitor_staticctor() +{ + if (!inited) + { + pthread_mutexattr_init(&_monitors_attr); + pthread_mutexattr_settype(&_monitors_attr, PTHREAD_MUTEX_RECURSIVE_NP); + pthread_mutex_init(&_monitor_critsec, 0); + inited = 1; + } +} + +void _STD_monitor_staticdtor() +{ + if (inited) + { inited = 0; + pthread_mutex_destroy(&_monitor_critsec); + pthread_mutexattr_destroy(&_monitors_attr); + } +} + +void _d_monitor_create(Object *h) +{ + /* + * NOTE: Assume this is only called when h->monitor is null prior to the + * call. However, please note that another thread may call this function + * at the same time, so we can not assert this here. Instead, try and + * create a lock, and if one already exists then forget about it. + */ + + //printf("+_d_monitor_create(%p)\n", h); + assert(h); + Monitor *cs = NULL; + pthread_mutex_lock(&_monitor_critsec); + if (!h->monitor) + { + cs = (Monitor *)calloc(sizeof(Monitor), 1); + assert(cs); + pthread_mutex_init(&cs->mon, & _monitors_attr); + h->monitor = (void *)cs; + cs = NULL; + } + pthread_mutex_unlock(&_monitor_critsec); + if (cs) + free(cs); + //printf("-_d_monitor_create(%p)\n", h); +} + +void _d_monitor_destroy(Object *h) +{ + //printf("+_d_monitor_destroy(%p)\n", h); + assert(h && h->monitor && !(((Monitor*)h->monitor)->impl)); + pthread_mutex_destroy(MONPTR(h)); + free((void *)h->monitor); + h->monitor = NULL; + //printf("-_d_monitor_destroy(%p)\n", h); +} + +int _d_monitor_lock(Object *h) +{ + //printf("+_d_monitor_acquire(%p)\n", h); + assert(h && h->monitor && !(((Monitor*)h->monitor)->impl)); + pthread_mutex_lock(MONPTR(h)); + //printf("-_d_monitor_acquire(%p)\n", h); +} + +void _d_monitor_unlock(Object *h) +{ + //printf("+_d_monitor_release(%p)\n", h); + assert(h && h->monitor && !(((Monitor*)h->monitor)->impl)); + pthread_mutex_unlock(MONPTR(h)); + //printf("-_d_monitor_release(%p)\n", h); +} + +#endif diff --git a/src/compiler/dmd/obj.d b/src/compiler/dmd/obj.d new file mode 100644 index 0000000..57bc037 --- /dev/null +++ b/src/compiler/dmd/obj.d @@ -0,0 +1,27 @@ +// Copyright (c) 2002 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// www.digitalmars.com + +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); +} diff --git a/src/compiler/dmd/object_.d b/src/compiler/dmd/object_.d new file mode 100644 index 0000000..3f9ddd2 --- /dev/null +++ b/src/compiler/dmd/object_.d @@ -0,0 +1,1307 @@ +/** + * Part of the D programming language runtime library. + * Forms the symbols available to all D programs. Includes + * Object, which is the root of the class object hierarchy. + * + * This module is implicitly imported. + * Macros: + * WIKI = Object + */ + +/* + * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module object; + +private +{ + import stdc.string; + import stdc.stdlib; + import util.string; + debug(PRINTF) import stdc.stdio; + + extern (C) void onOutOfMemoryError(); + extern (C) Object _d_newclass(ClassInfo ci); +} + +// NOTE: For some reason, this declaration method doesn't work +// in this particular file (and this file only). It must +// be a DMD thing. +//alias typeof(int.sizeof) size_t; +//alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; + +version( X86_64 ) +{ + alias ulong size_t; + alias long ptrdiff_t; +} +else +{ + alias uint size_t; + alias int ptrdiff_t; +} + +alias size_t hash_t; +alias int equals_t; + +alias char[] string; +alias wchar[] wstring; +alias dchar[] dstring; + +/** + * All D class objects inherit from Object. + */ +class Object +{ + /** + * Convert Object to a human readable string. + */ + string toString() + { + return this.classinfo.name; + } + + /** + * Compute hash function for Object. + */ + hash_t toHash() + { + // BUG: this prevents a compacting GC from working, needs to be fixed + return cast(hash_t)cast(void*)this; + } + + /** + * Compare with another Object obj. + * Returns: + * $(TABLE + * $(TR $(TD this < obj) $(TD < 0)) + * $(TR $(TD this == obj) $(TD 0)) + * $(TR $(TD this > obj) $(TD > 0)) + * ) + */ + int opCmp(Object o) + { + // BUG: this prevents a compacting GC from working, needs to be fixed + //return cast(int)cast(void*)this - cast(int)cast(void*)o; + + //throw new Exception("need opCmp for class " ~ this.classinfo.name); + return this !is o; + } + + /** + * Returns !=0 if this object does have the same contents as obj. + */ + equals_t opEquals(Object o) + { + return this is o; + } + + interface Monitor + { + void lock(); + void unlock(); + } +} + +/** + * Information about an interface. + * When an object is accessed via an interface, an Interface* appears as the + * first entry in its vtbl. + */ +struct Interface +{ + ClassInfo classinfo; /// .classinfo for this interface (not for containing class) + void*[] vtbl; + ptrdiff_t offset; /// offset to Interface 'this' from Object 'this' +} + +/** + * Runtime type information about a class. Can be retrieved for any class type + * or instance by using the .classinfo property. + * A pointer to this appears as the first entry in the class's vtbl[]. + */ +class ClassInfo : Object +{ + byte[] init; /** class static initializer + * (init.length gives size in bytes of class) + */ + string name; /// class name + void*[] vtbl; /// virtual function pointer table + Interface[] interfaces; /// interfaces this class implements + ClassInfo base; /// base class + void* destructor; + void function(Object) classInvariant; + uint flags; + // 1: // is IUnknown or is derived from IUnknown + // 2: // has no possible pointers into GC memory + // 4: // has offTi[] member + // 8: // has constructors + void* deallocator; + OffsetTypeInfo[] offTi; + void function(Object) defaultConstructor; // default Constructor + + /** + * Search all modules for ClassInfo corresponding to classname. + * Returns: null if not found + */ + static ClassInfo find(in char[] classname) + { + foreach (m; ModuleInfo) + { + //writefln("module %s, %d", m.name, m.localClasses.length); + foreach (c; m.localClasses) + { + //writefln("\tclass %s", c.name); + if (c.name == classname) + return c; + } + } + return null; + } + + /** + * Create instance of Object represented by 'this'. + */ + Object create() + { + if (flags & 8 && !defaultConstructor) + return null; + Object o = _d_newclass(this); + if (flags & 8 && defaultConstructor) + { + defaultConstructor(o); + } + return o; + } +} + +/** + * Array of pairs giving the offset and type information for each + * member in an aggregate. + */ +struct OffsetTypeInfo +{ + size_t offset; /// Offset of member from start of object + TypeInfo ti; /// TypeInfo for this member +} + +/** + * Runtime type information about a type. + * Can be retrieved for any type using a + * TypeidExpression. + */ +class TypeInfo +{ + hash_t toHash() + { hash_t hash; + + foreach (char c; this.toString()) + hash = hash * 9 + c; + return hash; + } + + int opCmp(Object o) + { + if (this is o) + return 0; + TypeInfo ti = cast(TypeInfo)o; + if (ti is null) + return 1; + return dstrcmp(this.toString(), ti.toString()); + } + + equals_t opEquals(Object o) + { + /* TypeInfo instances are singletons, but duplicates can exist + * across DLL's. Therefore, comparing for a name match is + * sufficient. + */ + if (this is o) + return true; + TypeInfo ti = cast(TypeInfo)o; + return ti && this.toString() == ti.toString(); + } + + /// Returns a hash of the instance of a type. + hash_t getHash(in void* p) { return cast(hash_t)p; } + + /// Compares two instances for equality. + equals_t equals(in void* p1, in void* p2) { return cast(int)(p1 == p2); } + + /// Compares two instances for <, ==, or >. + int compare(in void* p1, in void* p2) { return 0; } + + /// Returns size of the type. + size_t tsize() { return 0; } + + /// Swaps two instances of the type. + void swap(void* p1, void* p2) + { + size_t n = tsize(); + for (size_t i = 0; i < n; i++) + { byte t; + + t = (cast(byte *)p1)[i]; + (cast(byte *)p1)[i] = (cast(byte *)p2)[i]; + (cast(byte *)p2)[i] = t; + } + } + + /// Get TypeInfo for 'next' type, as defined by what kind of type this is, + /// null if none. + TypeInfo next() { return null; } + + /// Return default initializer, null if default initialize to 0 + void[] init() { return null; } + + /// Get flags for type: 1 means GC should scan for pointers + uint flags() { return 0; } + + /// Get type information on the contents of the type; null if not available + OffsetTypeInfo[] offTi() { return null; } +} + +class TypeInfo_Typedef : TypeInfo +{ + string toString() { return name; } + + equals_t opEquals(Object o) + { TypeInfo_Typedef c; + + return this is o || + ((c = cast(TypeInfo_Typedef)o) !is null && + this.name == c.name && + this.base == c.base); + } + + hash_t getHash(in void* p) { return base.getHash(p); } + equals_t equals(in void* p1, in void* p2) { return base.equals(p1, p2); } + int compare(in void* p1, in void* p2) { return base.compare(p1, p2); } + size_t tsize() { return base.tsize(); } + void swap(void* p1, void* p2) { return base.swap(p1, p2); } + + TypeInfo next() { return base.next(); } + uint flags() { return base.flags(); } + void[] init() { return m_init.length ? m_init : base.init(); } + + TypeInfo base; + string name; + void[] m_init; +} + +class TypeInfo_Enum : TypeInfo_Typedef +{ +} + +class TypeInfo_Pointer : TypeInfo +{ + string toString() { return m_next.toString() ~ "*"; } + + equals_t opEquals(Object o) + { TypeInfo_Pointer c; + + return this is o || + ((c = cast(TypeInfo_Pointer)o) !is null && + this.m_next == c.m_next); + } + + hash_t getHash(in void* p) + { + return cast(hash_t)*cast(void**)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return cast(int)(*cast(void* *)p1 == *cast(void* *)p2); + } + + int compare(in void* p1, in void* p2) + { + if (*cast(void* *)p1 < *cast(void* *)p2) + return -1; + else if (*cast(void* *)p1 > *cast(void* *)p2) + return 1; + else + return 0; + } + + size_t tsize() + { + return (void*).sizeof; + } + + void swap(void* p1, void* p2) + { void* tmp; + tmp = *cast(void**)p1; + *cast(void**)p1 = *cast(void**)p2; + *cast(void**)p2 = tmp; + } + + TypeInfo next() { return m_next; } + uint flags() { return 1; } + + TypeInfo m_next; +} + +class TypeInfo_Array : TypeInfo +{ + string toString() { return value.toString() ~ "[]"; } + + equals_t opEquals(Object o) + { TypeInfo_Array c; + + return this is o || + ((c = cast(TypeInfo_Array)o) !is null && + this.value == c.value); + } + + hash_t getHash(in void* p) + { size_t sz = value.tsize(); + hash_t hash = 0; + void[] a = *cast(void[]*)p; + for (size_t i = 0; i < a.length; i++) + hash += value.getHash(a.ptr + i * sz); + return hash; + } + + equals_t equals(in void* p1, in void* p2) + { + void[] a1 = *cast(void[]*)p1; + void[] a2 = *cast(void[]*)p2; + if (a1.length != a2.length) + return 0; + size_t sz = value.tsize(); + for (size_t i = 0; i < a1.length; i++) + { + if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) + return 0; + } + return 1; + } + + int compare(in void* p1, in void* p2) + { + void[] a1 = *cast(void[]*)p1; + void[] a2 = *cast(void[]*)p2; + size_t sz = value.tsize(); + size_t len = a1.length; + + if (a2.length < len) + len = a2.length; + for (size_t u = 0; u < len; u++) + { + int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz); + if (result) + return result; + } + return cast(int)a1.length - cast(int)a2.length; + } + + size_t tsize() + { + return (void[]).sizeof; + } + + void swap(void* p1, void* p2) + { void[] tmp; + tmp = *cast(void[]*)p1; + *cast(void[]*)p1 = *cast(void[]*)p2; + *cast(void[]*)p2 = tmp; + } + + TypeInfo value; + + TypeInfo next() + { + return value; +} + + uint flags() { return 1; } +} + +class TypeInfo_StaticArray : TypeInfo +{ + string toString() + { + char [10] tmp = void; + return value.toString() ~ "[" ~ tmp.intToString(len) ~ "]"; + } + + equals_t opEquals(Object o) + { TypeInfo_StaticArray c; + + return this is o || + ((c = cast(TypeInfo_StaticArray)o) !is null && + this.len == c.len && + this.value == c.value); + } + + hash_t getHash(in void* p) + { size_t sz = value.tsize(); + hash_t hash = 0; + for (size_t i = 0; i < len; i++) + hash += value.getHash(p + i * sz); + return hash; + } + + equals_t equals(in void* p1, in void* p2) + { + size_t sz = value.tsize(); + + for (size_t u = 0; u < len; u++) + { + if (!value.equals(p1 + u * sz, p2 + u * sz)) + return 0; + } + return 1; + } + + int compare(in void* p1, in void* p2) + { + size_t sz = value.tsize(); + + for (size_t u = 0; u < len; u++) + { + int result = value.compare(p1 + u * sz, p2 + u * sz); + if (result) + return result; + } + return 0; + } + + size_t tsize() + { + return len * value.tsize(); + } + + void swap(void* p1, void* p2) + { void* tmp; + size_t sz = value.tsize(); + ubyte[16] buffer; + void* pbuffer; + + if (sz < buffer.sizeof) + tmp = buffer.ptr; + else + tmp = pbuffer = (new void[sz]).ptr; + + for (size_t u = 0; u < len; u += sz) + { size_t o = u * sz; + memcpy(tmp, p1 + o, sz); + memcpy(p1 + o, p2 + o, sz); + memcpy(p2 + o, tmp, sz); + } + if (pbuffer) + delete pbuffer; + } + + void[] init() { return value.init(); } + TypeInfo next() { return value; } + uint flags() { return value.flags(); } + + TypeInfo value; + size_t len; +} + +class TypeInfo_AssociativeArray : TypeInfo +{ + string toString() + { + return next.toString() ~ "[" ~ key.toString() ~ "]"; + } + + equals_t opEquals(Object o) + { TypeInfo_AssociativeArray c; + + return this is o || + ((c = cast(TypeInfo_AssociativeArray)o) !is null && + this.key == c.key && + this.value == c.value); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { + return (char[int]).sizeof; + } + + TypeInfo next() { return value; } + uint flags() { return 1; } + + TypeInfo value; + TypeInfo key; +} + +class TypeInfo_Function : TypeInfo +{ + string toString() + { + return next.toString() ~ "()"; + } + + equals_t opEquals(Object o) + { TypeInfo_Function c; + + return this is o || + ((c = cast(TypeInfo_Function)o) !is null && + this.next == c.next); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { + return 0; // no size for functions + } + + TypeInfo next; +} + +class TypeInfo_Delegate : TypeInfo +{ + string toString() + { + return next.toString() ~ " delegate()"; + } + + equals_t opEquals(Object o) + { TypeInfo_Delegate c; + + return this is o || + ((c = cast(TypeInfo_Delegate)o) !is null && + this.next == c.next); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { alias int delegate() dg; + return dg.sizeof; + } + + uint flags() { return 1; } + + TypeInfo next; +} + +class TypeInfo_Class : TypeInfo +{ + string toString() { return info.name; } + + equals_t opEquals(Object o) + { TypeInfo_Class c; + + return this is o || + ((c = cast(TypeInfo_Class)o) !is null && + this.info.name == c.classinfo.name); + } + + hash_t getHash(in void* p) + { + Object o = *cast(Object*)p; + return o ? o.toHash() : 0; + } + + equals_t equals(in void* p1, in void* p2) + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + + return (o1 is o2) || (o1 && o1.opEquals(o2)); + } + + 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; + } + + size_t tsize() + { + return Object.sizeof; + } + + uint flags() { return 1; } + + OffsetTypeInfo[] offTi() + { + return (info.flags & 4) ? info.offTi : null; + } + + ClassInfo info; +} + +class TypeInfo_Interface : TypeInfo +{ + string toString() { return info.name; } + + equals_t opEquals(Object o) + { TypeInfo_Interface c; + + return this is o || + ((c = cast(TypeInfo_Interface)o) !is null && + this.info.name == c.classinfo.name); + } + + hash_t getHash(in void* p) + { + Interface* pi = **cast(Interface ***)*cast(void**)p; + Object o = cast(Object)(*cast(void**)p - pi.offset); + assert(o); + return o.toHash(); + } + + equals_t equals(in void* p1, in void* p2) + { + Interface* pi = **cast(Interface ***)*cast(void**)p1; + Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); + pi = **cast(Interface ***)*cast(void**)p2; + Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); + + return o1 == o2 || (o1 && o1.opCmp(o2) == 0); + } + + int compare(in void* p1, in void* p2) + { + Interface* pi = **cast(Interface ***)*cast(void**)p1; + Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); + pi = **cast(Interface ***)*cast(void**)p2; + Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); + int c = 0; + + // Regard null references as always being "less than" + if (o1 != o2) + { + if (o1) + { if (!o2) + c = 1; + else + c = o1.opCmp(o2); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return Object.sizeof; + } + + uint flags() { return 1; } + + ClassInfo info; +} + +class TypeInfo_Struct : TypeInfo +{ + string toString() { return name; } + + equals_t opEquals(Object o) + { TypeInfo_Struct s; + + return this is o || + ((s = cast(TypeInfo_Struct)o) !is null && + this.name == s.name && + this.init.length == s.init.length); + } + + hash_t getHash(in void* p) + { hash_t h; + + assert(p); + if (xtoHash) + { debug(PRINTF) printf("getHash() using xtoHash\n"); + h = (*xtoHash)(p); + } + else + { + debug(PRINTF) printf("getHash() using default hash\n"); + // A sorry hash algorithm. + // Should use the one for strings. + // BUG: relies on the GC not moving objects + for (size_t i = 0; i < init.length; i++) + { h = h * 9 + *cast(ubyte*)p; + p++; + } + } + return h; + } + + equals_t equals(in void* p1, in void* p2) + { int c; + + if (p1 == p2) + c = 1; + else if (!p1 || !p2) + c = 0; + else if (xopEquals) + c = (*xopEquals)(p1, p2); + else + // BUG: relies on the GC not moving objects + c = (memcmp(p1, p2, init.length) == 0); + return c; + } + + int compare(in void* p1, in void* p2) + { + int c = 0; + + // Regard null references as always being "less than" + if (p1 != p2) + { + if (p1) + { if (!p2) + c = 1; + else if (xopCmp) + c = (*xopCmp)(p2, p1); + else + // BUG: relies on the GC not moving objects + c = memcmp(p1, p2, init.length); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return init.length; + } + + void[] init() { return m_init; } + + uint flags() { return m_flags; } + + string name; + void[] m_init; // initializer; init.ptr == null if 0 initialize + + hash_t function(void*) xtoHash; + int function(void*,void*) xopEquals; + int function(void*,void*) xopCmp; + char[] function(void*) xtoString; + + uint m_flags; +} + +class TypeInfo_Tuple : TypeInfo +{ + TypeInfo[] elements; + + string toString() + { + char[] s; + s = "("; + foreach (i, element; elements) + { + if (i) + s ~= ','; + s ~= element.toString(); + } + s ~= ")"; + return s; + } + + equals_t opEquals(Object o) + { + if (this is o) + return true; + + auto t = cast(TypeInfo_Tuple)o; + if (t && elements.length == t.elements.length) + { + for (size_t i = 0; i < elements.length; i++) + { + if (elements[i] != t.elements[i]) + return false; + } + return true; + } + return false; + } + + hash_t getHash(in void* p) + { + assert(0); + } + + equals_t equals(in void* p1, in void* p2) + { + assert(0); + } + + int compare(in void* p1, in void* p2) + { + assert(0); + } + + size_t tsize() + { + assert(0); + } + + void swap(void* p1, void* p2) + { + assert(0); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Exception +/////////////////////////////////////////////////////////////////////////////// + + +class Exception : Object +{ + interface TraceInfo + { + int opApply( int delegate( inout char[] ) ); + } + + char[] msg; + char[] file; + size_t line; + TraceInfo info; + Exception next; + + this( char[] msg, Exception next = null ) + { + this.msg = msg; + this.next = next; + this.info = traceContext(); + } + + this( char[] msg, char[] file, size_t line, Exception next = null ) + { + this(msg, next); + this.file = file; + this.line = line; + this.info = traceContext(); + } + + string toString() + { + return msg; + } +} + + +alias Exception.TraceInfo function( void* ptr = null ) TraceHandler; +private TraceHandler traceHandler = null; + + +/** + * Overrides the default trace hander with a user-supplied version. + * + * Params: + * h = The new trace handler. Set to null to use the default handler. + */ +extern (C) void rt_setTraceHandler( TraceHandler h ) +{ + traceHandler = h; +} + + +/** + * This function will be called when an Exception is constructed. The + * user-supplied trace handler will be called if one has been supplied, + * otherwise no trace will be generated. + * + * Params: + * ptr = A pointer to the location from which to generate the trace, or null + * if the trace should be generated from within the trace handler + * itself. + * + * Returns: + * An object describing the current calling context or null if no handler is + * supplied. + */ +Exception.TraceInfo traceContext( void* ptr = null ) +{ + if( traceHandler is null ) + return null; + return traceHandler( ptr ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// ModuleInfo +/////////////////////////////////////////////////////////////////////////////// + + +enum +{ + MIctorstart = 1, // we've started constructing it + MIctordone = 2, // finished construction + MIstandalone = 4, // module ctor does not depend on other module + // ctors being done first + MIhasictor = 8, // has ictor member +} + + +class ModuleInfo +{ + string name; + ModuleInfo[] importedModules; + ClassInfo[] localClasses; + uint flags; + + void function() ctor; // module static constructor (order dependent) + void function() dtor; // module static destructor + void function() unitTest; // module unit tests + + void* xgetMembers; // module getMembers() function + + void function() ictor; // module static constructor (order independent) + + static int opApply( int delegate( inout ModuleInfo ) dg ) + { + int ret = 0; + + foreach( m; _moduleinfo_array ) + { + ret = dg( m ); + if( ret ) + break; + } + return ret; + } +} + + +// Windows: this gets initialized by minit.asm +// linux: this gets initialized in _moduleCtor() +extern (C) ModuleInfo[] _moduleinfo_array; + + +version (linux) +{ + // This linked list is created by a compiler generated function inserted + // into the .ctor list by the compiler. + struct ModuleReference + { + ModuleReference* next; + ModuleInfo mod; + } + + extern (C) ModuleReference* _Dmodule_ref; // start of linked list +} + +ModuleInfo[] _moduleinfo_dtors; +uint _moduleinfo_dtors_i; + +// Register termination function pointers +extern (C) int _fatexit(void*); + +/** + * Initialize the modules. + */ + +extern (C) void _moduleCtor() +{ + debug(PRINTF) printf("_moduleCtor()\n"); + version (linux) + { + int len = 0; + ModuleReference *mr; + + for (mr = _Dmodule_ref; mr; mr = mr.next) + len++; + _moduleinfo_array = new ModuleInfo[len]; + len = 0; + for (mr = _Dmodule_ref; mr; mr = mr.next) + { _moduleinfo_array[len] = mr.mod; + len++; + } + } + + version (Windows) + { + // Ensure module destructors also get called on program termination + //_fatexit(&_STD_moduleDtor); + } + + _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length]; + debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void*)_moduleinfo_dtors); + _moduleIndependentCtors(); + _moduleCtor2(_moduleinfo_array, 0); +} + +extern (C) void _moduleIndependentCtors() +{ + debug(PRINTF) printf("_moduleIndependentCtors()\n"); + foreach (m; _moduleinfo_array) + { + if (m && m.flags & MIhasictor && m.ictor) + { + (*m.ictor)(); + } + } +} + +void _moduleCtor2(ModuleInfo[] mi, int skip) +{ + debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length); + for (uint i = 0; i < mi.length; i++) + { + ModuleInfo m = mi[i]; + + debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m); + if (!m) + continue; + debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name); + if (m.flags & MIctordone) + continue; + debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m); + + if (m.ctor || m.dtor) + { + if (m.flags & MIctorstart) + { if (skip || m.flags & MIstandalone) + continue; + throw new Exception( "Cyclic dependency in module " ~ m.name ); + } + + m.flags |= MIctorstart; + _moduleCtor2(m.importedModules, 0); + if (m.ctor) + (*m.ctor)(); + m.flags &= ~MIctorstart; + m.flags |= MIctordone; + + // Now that construction is done, register the destructor + //printf("\tadding module dtor x%x\n", m); + assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length); + _moduleinfo_dtors[_moduleinfo_dtors_i++] = m; + } + else + { + m.flags |= MIctordone; + _moduleCtor2(m.importedModules, 1); + } + } +} + +/** + * Destruct the modules. + */ + +// Starting the name with "_STD" means under linux a pointer to the +// function gets put in the .dtors segment. + +extern (C) void _moduleDtor() +{ + debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i); + + for (uint i = _moduleinfo_dtors_i; i-- != 0;) + { + ModuleInfo m = _moduleinfo_dtors[i]; + + debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m); + if (m.dtor) + { + (*m.dtor)(); + } + } + debug(PRINTF) printf("_moduleDtor() done\n"); +} + +/////////////////////////////////////////////////////////////////////////////// +// Monitor +/////////////////////////////////////////////////////////////////////////////// + +alias Object.Monitor IMonitor; +alias void delegate(Object) DEvent; + +// NOTE: The dtor callback feature is only supported for monitors that are not +// supplied by the user. The assumption is that any object with a user- +// supplied monitor may have special storage or lifetime requirements and +// that as a result, storing references to local objects within Monitor +// may not be safe or desirable. Thus, devt is only valid if impl is +// null. +struct Monitor +{ + IMonitor impl; + /* internal */ + DEvent[] devt; + /* stuff */ +} + +Monitor* getMonitor(Object h) +{ + return cast(Monitor*) (cast(void**) h)[1]; +} + +void setMonitor(Object h, Monitor* m) +{ + (cast(void**) h)[1] = m; +} + +extern (C) void _d_monitor_create(Object); +extern (C) void _d_monitor_destroy(Object); +extern (C) void _d_monitor_lock(Object); +extern (C) int _d_monitor_unlock(Object); + +extern (C) void _d_monitordelete(Object h, bool det) +{ + Monitor* m = getMonitor(h); + + if (m !is null) + { + IMonitor i = m.impl; + if (i is null) + { + _d_monitor_devt(m, h); + _d_monitor_destroy(h); + setMonitor(h, null); + return; + } + if (det && (cast(void*) i) !is (cast(void*) h)) + delete i; + setMonitor(h, null); + } +} + +extern (C) void _d_monitorenter(Object h) +{ + Monitor* m = getMonitor(h); + + if (m is null) + { + _d_monitor_create(h); + m = getMonitor(h); + } + + IMonitor i = m.impl; + + if (i is null) + { + _d_monitor_lock(h); + return; + } + i.lock(); +} + +extern (C) void _d_monitorexit(Object h) +{ + Monitor* m = getMonitor(h); + IMonitor i = m.impl; + + if (i is null) + { + _d_monitor_unlock(h); + return; + } + i.unlock(); +} + +extern (C) void _d_monitor_devt(Monitor* m, Object h) +{ + if (m.devt.length) + { + DEvent[] devt; + + synchronized (h) + { + devt = m.devt; + m.devt = null; + } + foreach (v; devt) + { + if (v) + v(h); + } + free(devt.ptr); + } +} + +extern (C) void rt_attachDisposeEvent(Object h, DEvent e) +{ + synchronized (h) + { + Monitor* m = getMonitor(h); + assert(m.impl is null); + + foreach (inout v; m.devt) + { + if (v is null || v == e) + { + v = e; + return; + } + } + + auto len = m.devt.length + 4; // grow by 4 elements + auto pos = m.devt.length; // insert position + auto p = realloc(m.devt.ptr, DEvent.sizeof * len); + if (!p) + onOutOfMemoryError(); + m.devt = (cast(DEvent*)p)[0 .. len]; + m.devt[pos+1 .. len] = null; + m.devt[pos] = e; + } +} + +extern (C) void rt_detachDisposeEvent(Object h, DEvent e) +{ + synchronized (h) + { + Monitor* m = getMonitor(h); + assert(m.impl is null); + + foreach (p, v; m.devt) + { + if (v == e) + { + memmove(&m.devt[p], + &m.devt[p+1], + (m.devt.length - p - 1) * DEvent.sizeof); + m.devt[$ - 1] = null; + return; + } + } + } +} diff --git a/src/compiler/dmd/posix.mak b/src/compiler/dmd/posix.mak new file mode 100644 index 0000000..ee3b8fa --- /dev/null +++ b/src/compiler/dmd/posix.mak @@ -0,0 +1,176 @@ +# Makefile to build the compiler runtime D library for Linux +# Designed to work with GNU make +# Targets: +# make +# Same as make all +# make lib +# Build the compiler runtime library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=libdruntime-rt-dmd.a +LIB_MASK=libdruntime-rt-dmd*.a + +CP=cp -f +RM=rm -f +MD=mkdir -p + +CFLAGS=-O $(ADD_CFLAGS) +#CFLAGS=-g $(ADD_CFLAGS) + +DFLAGS=-release -O -inline -w -nofloat -version=Posix $(ADD_DFLAGS) +#DFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS) + +TFLAGS=-O -inline -w -nofloat -version=Posix $(ADD_DFLAGS) +#TFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS) + +DOCFLAGS=-version=DDoc -version=Posix + +CC=gcc +LC=$(AR) -qsv +DC=dmd + +LIB_DEST=../../../lib + +.SUFFIXES: .s .S .c .cpp .d .html .o + +.s.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.S.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.c.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.cpp.o: + g++ -c $(CFLAGS) $< -o$@ + +.d.o: + $(DC) -c $(DFLAGS) $< -of$@ + +.d.html: + $(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $< + +targets : lib doc +all : lib doc +lib : dmd.lib +doc : dmd.doc + +###################################################### + +OBJ_BASE= \ + aaA.o \ + aApply.o \ + aApplyR.o \ + adi.o \ + alloca.o \ + arraybyte.o \ + arraycast.o \ + arraycat.o \ + arraydouble.o \ + arrayfloat.o \ + arrayint.o \ + arrayreal.o \ + arrayshort.o \ + cast_.o \ + cmath2.o \ + complex.o \ + cover.o \ + critical.o \ + deh2.o \ + dmain2.o \ + invariant_.o \ + lifetime.o \ + llmath.o \ + memory.o \ + memset.o \ + monitor.o \ + obj.o \ + object_.o \ + qsort.o \ + switch_.o \ + trace.o +# NOTE: trace.obj and cover.obj 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 + +OBJ_UTIL= \ + util/console.o \ + util/cpuid.o \ + util/ctype.o \ + util/string.o \ + util/utf.o + +OBJ_TI= \ + typeinfo/ti_AC.o \ + typeinfo/ti_Acdouble.o \ + typeinfo/ti_Acfloat.o \ + typeinfo/ti_Acreal.o \ + typeinfo/ti_Adouble.o \ + typeinfo/ti_Afloat.o \ + typeinfo/ti_Ag.o \ + typeinfo/ti_Aint.o \ + typeinfo/ti_Along.o \ + typeinfo/ti_Areal.o \ + typeinfo/ti_Ashort.o \ + typeinfo/ti_byte.o \ + typeinfo/ti_C.o \ + typeinfo/ti_cdouble.o \ + typeinfo/ti_cfloat.o \ + typeinfo/ti_char.o \ + typeinfo/ti_creal.o \ + typeinfo/ti_dchar.o \ + typeinfo/ti_delegate.o \ + typeinfo/ti_double.o \ + typeinfo/ti_float.o \ + typeinfo/ti_idouble.o \ + typeinfo/ti_ifloat.o \ + typeinfo/ti_int.o \ + typeinfo/ti_ireal.o \ + typeinfo/ti_long.o \ + typeinfo/ti_ptr.o \ + typeinfo/ti_real.o \ + typeinfo/ti_short.o \ + typeinfo/ti_ubyte.o \ + typeinfo/ti_uint.o \ + typeinfo/ti_ulong.o \ + typeinfo/ti_ushort.o \ + typeinfo/ti_void.o \ + typeinfo/ti_wchar.o + +ALL_OBJS= \ + $(OBJ_BASE) \ + $(OBJ_UTIL) \ + $(OBJ_TI) + +###################################################### + +ALL_DOCS= + +###################################################### + +dmd.lib : $(LIB_TARGET) + +$(LIB_TARGET) : $(ALL_OBJS) + $(RM) $@ + $(LC) $@ $(ALL_OBJS) + +dmd.doc : $(ALL_DOCS) + echo No documentation available. + +###################################################### + +clean : + find . -name "*.di" | xargs $(RM) + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + $(RM) $(LIB_MASK) + +install : + $(MD) $(LIB_DEST) + $(CP) $(LIB_MASK) $(LIB_DEST)/. diff --git a/src/compiler/dmd/qsort.d b/src/compiler/dmd/qsort.d new file mode 100644 index 0000000..7fecff5 --- /dev/null +++ b/src/compiler/dmd/qsort.d @@ -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]); + } +} diff --git a/src/compiler/dmd/qsort2.d b/src/compiler/dmd/qsort2.d new file mode 100644 index 0000000..562e1fa --- /dev/null +++ b/src/compiler/dmd/qsort2.d @@ -0,0 +1,72 @@ + +/* + * Placed into Public Domain + * written by Walter Bright + * www.digitalmars.com + * + * This is a public domain version of qsort.d. + * All it does is call C's qsort(), but runs a little slower since + * it needs to synchronize a global variable. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.qsort2; + +//debug=qsort; + +private import 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]); + } +} diff --git a/src/compiler/dmd/switch_.d b/src/compiler/dmd/switch_.d new file mode 100644 index 0000000..ebb7373 --- /dev/null +++ b/src/compiler/dmd/switch_.d @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.switch_; + +private import 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; + } +} diff --git a/src/compiler/dmd/trace.d b/src/compiler/dmd/trace.d new file mode 100644 index 0000000..469afe2 --- /dev/null +++ b/src/compiler/dmd/trace.d @@ -0,0 +1,867 @@ + +/* Trace dynamic profiler. + * For use with the Digital Mars DMD compiler. + * Copyright (C) 1995-2006 by Digital Mars + * All Rights Reserved + * Written by Walter Bright + * www.digitalmars.com + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.trace; + +private +{ + import util.string; + import stdc.ctype; + import stdc.stdio; + import stdc.string; + import 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 + +static Symbol* root; // root of symbol table + +////////////////////////////////// +// 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 +} + +static Stack* stack_freelist; +static Stack* trace_tos; // top of stack +static int trace_inited; // !=0 if initialized +static timer_t trace_ohd; + +static Symbol** psymbols; +static uint nsymbols; // number of symbols + +static char[] trace_logfilename = "trace.log"; +static FILE* fplog; + +static char[] trace_deffilename = "trace.def"; +static FILE* fpdef; + + +//////////////////////////////////////// +// Set file name for output. +// A file name of "" means write results to stdout. +// Returns: +// 0 success +// !=0 failure + +int trace_setlogfilename(char[] 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(char[] 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(void* e1, 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) +{ static 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(void* e1, 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] = 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 + */ + + 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() +{ + 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); +} diff --git a/src/compiler/dmd/typeinfo/ti_AC.d b/src/compiler/dmd/typeinfo/ti_AC.d new file mode 100644 index 0000000..522f9ea --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_AC.d @@ -0,0 +1,95 @@ +module rt.typeinfo.ti_AC; + +// Object[] + +class TypeInfo_AC : TypeInfo +{ + 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; + } + + 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 0; + } + return 1; + } + return 0; + } + + 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; + } + + size_t tsize() + { + return (Object[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(Object); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Acdouble.d b/src/compiler/dmd/typeinfo/ti_Acdouble.d new file mode 100644 index 0000000..e2f1bbf --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Acdouble.d @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module rt.typeinfo.ti_Acdouble; + +private import typeinfo.ti_cdouble; + +// cdouble[] + +class TypeInfo_Ar : TypeInfo +{ + string toString() { return "cdouble[]"; } + + 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; + } + + 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 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_r._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + 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; + } + + size_t tsize() + { + return (cdouble[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(cdouble); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Acfloat.d b/src/compiler/dmd/typeinfo/ti_Acfloat.d new file mode 100644 index 0000000..c9a4b0c --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Acfloat.d @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module rt.typeinfo.ti_Acfloat; + +private import typeinfo.ti_cfloat; + +// cfloat[] + +class TypeInfo_Aq : TypeInfo +{ + string toString() { return "cfloat[]"; } + + 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; + } + + 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 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_q._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + 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; + } + + size_t tsize() + { + return (cfloat[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(cfloat); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Acreal.d b/src/compiler/dmd/typeinfo/ti_Acreal.d new file mode 100644 index 0000000..3abbbff --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Acreal.d @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module rt.typeinfo.ti_Acreal; + +private import typeinfo.ti_creal; + +// creal[] + +class TypeInfo_Ac : TypeInfo +{ + string toString() { return "creal[]"; } + + 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; + } + + 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++) + { + int c = TypeInfo_c._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + 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; + } + + size_t tsize() + { + return (creal[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(creal); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Adouble.d b/src/compiler/dmd/typeinfo/ti_Adouble.d new file mode 100644 index 0000000..c6321c4 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Adouble.d @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module rt.typeinfo.ti_Adouble; + +private import typeinfo.ti_double; + +// double[] + +class TypeInfo_Ad : TypeInfo +{ + string toString() { return "double[]"; } + + 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; + } + + 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++) + { + int c = TypeInfo_d._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + 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; + } + + size_t tsize() + { + return (double[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(double); + } +} + +// idouble[] + +class TypeInfo_Ap : TypeInfo_Ad +{ + string toString() { return "idouble[]"; } + + TypeInfo next() + { + return typeid(idouble); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Afloat.d b/src/compiler/dmd/typeinfo/ti_Afloat.d new file mode 100644 index 0000000..49625d9 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Afloat.d @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module rt.typeinfo.ti_Afloat; + +private import typeinfo.ti_float; + +// float[] + +class TypeInfo_Af : TypeInfo +{ + string toString() { return "float[]"; } + + 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; + } + + 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++) + { + int c = TypeInfo_f._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + 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; + } + + size_t tsize() + { + return (float[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(float); + } +} + +// ifloat[] + +class TypeInfo_Ao : TypeInfo_Af +{ + string toString() { return "ifloat[]"; } + + TypeInfo next() + { + return typeid(ifloat); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Ag.d b/src/compiler/dmd/typeinfo/ti_Ag.d new file mode 100644 index 0000000..daaa25b --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Ag.d @@ -0,0 +1,204 @@ + +module rt.typeinfo.ti_Ag; + +private import util.string; +private import stdc.string; + +// byte[] + +class TypeInfo_Ag : TypeInfo +{ + string toString() { return "byte[]"; } + + 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; + } + + 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; + } + + 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; + } + + size_t tsize() + { + return (byte[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(byte); + } +} + + +// ubyte[] + +class TypeInfo_Ah : TypeInfo_Ag +{ + string toString() { return "ubyte[]"; } + + int compare(in void* p1, in void* p2) + { + char[] s1 = *cast(char[]*)p1; + char[] s2 = *cast(char[]*)p2; + + return dstrcmp(s1, s2); + } + + TypeInfo next() + { + return typeid(ubyte); + } +} + +// void[] + +class TypeInfo_Av : TypeInfo_Ah +{ + string toString() { return "void[]"; } + + TypeInfo next() + { + return typeid(void); + } +} + +// bool[] + +class TypeInfo_Ab : TypeInfo_Ah +{ + string toString() { return "bool[]"; } + + TypeInfo next() + { + return typeid(bool); + } +} + +// char[] + +class TypeInfo_Aa : TypeInfo_Ag +{ + string toString() { return "char[]"; } + + 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; + } + + TypeInfo next() + { + return typeid(char); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Aint.d b/src/compiler/dmd/typeinfo/ti_Aint.d new file mode 100644 index 0000000..d888bed --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Aint.d @@ -0,0 +1,118 @@ + +module rt.typeinfo.ti_Aint; + +private import stdc.string; + +// int[] + +class TypeInfo_Ai : TypeInfo +{ + string toString() { return "int[]"; } + + 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; + } + + 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; + } + + 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; + } + + size_t tsize() + { + return (int[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(int); + } +} + +// uint[] + +class TypeInfo_Ak : TypeInfo_Ai +{ + string toString() { return "uint[]"; } + + 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; + } + + TypeInfo next() + { + return typeid(uint); + } +} + +// dchar[] + +class TypeInfo_Aw : TypeInfo_Ak +{ + string toString() { return "dchar[]"; } + + TypeInfo next() + { + return typeid(dchar); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Along.d b/src/compiler/dmd/typeinfo/ti_Along.d new file mode 100644 index 0000000..0a3b7f9 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Along.d @@ -0,0 +1,109 @@ + +module rt.typeinfo.ti_Along; + +private import stdc.string; + +// long[] + +class TypeInfo_Al : TypeInfo +{ + string toString() { return "long[]"; } + + 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; + } + + 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; + } + + 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; + } + + size_t tsize() + { + return (long[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(long); + } +} + + +// ulong[] + +class TypeInfo_Am : TypeInfo_Al +{ + string toString() { return "ulong[]"; } + + 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; + } + + TypeInfo next() + { + return typeid(ulong); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Areal.d b/src/compiler/dmd/typeinfo/ti_Areal.d new file mode 100644 index 0000000..afeb531 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Areal.d @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module rt.typeinfo.ti_Areal; + +private import typeinfo.ti_real; + +// real[] + +class TypeInfo_Ae : TypeInfo +{ + string toString() { return "real[]"; } + + 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; + } + + 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 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_e._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + 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; + } + + size_t tsize() + { + return (real[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(real); + } +} + +// ireal[] + +class TypeInfo_Aj : TypeInfo_Ae +{ + string toString() { return "ireal[]"; } + + TypeInfo next() + { + return typeid(ireal); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_Ashort.d b/src/compiler/dmd/typeinfo/ti_Ashort.d new file mode 100644 index 0000000..b5b494d --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_Ashort.d @@ -0,0 +1,132 @@ + +module rt.typeinfo.ti_Ashort; + +private import stdc.string; + +// short[] + +class TypeInfo_As : TypeInfo +{ + string toString() { return "short[]"; } + + 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; + } + + 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; + } + + 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; + } + + size_t tsize() + { + return (short[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(short); + } +} + + +// ushort[] + +class TypeInfo_At : TypeInfo_As +{ + string toString() { return "ushort[]"; } + + 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; + } + + TypeInfo next() + { + return typeid(ushort); + } +} + +// wchar[] + +class TypeInfo_Au : TypeInfo_At +{ + string toString() { return "wchar[]"; } + + TypeInfo next() + { + return typeid(wchar); + } +} diff --git a/src/compiler/dmd/typeinfo/ti_C.d b/src/compiler/dmd/typeinfo/ti_C.d new file mode 100644 index 0000000..5311398 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_C.d @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module rt.typeinfo.ti_C; + +// Object + +class TypeInfo_C : TypeInfo +{ + hash_t getHash(in void* p) + { + Object o = *cast(Object*)p; + return o ? o.toHash() : 0; + } + + equals_t equals(in void* p1, in void* p2) + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + + return o1 == o2; + } + + 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; + } + + size_t tsize() + { + return Object.sizeof; + } + + uint flags() + { + return 1; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_byte.d b/src/compiler/dmd/typeinfo/ti_byte.d new file mode 100644 index 0000000..ef0c8f2 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_byte.d @@ -0,0 +1,38 @@ + +// byte + +module rt.typeinfo.ti_byte; + +class TypeInfo_g : TypeInfo +{ + string toString() { return "byte"; } + + hash_t getHash(in void* p) + { + return *cast(byte *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(byte *)p1 == *cast(byte *)p2; + } + + int compare(in void* p1, in void* p2) + { + return *cast(byte *)p1 - *cast(byte *)p2; + } + + size_t tsize() + { + return byte.sizeof; + } + + void swap(void *p1, void *p2) + { + byte t; + + t = *cast(byte *)p1; + *cast(byte *)p1 = *cast(byte *)p2; + *cast(byte *)p2 = t; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_cdouble.d b/src/compiler/dmd/typeinfo/ti_cdouble.d new file mode 100644 index 0000000..0890360 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_cdouble.d @@ -0,0 +1,66 @@ + +// cdouble + +module rt.typeinfo.ti_cdouble; + +class TypeInfo_r : TypeInfo +{ + string toString() { return "cdouble"; } + + hash_t getHash(in void* p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1] + + (cast(uint *)p)[2] + (cast(uint *)p)[3]; + } + + static int _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; + } + + equals_t equals(in void* p1, in void* p2) + { + return _equals(*cast(cdouble *)p1, *cast(cdouble *)p2); + } + + int compare(in void* p1, in void* p2) + { + return _compare(*cast(cdouble *)p1, *cast(cdouble *)p2); + } + + size_t tsize() + { + return cdouble.sizeof; + } + + void swap(void *p1, void *p2) + { + cdouble t; + + t = *cast(cdouble *)p1; + *cast(cdouble *)p1 = *cast(cdouble *)p2; + *cast(cdouble *)p2 = t; + } + + void[] init() + { static cdouble r; + + return (cast(cdouble *)&r)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_cfloat.d b/src/compiler/dmd/typeinfo/ti_cfloat.d new file mode 100644 index 0000000..50c7ba8 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_cfloat.d @@ -0,0 +1,65 @@ + +// cfloat + +module rt.typeinfo.ti_cfloat; + +class TypeInfo_q : TypeInfo +{ + string toString() { return "cfloat"; } + + hash_t getHash(in void* p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1]; + } + + static int _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; + } + + equals_t equals(in void* p1, in void* p2) + { + return _equals(*cast(cfloat *)p1, *cast(cfloat *)p2); + } + + int compare(in void* p1, in void* p2) + { + return _compare(*cast(cfloat *)p1, *cast(cfloat *)p2); + } + + size_t tsize() + { + return cfloat.sizeof; + } + + void swap(void *p1, void *p2) + { + cfloat t; + + t = *cast(cfloat *)p1; + *cast(cfloat *)p1 = *cast(cfloat *)p2; + *cast(cfloat *)p2 = t; + } + + void[] init() + { static cfloat r; + + return (cast(cfloat *)&r)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_char.d b/src/compiler/dmd/typeinfo/ti_char.d new file mode 100644 index 0000000..60e49e2 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_char.d @@ -0,0 +1,42 @@ + +module rt.typeinfo.ti_char; + +class TypeInfo_a : TypeInfo +{ + string toString() { return "char"; } + + hash_t getHash(in void* p) + { + return *cast(char *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(char *)p1 == *cast(char *)p2; + } + + int compare(in void* p1, in void* p2) + { + return *cast(char *)p1 - *cast(char *)p2; + } + + size_t tsize() + { + return char.sizeof; + } + + void swap(void *p1, void *p2) + { + char t; + + t = *cast(char *)p1; + *cast(char *)p1 = *cast(char *)p2; + *cast(char *)p2 = t; + } + + void[] init() + { static char c; + + return (cast(char *)&c)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_creal.d b/src/compiler/dmd/typeinfo/ti_creal.d new file mode 100644 index 0000000..8221dad --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_creal.d @@ -0,0 +1,67 @@ + +// creal + +module rt.typeinfo.ti_creal; + +class TypeInfo_c : TypeInfo +{ + string toString() { return "creal"; } + + 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 int _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; + } + + equals_t equals(in void* p1, in void* p2) + { + return _equals(*cast(creal *)p1, *cast(creal *)p2); + } + + int compare(in void* p1, in void* p2) + { + return _compare(*cast(creal *)p1, *cast(creal *)p2); + } + + size_t tsize() + { + return creal.sizeof; + } + + void swap(void *p1, void *p2) + { + creal t; + + t = *cast(creal *)p1; + *cast(creal *)p1 = *cast(creal *)p2; + *cast(creal *)p2 = t; + } + + void[] init() + { static creal r; + + return (cast(creal *)&r)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_dchar.d b/src/compiler/dmd/typeinfo/ti_dchar.d new file mode 100644 index 0000000..fda33bf --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_dchar.d @@ -0,0 +1,44 @@ + +// dchar + +module rt.typeinfo.ti_dchar; + +class TypeInfo_w : TypeInfo +{ + string toString() { return "dchar"; } + + hash_t getHash(in void* p) + { + return *cast(dchar *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(dchar *)p1 == *cast(dchar *)p2; + } + + int compare(in void* p1, in void* p2) + { + return *cast(dchar *)p1 - *cast(dchar *)p2; + } + + size_t tsize() + { + return dchar.sizeof; + } + + void swap(void *p1, void *p2) + { + dchar t; + + t = *cast(dchar *)p1; + *cast(dchar *)p1 = *cast(dchar *)p2; + *cast(dchar *)p2 = t; + } + + void[] init() + { static dchar c; + + return (cast(dchar *)&c)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_delegate.d b/src/compiler/dmd/typeinfo/ti_delegate.d new file mode 100644 index 0000000..c4d41df --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_delegate.d @@ -0,0 +1,39 @@ + +// delegate + +module rt.typeinfo.ti_delegate; + +alias void delegate(int) dg; + +class TypeInfo_D : TypeInfo +{ + hash_t getHash(in void* p) + { long l = *cast(long *)p; + + return cast(uint)(l + (l >> 32)); + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(dg *)p1 == *cast(dg *)p2; + } + + size_t tsize() + { + return dg.sizeof; + } + + void swap(void *p1, void *p2) + { + dg t; + + t = *cast(dg *)p1; + *cast(dg *)p1 = *cast(dg *)p2; + *cast(dg *)p2 = t; + } + + uint flags() + { + return 1; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_double.d b/src/compiler/dmd/typeinfo/ti_double.d new file mode 100644 index 0000000..db79d37 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_double.d @@ -0,0 +1,64 @@ + +// double + +module rt.typeinfo.ti_double; + +class TypeInfo_d : TypeInfo +{ + string toString() { return "double"; } + + hash_t getHash(in void* p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1]; + } + + static int _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); + } + + equals_t equals(in void* p1, in void* p2) + { + return _equals(*cast(double *)p1, *cast(double *)p2); + } + + int compare(in void* p1, in void* p2) + { + return _compare(*cast(double *)p1, *cast(double *)p2); + } + + size_t tsize() + { + return double.sizeof; + } + + void swap(void *p1, void *p2) + { + double t; + + t = *cast(double *)p1; + *cast(double *)p1 = *cast(double *)p2; + *cast(double *)p2 = t; + } + + void[] init() + { static double r; + + return (cast(double *)&r)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_float.d b/src/compiler/dmd/typeinfo/ti_float.d new file mode 100644 index 0000000..6b0688c --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_float.d @@ -0,0 +1,64 @@ + +// float + +module rt.typeinfo.ti_float; + +class TypeInfo_f : TypeInfo +{ + string toString() { return "float"; } + + hash_t getHash(in void* p) + { + return *cast(uint *)p; + } + + static int _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); + } + + equals_t equals(in void* p1, in void* p2) + { + return _equals(*cast(float *)p1, *cast(float *)p2); + } + + int compare(in void* p1, in void* p2) + { + return _compare(*cast(float *)p1, *cast(float *)p2); + } + + size_t tsize() + { + return float.sizeof; + } + + void swap(void *p1, void *p2) + { + float t; + + t = *cast(float *)p1; + *cast(float *)p1 = *cast(float *)p2; + *cast(float *)p2 = t; + } + + void[] init() + { static float r; + + return (cast(float *)&r)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_idouble.d b/src/compiler/dmd/typeinfo/ti_idouble.d new file mode 100644 index 0000000..fbb1a02 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_idouble.d @@ -0,0 +1,11 @@ + +// idouble + +module rt.typeinfo.ti_idouble; + +private import typeinfo.ti_double; + +class TypeInfo_p : TypeInfo_d +{ + string toString() { return "idouble"; } +} diff --git a/src/compiler/dmd/typeinfo/ti_ifloat.d b/src/compiler/dmd/typeinfo/ti_ifloat.d new file mode 100644 index 0000000..6b63dc6 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_ifloat.d @@ -0,0 +1,11 @@ + +// ifloat + +module rt.typeinfo.ti_ifloat; + +private import typeinfo.ti_float; + +class TypeInfo_o : TypeInfo_f +{ + string toString() { return "ifloat"; } +} diff --git a/src/compiler/dmd/typeinfo/ti_int.d b/src/compiler/dmd/typeinfo/ti_int.d new file mode 100644 index 0000000..b2d0cf8 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_int.d @@ -0,0 +1,42 @@ + +// int + +module rt.typeinfo.ti_int; + +class TypeInfo_i : TypeInfo +{ + string toString() { return "int"; } + + hash_t getHash(in void* p) + { + return *cast(uint *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(uint *)p1 == *cast(uint *)p2; + } + + 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; + } + + size_t tsize() + { + return int.sizeof; + } + + void swap(void *p1, void *p2) + { + int t; + + t = *cast(int *)p1; + *cast(int *)p1 = *cast(int *)p2; + *cast(int *)p2 = t; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_ireal.d b/src/compiler/dmd/typeinfo/ti_ireal.d new file mode 100644 index 0000000..edf6815 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_ireal.d @@ -0,0 +1,11 @@ + +// ireal + +module rt.typeinfo.ti_ireal; + +private import typeinfo.ti_real; + +class TypeInfo_j : TypeInfo_e +{ + string toString() { return "ireal"; } +} diff --git a/src/compiler/dmd/typeinfo/ti_long.d b/src/compiler/dmd/typeinfo/ti_long.d new file mode 100644 index 0000000..ed64dae --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_long.d @@ -0,0 +1,42 @@ + +// long + +module rt.typeinfo.ti_long; + +class TypeInfo_l : TypeInfo +{ + string toString() { return "long"; } + + hash_t getHash(in void* p) + { + return *cast(uint *)p + (cast(uint *)p)[1]; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(long *)p1 == *cast(long *)p2; + } + + 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; + } + + size_t tsize() + { + return long.sizeof; + } + + void swap(void *p1, void *p2) + { + long t; + + t = *cast(long *)p1; + *cast(long *)p1 = *cast(long *)p2; + *cast(long *)p2 = t; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_ptr.d b/src/compiler/dmd/typeinfo/ti_ptr.d new file mode 100644 index 0000000..c285a64 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_ptr.d @@ -0,0 +1,46 @@ + +// pointer + +module rt.typeinfo.ti_ptr; + +class TypeInfo_P : TypeInfo +{ + hash_t getHash(in void* p) + { + return cast(uint)*cast(void* *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(void* *)p1 == *cast(void* *)p2; + } + + 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; + } + + size_t tsize() + { + return (void*).sizeof; + } + + void swap(void *p1, void *p2) + { + void* t; + + t = *cast(void* *)p1; + *cast(void* *)p1 = *cast(void* *)p2; + *cast(void* *)p2 = t; + } + + uint flags() + { + return 1; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_real.d b/src/compiler/dmd/typeinfo/ti_real.d new file mode 100644 index 0000000..b678d2c --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_real.d @@ -0,0 +1,64 @@ + +// real + +module rt.typeinfo.ti_real; + +class TypeInfo_e : TypeInfo +{ + string toString() { return "real"; } + + hash_t getHash(in void* p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1] + (cast(ushort *)p)[4]; + } + + static int _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); + } + + equals_t equals(in void* p1, in void* p2) + { + return _equals(*cast(real *)p1, *cast(real *)p2); + } + + int compare(in void* p1, in void* p2) + { + return _compare(*cast(real *)p1, *cast(real *)p2); + } + + size_t tsize() + { + return real.sizeof; + } + + void swap(void *p1, void *p2) + { + real t; + + t = *cast(real *)p1; + *cast(real *)p1 = *cast(real *)p2; + *cast(real *)p2 = t; + } + + void[] init() + { static real r; + + return (cast(real *)&r)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_short.d b/src/compiler/dmd/typeinfo/ti_short.d new file mode 100644 index 0000000..fa6a409 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_short.d @@ -0,0 +1,38 @@ + +// short + +module rt.typeinfo.ti_short; + +class TypeInfo_s : TypeInfo +{ + string toString() { return "short"; } + + hash_t getHash(in void* p) + { + return *cast(short *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(short *)p1 == *cast(short *)p2; + } + + int compare(in void* p1, in void* p2) + { + return *cast(short *)p1 - *cast(short *)p2; + } + + size_t tsize() + { + return short.sizeof; + } + + void swap(void *p1, void *p2) + { + short t; + + t = *cast(short *)p1; + *cast(short *)p1 = *cast(short *)p2; + *cast(short *)p2 = t; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_ubyte.d b/src/compiler/dmd/typeinfo/ti_ubyte.d new file mode 100644 index 0000000..a555e9e --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_ubyte.d @@ -0,0 +1,43 @@ + +// ubyte + +module rt.typeinfo.ti_ubyte; + +class TypeInfo_h : TypeInfo +{ + string toString() { return "ubyte"; } + + hash_t getHash(in void* p) + { + return *cast(ubyte *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(ubyte *)p1 == *cast(ubyte *)p2; + } + + int compare(in void* p1, in void* p2) + { + return *cast(ubyte *)p1 - *cast(ubyte *)p2; + } + + size_t tsize() + { + return ubyte.sizeof; + } + + 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 +{ + string toString() { return "bool"; } +} diff --git a/src/compiler/dmd/typeinfo/ti_uint.d b/src/compiler/dmd/typeinfo/ti_uint.d new file mode 100644 index 0000000..e3cf4c6 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_uint.d @@ -0,0 +1,42 @@ + +// uint + +module rt.typeinfo.ti_uint; + +class TypeInfo_k : TypeInfo +{ + string toString() { return "uint"; } + + hash_t getHash(in void* p) + { + return *cast(uint *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(uint *)p1 == *cast(uint *)p2; + } + + 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; + } + + size_t tsize() + { + return uint.sizeof; + } + + void swap(void *p1, void *p2) + { + int t; + + t = *cast(uint *)p1; + *cast(uint *)p1 = *cast(uint *)p2; + *cast(uint *)p2 = t; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_ulong.d b/src/compiler/dmd/typeinfo/ti_ulong.d new file mode 100644 index 0000000..e4ec94d --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_ulong.d @@ -0,0 +1,42 @@ + +// ulong + +module rt.typeinfo.ti_ulong; + +class TypeInfo_m : TypeInfo +{ + string toString() { return "ulong"; } + + hash_t getHash(in void* p) + { + return *cast(uint *)p + (cast(uint *)p)[1]; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(ulong *)p1 == *cast(ulong *)p2; + } + + 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; + } + + size_t tsize() + { + return ulong.sizeof; + } + + void swap(void *p1, void *p2) + { + ulong t; + + t = *cast(ulong *)p1; + *cast(ulong *)p1 = *cast(ulong *)p2; + *cast(ulong *)p2 = t; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_ushort.d b/src/compiler/dmd/typeinfo/ti_ushort.d new file mode 100644 index 0000000..e5702a2 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_ushort.d @@ -0,0 +1,38 @@ + +// ushort + +module rt.typeinfo.ti_ushort; + +class TypeInfo_t : TypeInfo +{ + string toString() { return "ushort"; } + + hash_t getHash(in void* p) + { + return *cast(ushort *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(ushort *)p1 == *cast(ushort *)p2; + } + + int compare(in void* p1, in void* p2) + { + return *cast(ushort *)p1 - *cast(ushort *)p2; + } + + size_t tsize() + { + return ushort.sizeof; + } + + void swap(void *p1, void *p2) + { + ushort t; + + t = *cast(ushort *)p1; + *cast(ushort *)p1 = *cast(ushort *)p2; + *cast(ushort *)p2 = t; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_void.d b/src/compiler/dmd/typeinfo/ti_void.d new file mode 100644 index 0000000..495aa1e --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_void.d @@ -0,0 +1,43 @@ + +// void + +module rt.typeinfo.ti_void; + +class TypeInfo_v : TypeInfo +{ + string toString() { return "void"; } + + hash_t getHash(in void* p) + { + assert(0); + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(byte *)p1 == *cast(byte *)p2; + } + + int compare(in void* p1, in void* p2) + { + return *cast(byte *)p1 - *cast(byte *)p2; + } + + size_t tsize() + { + return void.sizeof; + } + + void swap(void *p1, void *p2) + { + byte t; + + t = *cast(byte *)p1; + *cast(byte *)p1 = *cast(byte *)p2; + *cast(byte *)p2 = t; + } + + uint flags() + { + return 1; + } +} diff --git a/src/compiler/dmd/typeinfo/ti_wchar.d b/src/compiler/dmd/typeinfo/ti_wchar.d new file mode 100644 index 0000000..29c7963 --- /dev/null +++ b/src/compiler/dmd/typeinfo/ti_wchar.d @@ -0,0 +1,43 @@ + +module rt.typeinfo.ti_wchar; + + +class TypeInfo_u : TypeInfo +{ + string toString() { return "wchar"; } + + hash_t getHash(in void* p) + { + return *cast(wchar *)p; + } + + equals_t equals(in void* p1, in void* p2) + { + return *cast(wchar *)p1 == *cast(wchar *)p2; + } + + int compare(in void* p1, in void* p2) + { + return *cast(wchar *)p1 - *cast(wchar *)p2; + } + + size_t tsize() + { + return wchar.sizeof; + } + + void swap(void *p1, void *p2) + { + wchar t; + + t = *cast(wchar *)p1; + *cast(wchar *)p1 = *cast(wchar *)p2; + *cast(wchar *)p2 = t; + } + + void[] init() + { static wchar c; + + return (cast(wchar *)&c)[0 .. 1]; + } +} diff --git a/src/compiler/dmd/util/console.d b/src/compiler/dmd/util/console.d new file mode 100644 index 0000000..93d7fdf --- /dev/null +++ b/src/compiler/dmd/util/console.d @@ -0,0 +1,49 @@ +/** + * The console module contains some simple routines for console output. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + */ +module rt.util.console; + + +private +{ + version (Windows) + { + import sys.windows.windows; + } + else version( Posix ) + { + import stdc.posix.unistd; + } + import util.string; +} + + +struct Console +{ + Console opCall( in char[] val ) + { + version( Windows ) + { + uint count = void; + WriteFile( GetStdHandle( 0xfffffff5 ), val.ptr, val.length, &count, null ); + } + else version( Posix ) + { + write( 2, val.ptr, val.length ); + } + return *this; + } + + + Console opCall( uint val ) + { + char[10] tmp = void; + return opCall( tmp.intToString( val ) ); + } +} + +Console console; diff --git a/src/compiler/dmd/util/cpuid.d b/src/compiler/dmd/util/cpuid.d new file mode 100644 index 0000000..b4d9cba --- /dev/null +++ b/src/compiler/dmd/util/cpuid.d @@ -0,0 +1,459 @@ +/** + * Identify the characteristics of the host CPU. + * + * Implemented according to: + +- AP-485 Intel(C) Processor Identification and the CPUID Instruction + $(LINK http://www.intel.com/design/xeon/applnots/241618.htm) + +- Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M + $(LINK http://developer.intel.com/design/pentium4/manuals/index_new.htm) + +- AMD CPUID Specification Publication # 25481 + $(LINK http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf) + +Example: +--- +import std.cpuid; +import std.stdio; + +void main() +{ + writefln(std.cpuid.toString()); +} +--- + +AUTHORS: Tomas Lindquist Olsen <tomas@famolsen.dk> + (slightly altered by Walter Bright) +COPYRIGHT: Public Domain + + * BUGS: Only works on x86 CPUs + * + * Macros: + * WIKI = Phobos/StdCpuid + * COPYRIGHT = Public Domain + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.util.cpuid; + +private import stdc.string; + +version(D_InlineAsm_X86) +{ + /// Returns vendor string + char[] vendor() {return vendorStr;} + /// Returns processor string + char[] processor() {return processorStr;} + + /// Is MMX supported? + bool mmx() {return (flags&MMX_BIT)!=0;} + /// Is FXSR supported? + bool fxsr() {return (flags&FXSR_BIT)!=0;} + /// Is SSE supported? + bool sse() {return (flags&SSE_BIT)!=0;} + /// Is SSE2 supported? + bool sse2() {return (flags&SSE2_BIT)!=0;} + /// Is SSE3 supported? + bool sse3() {return (misc&SSE3_BIT)!=0;} + /// Is SSSE3 supported? + bool ssse3() {return (misc&SSSE3_BIT)!=0;} + + /// Is AMD 3DNOW supported? + bool amd3dnow() {return (exflags&AMD_3DNOW_BIT)!=0;} + /// Is AMD 3DNOW Ext supported? + bool amd3dnowExt() {return (exflags&AMD_3DNOW_EXT_BIT)!=0;} + /// Is AMD MMX supported? + bool amdMmx() {return (exflags&AMD_MMX_BIT)!=0;} + + /// Is this an Intel Architecture IA64? + bool ia64() {return (flags&IA64_BIT)!=0;} + /// Is this an AMD 64? + bool amd64() {return (exflags&AMD64_BIT)!=0;} + + /// Is hyperthreading supported? + bool hyperThreading() {return (flags&HTT_BIT)!=0;} + /// Returns number of threads per CPU + uint threadsPerCPU() {return maxThreads;} + /// Returns number of cores in CPU + uint coresPerCPU() {return maxCores;} + + /// Is this an Intel processor? + bool intel() {return manufac==INTEL;} + /// Is this an AMD processor? + bool amd() {return manufac==AMD;} + + /// Returns stepping + uint stepping() {return _stepping;} + /// Returns model + uint model() {return _model;} + /// Returns family + uint family() {return _family;} + //uint processorType() {return (signature>>>12)&0x3;} + + static this() + { + getVendorString(); + getProcessorString(); + getFeatureFlags(); + + // stepping / family / model + _stepping = signature&0xF; + uint fbase = (signature>>>8)&0xF; + uint fex = (signature>>>20)&0xFF; + uint mbase = (signature>>>4)&0xF; + uint mex = (signature>>>16)&0xF; + + // vendor specific + void function() threadFn; + switch(vendorStr) + { + case "GenuineIntel": + manufac = INTEL; + threadFn = &getThreadingIntel; + if (fbase == 0xF) + _family = fbase+fex; + else + _family = fbase; + if (_family == 0x6 || _family == 0xF) + _model = mbase+(mex<<4); + else + _model = mbase; + break; + + case "AuthenticAMD": + manufac = AMD; + threadFn = &getThreadingAMD; + if (fbase < 0xF) + { + _family = fbase; + _model = mbase; + } + else + { + _family = fbase+fex; + _model = mbase+(mex<<4); + } + break; + + default: + manufac = OTHER; + } + + // threading details + if (hyperThreading && threadFn !is null) + { + threadFn(); + } + } + +private: + // feature flags + enum : uint + { + 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 + enum : uint + { + SSE3_BIT = 1, + SSSE3_BIT = 1<<9 + } + // extended feature flags + enum : uint + { + AMD_MMX_BIT = 1<<22, + AMD64_BIT = 1<<29, + AMD_3DNOW_EXT_BIT = 1<<30, + AMD_3DNOW_BIT = 1<<31 + } + // manufacturer + enum + { + OTHER, + INTEL, + AMD + } + + uint flags, misc, exflags, apic, signature; + uint _stepping, _model, _family; + + char[12] vendorStr = ""; + char[] processorStr = ""; + + uint maxThreads=1; + uint maxCores=1; + uint manufac=OTHER; + + /* ** + * fetches the cpu vendor string + */ + private void getVendorString() + { + char* dst = vendorStr.ptr; + // puts the vendor string into dst + asm + { + mov EAX, 0 ; + cpuid ; + mov EAX, dst ; + mov [EAX], EBX ; + mov [EAX+4], EDX ; + mov [EAX+8], ECX ; + } + } + + private void getProcessorString() + { + char[48] buffer; + char* dst = buffer.ptr; + // puts the processor string into dst + asm + { + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0004 ; + jb PSLabel ; // no support + push EDI ; + mov EDI, dst ; + mov EAX, 0x8000_0002 ; + cpuid ; + mov [EDI], EAX ; + mov [EDI+4], EBX ; + mov [EDI+8], ECX ; + mov [EDI+12], EDX ; + mov EAX, 0x8000_0003 ; + cpuid ; + mov [EDI+16], EAX ; + mov [EDI+20], EBX ; + mov [EDI+24], ECX ; + mov [EDI+28], EDX ; + mov EAX, 0x8000_0004 ; + cpuid ; + mov [EDI+32], EAX ; + mov [EDI+36], EBX ; + mov [EDI+40], ECX ; + mov [EDI+44], EDX ; + pop EDI ; + PSLabel: ; + } + + if (buffer[0] == char.init) // no support + return; + + // seems many intel processors prepend whitespace + processorStr = strip(toString(dst)).dup; + } + + private void getFeatureFlags() + { + uint f,m,e,a,s; + asm + { + mov EAX, 0 ; + cpuid ; + cmp EAX, 1 ; + jb FeatLabel ; // no support + mov EAX, 1 ; + cpuid ; + mov f, EDX ; + mov m, ECX ; + mov a, EBX ; + mov s, EAX ; + + FeatLabel: ; + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0001 ; + jb FeatLabel2 ; // no support + mov EAX, 0x8000_0001 ; + cpuid ; + mov e, EDX ; + + FeatLabel2: + ; + } + flags = f; + misc = m; + exflags = e; + apic = a; + signature = s; + } + + private void getThreadingIntel() + { + uint n; + ubyte b = 0; + asm + { + mov EAX, 0 ; + cpuid ; + cmp EAX, 4 ; + jb IntelSingle ; + mov EAX, 4 ; + mov ECX, 0 ; + cpuid ; + mov n, EAX ; + mov b, 1 ; + IntelSingle: ; + } + if (b != 0) + { + maxCores = ((n>>>26)&0x3F)+1; + maxThreads = (apic>>>16)&0xFF; + } + else + { + maxCores = maxThreads = 1; + } + } + + private void getThreadingAMD() + { + ubyte n; + ubyte b = 0; + asm + { + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0008 ; + jb AMDSingle ; + mov EAX, 0x8000_0008 ; + cpuid ; + mov n, CL ; + mov b, 1 ; + AMDSingle: ; + } + if (b != 0) + { + maxCores = n+1; + maxThreads = (apic>>>16)&0xFF; + } + else + { + maxCores = maxThreads = 1; + } + } + + /*************************************************************************** + * Support code for above, from std.string and std.ctype + ***************************************************************************/ + + private + { + enum + { + _SPC = 8, + _CTL = 0x20, + _BLK = 0x40, + _HEX = 0x80, + _UC = 1, + _LC = 2, + _PNC = 0x10, + _DIG = 4, + _ALP = _UC|_LC, + } + + ubyte _ctype[128] = + [ + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL, + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, + _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, + _PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC, + _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, + _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, + _UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC, + _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, + _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, + _LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL + ]; + + /** + * Returns !=0 if c is a space, tab, vertical tab, form feed, + * carriage return, or linefeed. + */ + int isspace(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; } + + /***************************************** + * Strips leading or trailing whitespace, or both. + */ + char[] stripl(char[] s) + { + uint i; + + for (i = 0; i < s.length; i++) + { + if (!isspace(s[i])) + break; + } + return s[i .. s.length]; + } + + char[] stripr(char[] s) /// ditto + { + uint i; + + for (i = s.length; i > 0; i--) + { + if (!isspace(s[i - 1])) + break; + } + return s[0 .. i]; + } + + char[] strip(char[] s) /// ditto + { + return stripr(stripl(s)); + } + + string toString(char *s) + { + return s ? s[0 .. strlen(s)] : cast(char[])null; + } + } +} +else +{ + char[] vendor() {return "unknown vendor"; } + char[] processor() {return "unknown processor"; } + + bool mmx() {return false; } + bool fxsr() {return false; } + bool sse() {return false; } + bool sse2() {return false; } + bool sse3() {return false; } + bool ssse3() {return false; } + + bool amd3dnow() {return false; } + bool amd3dnowExt() {return false; } + bool amdMmx() {return false; } + + bool ia64() {return false; } + bool amd64() {return false; } + + bool hyperThreading() {return false; } + uint threadsPerCPU() {return 0; } + uint coresPerCPU() {return 0; } + + bool intel() {return false; } + bool amd() {return false; } + + uint stepping() {return 0; } + uint model() {return 0; } + uint family() {return 0; } +} diff --git a/src/compiler/dmd/util/ctype.d b/src/compiler/dmd/util/ctype.d new file mode 100644 index 0000000..5948e78 --- /dev/null +++ b/src/compiler/dmd/util/ctype.d @@ -0,0 +1,106 @@ + +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +// Simple ASCII char classification functions + +module rt.util.ctype; + +int isalnum(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG) : 0; } +int isalpha(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP) : 0; } +int iscntrl(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_CTL) : 0; } +int isdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_DIG) : 0; } +int islower(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_LC) : 0; } +int ispunct(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_PNC) : 0; } +int isspace(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; } +int isupper(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_UC) : 0; } +int isxdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_HEX) : 0; } +int isgraph(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC) : 0; } +int isprint(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC|_BLK) : 0; } +int isascii(dchar c) { return c <= 0x7F; } + +dchar tolower(dchar c) + out (result) + { + assert(!isupper(result)); + } + body + { + return isupper(c) ? c + (cast(dchar)'a' - 'A') : c; + } + +dchar toupper(dchar c) + out (result) + { + assert(!islower(result)); + } + body + { + return islower(c) ? c - (cast(dchar)'a' - 'A') : c; + } + +private: + +enum +{ + _SPC = 8, + _CTL = 0x20, + _BLK = 0x40, + _HEX = 0x80, + _UC = 1, + _LC = 2, + _PNC = 0x10, + _DIG = 4, + _ALP = _UC|_LC, +} + +ubyte _ctype[128] = +[ + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL, + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, + _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, + _PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC, + _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, + _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, + _UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC, + _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, + _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, + _LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL +]; + + +unittest +{ + assert(isspace(' ')); + assert(!isspace('z')); + assert(toupper('a') == 'A'); + assert(tolower('Q') == 'q'); + assert(!isxdigit('G')); +} diff --git a/src/compiler/dmd/util/string.d b/src/compiler/dmd/util/string.d new file mode 100644 index 0000000..d63a5a1 --- /dev/null +++ b/src/compiler/dmd/util/string.d @@ -0,0 +1,35 @@ +/** + * The exception module defines all system-level exceptions and provides a + * mechanism to alter system-level error handling. + * + * Copyright: Copyright (c) 2005-2008, The D Runtime Project + * License: BSD Style, see LICENSE + * Authors: Sean Kelly + */ +module rt.util.string; + +private import stdc.string; + +char[] intToString( char[] buf, uint val ) +{ + assert( buf.length > 9 ); + char* p = buf.ptr + buf.length; + + do + { + *--p = val % 10 + '0'; + } while( val /= 10 ); + + return buf[p - buf.ptr .. $]; +} + + +int dstrcmp( in char[] s1, in char[] s2 ) +{ + auto len = s1.length; + if( s2.length < len ) + len = s2.length; + if( memcmp( s1.ptr, s2.ptr, len ) == 0 ) + return 0; + return s1.length > s2.length ? 1 : -1; +} diff --git a/src/compiler/dmd/util/utf.d b/src/compiler/dmd/util/utf.d new file mode 100644 index 0000000..84ace7c --- /dev/null +++ b/src/compiler/dmd/util/utf.d @@ -0,0 +1,851 @@ +// utf.d + +/* + * Copyright (C) 2003-2004 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +// Description of UTF-8 at: +// http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 +// http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335 + + +module rt.util.utf; + + +extern (C) void onUnicodeError( char[] msg, size_t idx ); + + +bool isValidDchar(dchar c) +{ + /* Note: FFFE and FFFF are specifically permitted by the + * Unicode standard for application internal use, but are not + * allowed for interchange. + * (thanks to Arcane Jill) + */ + + return c < 0xD800 || + (c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/); +} + +unittest +{ + debug(utf) printf("utf.isValidDchar.unittest\n"); + assert(isValidDchar(cast(dchar)'a') == true); + assert(isValidDchar(cast(dchar)0x1FFFFF) == false); +} + + +/* This array gives the length of a UTF-8 sequence indexed by the value + * of the leading byte. An FF represents an illegal starting value of + * a UTF-8 sequence. + * FF is used instead of 0 to avoid having loops hang. + */ + +ubyte[256] UTF8stride = +[ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, +]; + +uint stride(char[] s, size_t i) +{ + return UTF8stride[s[i]]; +} + +uint stride(wchar[] s, size_t i) +{ uint u = s[i]; + return 1 + (u >= 0xD800 && u <= 0xDBFF); +} + +uint stride(dchar[] s, size_t i) +{ + return 1; +} + +/******************************************* + * Given an index into an array of char's, + * and assuming that index is at the start of a UTF character, + * determine the number of UCS characters up to that index. + */ + +size_t toUCSindex(char[] s, size_t i) +{ + size_t n; + size_t j; + size_t stride; + + for (j = 0; j < i; j += stride) + { + stride = UTF8stride[s[j]]; + if (stride == 0xFF) + goto Lerr; + n++; + } + if (j > i) + { + Lerr: + onUnicodeError("invalid UTF-8 sequence", j); + } + return n; +} + +size_t toUCSindex(wchar[] s, size_t i) +{ + size_t n; + size_t j; + + for (j = 0; j < i; ) + { uint u = s[j]; + + j += 1 + (u >= 0xD800 && u <= 0xDBFF); + n++; + } + if (j > i) + { + Lerr: + onUnicodeError("invalid UTF-16 sequence", j); + } + return n; +} + +size_t toUCSindex(dchar[] s, size_t i) +{ + return i; +} + +/****************************************** + * Given a UCS index into an array of characters, return the UTF index. + */ + +size_t toUTFindex(char[] s, size_t n) +{ + size_t i; + + while (n--) + { + uint j = UTF8stride[s[i]]; + if (j == 0xFF) + onUnicodeError("invalid UTF-8 sequence", i); + i += j; + } + return i; +} + +size_t toUTFindex(wchar[] s, size_t n) +{ + size_t i; + + while (n--) + { wchar u = s[i]; + + i += 1 + (u >= 0xD800 && u <= 0xDBFF); + } + return i; +} + +size_t toUTFindex(dchar[] s, size_t n) +{ + return n; +} + +/* =================== Decode ======================= */ + +dchar decode(char[] s, inout size_t idx) + in + { + assert(idx >= 0 && idx < s.length); + } + out (result) + { + assert(isValidDchar(result)); + } + body + { + size_t len = s.length; + dchar V; + size_t i = idx; + char u = s[i]; + + if (u & 0x80) + { uint n; + char u2; + + /* The following encodings are valid, except for the 5 and 6 byte + * combinations: + * 0xxxxxxx + * 110xxxxx 10xxxxxx + * 1110xxxx 10xxxxxx 10xxxxxx + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + for (n = 1; ; n++) + { + if (n > 4) + goto Lerr; // only do the first 4 of 6 encodings + if (((u << n) & 0x80) == 0) + { + if (n == 1) + goto Lerr; + break; + } + } + + // Pick off (7 - n) significant bits of B from first byte of octet + V = cast(dchar)(u & ((1 << (7 - n)) - 1)); + + if (i + (n - 1) >= len) + goto Lerr; // off end of string + + /* The following combinations are overlong, and illegal: + * 1100000x (10xxxxxx) + * 11100000 100xxxxx (10xxxxxx) + * 11110000 1000xxxx (10xxxxxx 10xxxxxx) + * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) + * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) + */ + u2 = s[i + 1]; + if ((u & 0xFE) == 0xC0 || + (u == 0xE0 && (u2 & 0xE0) == 0x80) || + (u == 0xF0 && (u2 & 0xF0) == 0x80) || + (u == 0xF8 && (u2 & 0xF8) == 0x80) || + (u == 0xFC && (u2 & 0xFC) == 0x80)) + goto Lerr; // overlong combination + + for (uint j = 1; j != n; j++) + { + u = s[i + j]; + if ((u & 0xC0) != 0x80) + goto Lerr; // trailing bytes are 10xxxxxx + V = (V << 6) | (u & 0x3F); + } + if (!isValidDchar(V)) + goto Lerr; + i += n; + } + else + { + V = cast(dchar) u; + i++; + } + + idx = i; + return V; + + Lerr: + onUnicodeError("invalid UTF-8 sequence", i); + return V; // dummy return + } + +unittest +{ size_t i; + dchar c; + + debug(utf) printf("utf.decode.unittest\n"); + + static char[] s1 = "abcd"; + i = 0; + c = decode(s1, i); + assert(c == cast(dchar)'a'); + assert(i == 1); + c = decode(s1, i); + assert(c == cast(dchar)'b'); + assert(i == 2); + + static char[] s2 = "\xC2\xA9"; + i = 0; + c = decode(s2, i); + assert(c == cast(dchar)'\u00A9'); + assert(i == 2); + + static char[] s3 = "\xE2\x89\xA0"; + i = 0; + c = decode(s3, i); + assert(c == cast(dchar)'\u2260'); + assert(i == 3); + + static char[][] s4 = + [ "\xE2\x89", // too short + "\xC0\x8A", + "\xE0\x80\x8A", + "\xF0\x80\x80\x8A", + "\xF8\x80\x80\x80\x8A", + "\xFC\x80\x80\x80\x80\x8A", + ]; + + for (int j = 0; j < s4.length; j++) + { + try + { + i = 0; + c = decode(s4[j], i); + assert(0); + } + catch (Object o) + { + i = 23; + } + assert(i == 23); + } +} + +/********************************************************/ + +dchar decode(wchar[] s, inout size_t idx) + in + { + assert(idx >= 0 && idx < s.length); + } + out (result) + { + assert(isValidDchar(result)); + } + body + { + char[] msg; + dchar V; + size_t i = idx; + uint u = s[i]; + + if (u & ~0x7F) + { if (u >= 0xD800 && u <= 0xDBFF) + { uint u2; + + if (i + 1 == s.length) + { msg = "surrogate UTF-16 high value past end of string"; + goto Lerr; + } + u2 = s[i + 1]; + if (u2 < 0xDC00 || u2 > 0xDFFF) + { msg = "surrogate UTF-16 low value out of range"; + goto Lerr; + } + u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); + i += 2; + } + else if (u >= 0xDC00 && u <= 0xDFFF) + { msg = "unpaired surrogate UTF-16 value"; + goto Lerr; + } + else if (u == 0xFFFE || u == 0xFFFF) + { msg = "illegal UTF-16 value"; + goto Lerr; + } + else + i++; + } + else + { + i++; + } + + idx = i; + return cast(dchar)u; + + Lerr: + onUnicodeError(msg, i); + return cast(dchar)u; // dummy return + } + +/********************************************************/ + +dchar decode(dchar[] s, inout size_t idx) + in + { + assert(idx >= 0 && idx < s.length); + } + body + { + size_t i = idx; + dchar c = s[i]; + + if (!isValidDchar(c)) + goto Lerr; + idx = i + 1; + return c; + + Lerr: + onUnicodeError("invalid UTF-32 value", i); + return c; // dummy return + } + + +/* =================== Encode ======================= */ + +void encode(inout char[] s, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + char[] r = s; + + if (c <= 0x7F) + { + r ~= cast(char) c; + } + else + { + char[4] buf; + uint L; + + if (c <= 0x7FF) + { + buf[0] = cast(char)(0xC0 | (c >> 6)); + buf[1] = cast(char)(0x80 | (c & 0x3F)); + L = 2; + } + else if (c <= 0xFFFF) + { + buf[0] = cast(char)(0xE0 | (c >> 12)); + buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); + buf[2] = cast(char)(0x80 | (c & 0x3F)); + L = 3; + } + else if (c <= 0x10FFFF) + { + buf[0] = cast(char)(0xF0 | (c >> 18)); + buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); + buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); + buf[3] = cast(char)(0x80 | (c & 0x3F)); + L = 4; + } + else + { + assert(0); + } + r ~= buf[0 .. L]; + } + s = r; + } + +unittest +{ + debug(utf) printf("utf.encode.unittest\n"); + + char[] s = "abcd"; + encode(s, cast(dchar)'a'); + assert(s.length == 5); + assert(s == "abcda"); + + encode(s, cast(dchar)'\u00A9'); + assert(s.length == 7); + assert(s == "abcda\xC2\xA9"); + //assert(s == "abcda\u00A9"); // BUG: fix compiler + + encode(s, cast(dchar)'\u2260'); + assert(s.length == 10); + assert(s == "abcda\xC2\xA9\xE2\x89\xA0"); +} + +/********************************************************/ + +void encode(inout wchar[] s, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + wchar[] r = s; + + if (c <= 0xFFFF) + { + r ~= cast(wchar) c; + } + else + { + wchar[2] buf; + + buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); + buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); + r ~= buf; + } + s = r; + } + +void encode(inout dchar[] s, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + s ~= c; + } + +/* =================== Validation ======================= */ + +void validate(char[] s) +{ + size_t len = s.length; + size_t i; + + for (i = 0; i < len; ) + { + decode(s, i); + } +} + +void validate(wchar[] s) +{ + size_t len = s.length; + size_t i; + + for (i = 0; i < len; ) + { + decode(s, i); + } +} + +void validate(dchar[] s) +{ + size_t len = s.length; + size_t i; + + for (i = 0; i < len; ) + { + decode(s, i); + } +} + +/* =================== Conversion to UTF8 ======================= */ + +char[] toUTF8(char[4] buf, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + if (c <= 0x7F) + { + buf[0] = cast(char) c; + return buf[0 .. 1]; + } + else if (c <= 0x7FF) + { + buf[0] = cast(char)(0xC0 | (c >> 6)); + buf[1] = cast(char)(0x80 | (c & 0x3F)); + return buf[0 .. 2]; + } + else if (c <= 0xFFFF) + { + buf[0] = cast(char)(0xE0 | (c >> 12)); + buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); + buf[2] = cast(char)(0x80 | (c & 0x3F)); + return buf[0 .. 3]; + } + else if (c <= 0x10FFFF) + { + buf[0] = cast(char)(0xF0 | (c >> 18)); + buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); + buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); + buf[3] = cast(char)(0x80 | (c & 0x3F)); + return buf[0 .. 4]; + } + assert(0); + } + +char[] toUTF8(char[] s) + in + { + validate(s); + } + body + { + return s; + } + +char[] toUTF8(wchar[] s) +{ + char[] r; + size_t i; + size_t slen = s.length; + + r.length = slen; + + for (i = 0; i < slen; i++) + { wchar c = s[i]; + + if (c <= 0x7F) + r[i] = cast(char)c; // fast path for ascii + else + { + r.length = i; + foreach (dchar c; s[i .. slen]) + { + encode(r, c); + } + break; + } + } + return r; +} + +char[] toUTF8(dchar[] s) +{ + char[] r; + size_t i; + size_t slen = s.length; + + r.length = slen; + + for (i = 0; i < slen; i++) + { dchar c = s[i]; + + if (c <= 0x7F) + r[i] = cast(char)c; // fast path for ascii + else + { + r.length = i; + foreach (dchar d; s[i .. slen]) + { + encode(r, d); + } + break; + } + } + return r; +} + +/* =================== Conversion to UTF16 ======================= */ + +wchar[] toUTF16(wchar[2] buf, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + if (c <= 0xFFFF) + { + buf[0] = cast(wchar) c; + return buf[0 .. 1]; + } + else + { + buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); + buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); + return buf[0 .. 2]; + } + } + +wchar[] toUTF16(char[] s) +{ + wchar[] r; + size_t slen = s.length; + + r.length = slen; + r.length = 0; + for (size_t i = 0; i < slen; ) + { + dchar c = s[i]; + if (c <= 0x7F) + { + i++; + r ~= cast(wchar)c; + } + else + { + c = decode(s, i); + encode(r, c); + } + } + return r; +} + +wchar* toUTF16z(char[] s) +{ + wchar[] r; + size_t slen = s.length; + + r.length = slen + 1; + r.length = 0; + for (size_t i = 0; i < slen; ) + { + dchar c = s[i]; + if (c <= 0x7F) + { + i++; + r ~= cast(wchar)c; + } + else + { + c = decode(s, i); + encode(r, c); + } + } + r ~= "\000"; + return r.ptr; +} + +wchar[] toUTF16(wchar[] s) + in + { + validate(s); + } + body + { + return s; + } + +wchar[] toUTF16(dchar[] s) +{ + wchar[] r; + size_t slen = s.length; + + r.length = slen; + r.length = 0; + for (size_t i = 0; i < slen; i++) + { + encode(r, s[i]); + } + return r; +} + +/* =================== Conversion to UTF32 ======================= */ + +dchar[] toUTF32(char[] s) +{ + dchar[] r; + size_t slen = s.length; + size_t j = 0; + + r.length = slen; // r[] will never be longer than s[] + for (size_t i = 0; i < slen; ) + { + dchar c = s[i]; + if (c >= 0x80) + c = decode(s, i); + else + i++; // c is ascii, no need for decode + r[j++] = c; + } + return r[0 .. j]; +} + +dchar[] toUTF32(wchar[] s) +{ + dchar[] r; + size_t slen = s.length; + size_t j = 0; + + r.length = slen; // r[] will never be longer than s[] + for (size_t i = 0; i < slen; ) + { + dchar c = s[i]; + if (c >= 0x80) + c = decode(s, i); + else + i++; // c is ascii, no need for decode + r[j++] = c; + } + return r[0 .. j]; +} + +dchar[] toUTF32(dchar[] s) + in + { + validate(s); + } + body + { + return s; + } + +/* ================================ tests ================================== */ + +unittest +{ + debug(utf) printf("utf.toUTF.unittest\n"); + + char[] c; + wchar[] w; + dchar[] d; + + c = "hello"; + w = toUTF16(c); + assert(w == "hello"); + d = toUTF32(c); + assert(d == "hello"); + + c = toUTF8(w); + assert(c == "hello"); + d = toUTF32(w); + assert(d == "hello"); + + c = toUTF8(d); + assert(c == "hello"); + w = toUTF16(d); + assert(w == "hello"); + + + c = "hel\u1234o"; + w = toUTF16(c); + assert(w == "hel\u1234o"); + d = toUTF32(c); + assert(d == "hel\u1234o"); + + c = toUTF8(w); + assert(c == "hel\u1234o"); + d = toUTF32(w); + assert(d == "hel\u1234o"); + + c = toUTF8(d); + assert(c == "hel\u1234o"); + w = toUTF16(d); + assert(w == "hel\u1234o"); + + + c = "he\U0010AAAAllo"; + w = toUTF16(c); + //foreach (wchar c; w) printf("c = x%x\n", c); + //foreach (wchar c; cast(wchar[])"he\U0010AAAAllo") printf("c = x%x\n", c); + assert(w == "he\U0010AAAAllo"); + d = toUTF32(c); + assert(d == "he\U0010AAAAllo"); + + c = toUTF8(w); + assert(c == "he\U0010AAAAllo"); + d = toUTF32(w); + assert(d == "he\U0010AAAAllo"); + + c = toUTF8(d); + assert(c == "he\U0010AAAAllo"); + w = toUTF16(d); + assert(w == "he\U0010AAAAllo"); +} diff --git a/src/compiler/dmd/win32.mak b/src/compiler/dmd/win32.mak new file mode 100644 index 0000000..3ac7221 --- /dev/null +++ b/src/compiler/dmd/win32.mak @@ -0,0 +1,169 @@ +# Makefile to build the compiler runtime D library for Win32 +# Designed to work with DigitalMars make +# Targets: +# make +# Same as make all +# make lib +# Build the compiler runtime library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=druntime-rt-dmd.lib +LIB_MASK=druntime-rt-dmd*.lib + +CP=xcopy /y +RM=del /f +MD=mkdir + +CFLAGS=-mn -6 -r $(ADD_CFLAGS) +#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS) + +DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS) +#DFLAGS=-g -w -nofloat $(ADD_DFLAGS) + +TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS) +#TFLAGS=-g -w -nofloat $(ADD_DFLAGS) + +DOCFLAGS=-version=DDoc + +CC=dmc +LC=lib +DC=dmd + +LIB_DEST=..\..\..\lib + +.DEFAULT: .asm .c .cpp .d .html .obj + +.asm.obj: + $(CC) -c $< + +.c.obj: + $(CC) -c $(CFLAGS) $< -o$@ + +.cpp.obj: + $(CC) -c $(CFLAGS) $< -o$@ + +.d.obj: + $(DC) -c $(DFLAGS) $< -of$@ + +.d.html: + $(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $< + +targets : lib doc +all : lib doc +lib : dmd.lib +doc : dmd.doc + +###################################################### + +OBJ_BASE= \ + aaA.obj \ + aApply.obj \ + aApplyR.obj \ + adi.obj \ + arraybyte.obj \ + arraycast.obj \ + arraycat.obj \ + arraydouble.obj \ + arrayfloat.obj \ + arrayint.obj \ + arrayreal.obj \ + arrayshort.obj \ + cast_.obj \ + complex.obj \ + cover.obj \ + critical.obj \ + deh.obj \ + dmain2.obj \ + invariant_.obj \ + lifetime.obj \ + memory.obj \ + memset.obj \ + monitor.obj \ + obj.obj \ + object_.obj \ + qsort.obj \ + switch_.obj \ + trace.obj +# NOTE: trace.obj and cover.obj 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 + +OBJ_UTIL= \ + util\console.obj \ + util\cpuid.obj \ + util\ctype.obj \ + util\string.obj \ + util\utf.obj + +OBJ_TI= \ + typeinfo\ti_AC.obj \ + typeinfo\ti_Acdouble.obj \ + typeinfo\ti_Acfloat.obj \ + typeinfo\ti_Acreal.obj \ + typeinfo\ti_Adouble.obj \ + typeinfo\ti_Afloat.obj \ + typeinfo\ti_Ag.obj \ + typeinfo\ti_Aint.obj \ + typeinfo\ti_Along.obj \ + typeinfo\ti_Areal.obj \ + typeinfo\ti_Ashort.obj \ + typeinfo\ti_byte.obj \ + typeinfo\ti_C.obj \ + typeinfo\ti_cdouble.obj \ + typeinfo\ti_cfloat.obj \ + typeinfo\ti_char.obj \ + typeinfo\ti_creal.obj \ + typeinfo\ti_dchar.obj \ + typeinfo\ti_delegate.obj \ + typeinfo\ti_double.obj \ + typeinfo\ti_float.obj \ + typeinfo\ti_idouble.obj \ + typeinfo\ti_ifloat.obj \ + typeinfo\ti_int.obj \ + typeinfo\ti_ireal.obj \ + typeinfo\ti_long.obj \ + typeinfo\ti_ptr.obj \ + typeinfo\ti_real.obj \ + typeinfo\ti_short.obj \ + typeinfo\ti_ubyte.obj \ + typeinfo\ti_uint.obj \ + typeinfo\ti_ulong.obj \ + typeinfo\ti_ushort.obj \ + typeinfo\ti_void.obj \ + typeinfo\ti_wchar.obj + +ALL_OBJS= \ + $(OBJ_BASE) \ + $(OBJ_UTIL) \ + $(OBJ_TI) + +###################################################### + +ALL_DOCS= + +###################################################### + +dmd.lib : $(LIB_TARGET) + +$(LIB_TARGET) : $(ALL_OBJS) + $(RM) $@ + $(LC) -c -n $@ $(ALL_OBJS) minit.obj + +dmd.doc : $(ALL_DOCS) + @echo No documentation available. + +###################################################### + +clean : + $(RM) /s *.di + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + $(RM) $(LIB_MASK) + +install : + $(MD) $(LIB_DEST) + $(CP) $(LIB_MASK) $(LIB_DEST)\. diff --git a/src/compiler/tango-rt-dmd.lib b/src/compiler/tango-rt-dmd.lib new file mode 100644 index 0000000000000000000000000000000000000000..5a07e5f3d6a70f63e36b2af7710af30df171fff7 GIT binary patch literal 258048 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
  • z!>v(PUIgfj4emL%estvVMJlSiA!kw`@}LfI0YP2FSuH~AWIe|Bb-A9{y)jD11H|LPjNynj6Koq8 zw(kPHvNL| zU}Bg&01*oY7%YdT<4vqHZM@EW@N-%+NJNOQGfTs-ad~|$G*ohYt$A5nYYq*5_5aX} z+nslFe60bUI(EbBs+I&of}@-bsc5wm1rwFK;E{_cHAT3*owD<`9X$~lz$0QJp z(R9fuie|4B4YmRR9RdKn?x30EzGT($q(RNQQ>-4qN&AjJF+Hi=@h2uI%XU34x|>Q& zxExZUrz~S}n!>BlS8YsJP&RsMEyqlE&`i%qz5)zDzL0TkJ6C8uO)N!q)X{sXqvUO< zbe2gpG@&3#8f#J$XnK)!LrqHN#KQC<;35_#9`2$Kq=o5jeYgi$nRwXc#pwhsPGZo_ zH^&#J|DeU`bzYoK7}YL!Mjr1&$w-TnBcU7v#B`~X)Go!TY8R0{;LfW~!X;*2enrca zk$HK9K)j7W>}L=!kU*>}SujZ2GDSoS6n>`-snl21PFlLrsDyeP+HZgt*hQKOtTH-g zX;^iqhE)st#VRSk_0E)4Y8YeFu@5`r%M`g4vFZlBcawgqFTI3sIHm(!C3md^s&$ve zSEy7~4eQ(A>OO)F=SfQxd^)u%k`xtzZ|QSXTc@CEAJg#@TBjNbxc4(~(`jW=f&1^k z$yDIVa8=E_4T}_3^^8Fuw@kW!oH&V$y8k`7`&gymPk>eGe*PBSTCcx1xF zezqC`K^FyKD&8$m5PNsu6U2`3fa_Kol9GOcXz2rP2Tc%}1n~qha>Kehh9$th)G-S0 zcdT!^7P^>qfL}UYj0N!tXNF`q1?+dMZ@P^Aj`dARdy3$@0GsOGNf3*9^I&ReRvy^L zM=CaGZ0c8fw|ISi@507fpYHcCO0i3CR@G^*u%c@QemxUqAm<06sHm@K^98t^Jyx>M z*YN(FT7^=PGlbX*$f@FG+7U0d0@iyTpoHWJA$Bz)g1rsM=Ru2E*s__@kY9t?VpoqC zPLyzJpeVgFaBA2)LEn9q0x1E8^!uiAHHQQ<5{=dFDZLZ-SKyp5!lvwbq)%;%*lmTr zL4{UdQ}1o&-Bz^eRCY?3%{~i7vlibmJqV|TAnlICE-k+|P&AA88!}`?CGovUTjP6{ zls#?9jtrv28PnnCu(ot-vd6^$J`#z{wUjx&W6VO0YH8a71<4*C?J<@6P*g~67yf{+ zsos0X^qI37ujT%$`lcjhkc&nz;Ru0gZ`glT-^A~e1M-vynqHA3gq<8AM)c(fVQ|;b z9U%zgc!p|wrY4bQYU0(|Gld=-_e@RD_Ds!|7zb#09GbIXeyG=E`}`2RB-Z37Sa)OL zkqy{AgU38^2PTnZ?*ecQ%nycNjsyy0B`0j5Bk0KP!Mn${|M7EMN6-7*R@-Ak9?QLB z`P>hE=gj<-CwH^1}pKN@)U|Z>dVt!nfB6(h~u`E z5$hyj1ggO6c`FlTmE-lqX|IV4rne%?CdQ_{6n;5$aNc?LNHDl5JHXN3szkvp6NK3V+>w8|0=*LWT1cG$635 zD^l|sM)R#=puc!u4^H+jZ7p$E60^(MwubGZUtkcy_ z)Bb7CtpIPrP6j+k>Iw9zFk+oM?bTgJx0x2a`bX2zl`GKSc@gWUG#HS>0YI{3g%~Tm zTxNP*eQDYYk;>&C)9!=9^EZ+Rk}^Q!l@9oHJ38K`A;_X&3PyzXLSZndC)#BiQKj~T zdh!o@&g3Hs26c74UG-Q(y;;7xNZEy=qv4Uj{O}4(c!d?47b2Tuwx{0D4qC%yXP+VZ zF!zNmwu(sE8SYZpb2fC)JU3|d-&C?hoU!4%HNJpCSCz~;G#exeb?tzpVEQjV3v zBOa_~0X+hP;_AfkYmvY%1t?bXJO4dkY01ArNChyxL5QZ!6UZlgMSy|T;pg=7g{Q~~ zWGIZx8$In$7)X2e3mAGw_#@!0XZN!3O4~VnlKY0tpd1|z{NK3@-&|1GqKkyg#ySa~kqbvFPj10Jo#jp|kDK=RE zkLLlz^TPy!c{&L4BGxs8{^5^I&jSiB4GIKd0>pO)0K_B)#8?Rs4-*D|9*%V#hZq{9 ziPkP?kl+x9){{=e0dKgx;2O149TrvVb~#uRKj;LUPff_`pbg}?HZ5!7?Yq%2|4;QMP0>LbuMIT_V<_ytC2m0pH`dEaZ>X?=_wWf?Id87}RlIw--b>Ng-yVHvAK_ZOSb*i{{43l{m4bzRACl&H<_1uy&4qzqoWm>4vrU z)BK*Il`Z9)gDK$mdwqe$P2y0O8`Ltn1sIF?&vX?bSd=3rBO zk^q~!>tT{h*;C%9VgYI#oM}Txx76I<7HqBelg@xoxj}E}Fc)1m7q!i7Xs+Gh-vp(J z8`>irIh5#MQbUN}#omLd{D%Wmj>cpVqY?jU%pM6!&?}C~HDwz!4U-e=_vtdtB>6*J zCMz@QF5=KVRxsKK)iO)OYzcd!s>d1jbbUBTOKZ06{1a|N+b#2LkNzHaV6ms{$9kPj zIeTnB_SnOo3##YBfwPvO+KnAIyFJz%kMldWzj7ZTD=zQ0_vox-hhVeuM4OLHu6C?>K&E-nV^j@qPr$k07W%i{Rc1b3gX|JRCfW zR-T^*_NkBZ8&E!eOY8{BT?o>a-$3OfSbhXS^;ral@?SuQbx^>ibSuE%@;yKxIIDx; zq5wg!>gi<=^m2PHqQB^FFZcFK=&uXSL2E2%j2&&kemxhuik_mQ=qH+S7Om()BQBr~ zz3Af$wymO<-Ahod*|&hIr7eF9`Ab~QB~-J!%#QNS4J!P2S7%`pn(~73it6j|ZLglL`2gP%+s_o+&&ups2h_5&rI5mwK4$7Zog_x#XqX$Y zNB7*VyixZy4K45o&K^ zF)lj7o{RdZDL`N{*9Zh2MED{ja4+L&UXI5BRQ0LBE_FLb@`74+v2Pp&u1?0Ui7@v8 z!rX0zp#$?Z%zX)ePvG}fADH{yaIg!F43}Lz{}Ih5xyCQ?g}Koe?zTxRt_MOwzIC6wgAo!dnSPn< zgjKXdlz$o$S~Vmb!H4F^$wv;H{Aa)y?J|w(8}VdhBQaYb+grFZAln5&DnJ`9GN}+Z zpq3Xu@K|ku^$c`S$X4$~K_&%40K*33x18{;n(*!3LdKDdDCM(&I4i1B3kL=b#&0>{ zQ#IjJ+H(8ACn~r5VZGy^jhh*bHX6{VS9BP7bcs7G(5e?5yrdCE>LHqeRsfHxfk*c` ziB|Sc8DC~R(lE%j+hf;}MKN`sPeGPELKZBXIA#EBg?^bv)9A;SS-RH{#;zgEs9clP zn8lGjm4^3%0HI8nA7~^7|l4I$L;c*|y$;=qWmiex_OEu9$7heegs>N;I*Da7DjsCL$dcN*;z_PqQ_I=U=+&u zeguj7@LCp5M17R(EG3ic`$r6+4y$&!wCxg$1$NPVmguxBlF+gXSjo#S00X|ZM_PGV zBBvend#M9-UVEdWJsnbue zaD<&v5YwnZsED(0OiY(EF_i^_Ji@XJWeRK=l(SB_ysRT6B%RndYxh@{DVXd*rs#!C z(VKxx@n^z?s~}St>jf^RlaeKwg0L}xoq=tK6WgqWs&6yHzUp8j9g(P7k!}2Rgf!; z_4I*4*G{hJpA2OnR{)Xvl`B3ioh&tl)UzC8~L(A($)Ju`Xc=CEh3ob9H5 zvt2J`dvc|=*N^n$WX{y9*8UFF{(_fNmPqd`(tXM;Ic?c-I#(3l8k3@KYGWR?QTIk= z#d)$(RVpQJU#+Y42d;&EwGovKY+q$pP0e&bEzzy1>76BqNzRg1$ystZIZJNr(>j48 zx9V#GjlQ<6^NW>Y9COrm|3+_JV6NxEI`8H{Q(NoInz}$6J~B{RyD$;CR=O7slQ^Ef zt{D~@I2=0JDibdNR+)wLW^J-bgZh+Y(kSFnc(PSO3Ku1FwKVzp;~OpBR@h9mv0|eN zLq-}r+!E5bv?v0#e)WkogfN9Tw>-LtaAjT`VLI#etPpx~$}x@Xwx`H1-~f&)4Y)14 zjs^dOBhQzOV#WxkAJyvC^T8*Cj^%J*ZnCNfdq+vZO-I@e>VQ*}xuXPD zn&_?6kbD_)89phP+m0_YXt1~@==#s-*=3?@8$Mg08UO#*(RFfP=o%|`hZo0na z+RdArS~nQd(7t9GaJ^D3dHfHdbGi0JL!@8qxT-(Mf1enyM6sz3g-4mw-&Jlg7l zGnQGOLgp13FDwpCg%?!!jY+kT6N=caYp6w^H&}%hC{e6JgF75FZEmJ%gGrp-ffH+o zM1%C=A$sv8dhs~Tr!aLkM8ORdOrUP-Yr=ih`;?hQkvJ~`l$ZyhzAbov^EL6fS%+!{ zo?_`d36gwn>h)=tE^U%G1E(DZJ9)xKf?YjQJ$X1KdENBst->kD*Cw5B0oq7D44j61 zY*On>*D{+SWgmVXT&6v3%QTM$PC=eF=~^bIAzzy`Eekfw{x4h_dEBIhZ<@5^d6NpY zvLG#q0wUyhleTSAn)Dtwi<-8iw2eG&QtLy?czs4s8-2vlBEFR&V)V30PAQKndD`&T zd5VgpnUdt}Q7=1t)R)!^XAg3{naGDz$XQeTJ;>{3yn=%m4K)~CJ|-YZ`qgHl#2ihM zm?IZ4M_1zVF(&t#xP07%b%s83CPN}=t#J`WQaY`~5sS-|lPt+u)G}+te1I+4uxCT# z2{mc2tP0qTtfB2ryY10-+`(aE$_2Ou=-Ht5yQr4I4S|d%(6Kbw?9f8mNegKwU87xd zgs{VyY$s!~os7wL7?a8Hyc&A^)lfLChQev}TWr@JNxGkrVuI>M}RY* zx76!Q=I!YIaQPa|+cj8d*I?eR!Mt5_W%ITy(|IfN8xHQPq*0HrH5YhY?UN6q+1s9e z_72F0@sgXuhmjjBg8}@;8t@xyt`@&x$&lZW*I?nn^a-rN84Y}YbD22HOxEDs{;=9e zp|8bUHjeCHJeR50eavP3z!_@#LeX^zrhV!N1U?P8e*&BF_hIGdJ-6tQIQLoA9s<~5wvjx3N^!iMiStUGh#|yhm z=M1Tv>|4a{8*gCe?5VS%9?KhfbP6`dby3RDLESAJpJ&5f$2+C$< z2cXilv-!-*<}>q~B?lz)SsLqE9+|-s%2IB7!g@ANGJ_e6ZWH>==9IGO%1ajkpbzCG z-n8Rr5T3XV&26>U#6ob@)RzsHp}yp_8L2NhWxwi6PBDP`lG9|QzT}h{sV_NYzv@d) zF@XA#(`2N+{orsDKb)Da>|UMl3+X%OyzyBZGpHEvg%?R`+& zu-5lZwmriW$K=eI4m0qLP;=6EcO;Od*K%%4(Q>A&e>>QJ5DWm;9B^KVT{~H}oezWf zk(Sf9#h~Ft7E(>X8(ge}wCdx6But7cQgLb;PMdu)={HHescAQ%{(x>1s!gHUBq@sY znxxj$w3^Sv_osA!HqM5$2e1}9Ek3Np&V(Kf?MU`$(>*D*EnYU8>1#IIQVW6=b_8pj zU$cE~Fm`!au*=JiU0$?h1|D$O3I>15XHz%FK&1-N+YIQ0y3D7b9)Q9LPf)O$PvQxS zG@ihkm`|msRK*f~UGzt+fs#i;=vDvPBeCuvw5d?03SH_aFcM#(kwCD*j$n=RD_3tM zpdh)jkr2Bu3pA$qxXu&MZ|UeNC-~)j2b+yZijm^G`T{N zOH6Q@=|IT;B2>80;HH813*q4Lu;utB~{1VSXl5szeI|Db0`oX=^=W{*S zO>sf3!X)kqKU=han5So06?94$!&P8c(K;kMV{7w@9V@iq$FLRBW;=-4@gjc5@jH_; zN%R@=9L*4Fr0O|d;yFnw<}*A6&hYd&Nh;an9C2LCi6m7O<^)ue*G0d=bK>tL>Lm2c zZfzt`zTnOYz;RfBBK@;~1?(y^Kv+N<~)s2yqy@c zc09B6@KEx2fy*CoywE1Ne~ZCN+HEuNNP&>?1_;0q@HpESJhYQ~;@;p;lwTJ;$m4RC zG%n&mp%k4A#wBIF;QeQIAMZbtX9#VS5}TOBDlwR}|D^oabpOe##DV$pDv@TQ{8a26 z>TXLwJW$8bUY`u@#Kxr*I1acn0O=3Vvha(f%}Ss)iB*8s1Q^z^3c#?2H37Jmqzce+ z{%Zu=gg#*Z=O9=JeE^FUK$tXF4&q4mzdHJW2c&@&1_6D-fr`Z^97u&>|9PLJ5Bm;; z4xmS#Kf7HO2ngm zo*YyERMn+Z>wDo4!`cZTDb1u_Voy>?9+sgO@jH&+nUvMYK=P<@28D#a>MJM7LIH&Y zBA}2UHXw=QK{pd8c^yY^%3Aa=t0uzISO|kfAIlJ!GHDsonKCRzV9G2BvvbN)avvomo7{4 zl=>T3mIjzj11?Jf9vLo6!Wi^PFG~{3oQ8;9rDX|l?3Ycxl4Xft+uyR(DT^n< z!pa~~qpQIbuQ>=~6KqW|HKhUSUzaKV5vUJ-$MHM!ql~GKOnOc!C&?C;Ia4f;gfNI* zfuNXfb;v|yC#l6KvhSY{JD6?FOR$0oBUqX->RV)o>x)r+j#X-4ksZ)pYC*8Vj$n;5 z1@Kocvcvk8xu7VEC&C1GP1XU+U%C#+6XK2N#aWTuoz+rYZAh#L3GaZ$)Nqz`otdctiHrRV#NhdPSQe8 z5_g)aJCxBnRZXZ%4DDz^f+GzCSPX1U=0q=^^7KF|;1Ki&r(waDKo<^O007#NFX9dx z{S(>|Y73qA1MLV&GI4?Bq(*+Cns!7>XAAA868PLO8m=yBxYB4y-8zc^ z0qru4(|44ff<2Rrs^(K{ROMZ!no(6dX=FlwHdR-`rn*9+pUa9xE+bE{II??uH5l;oz+B)cgz zl{N`C1@Ho5_mtSeifk!93NXw+o~t;dk_`?DGw?e7=Bi?8bJa{~bJeUX-CQ-T;F@f% zGHl`{z)i2IDQl|_HhY)0Hngq9dV%W`JWls*iCNYRx%zRs21PBKGoo?!69>8c2O28W z*5AclG8+nB5eMq_#E;Ki#708IMscWB6}y$d+%u?5XH`!-P1={#EAcm~M; zG8P*bkB7@nh7T0&SF28{>yHoX9QI2x1=FS#v;v8uwzeudUKOW3vK=_I-;NHT{iqtJ zOD(6P#&7;cj`M!8%5TsDrC6uOC+2I6= z^lgWPXDLVD#;s-$oYFYa0NH*PN46iOK{mtbw`In2qY^kalFv*-u*MEVfmu?+w-*ff z_DbA!=KQ}f${CK*MIJs2Z6yBE_Og_+40x9)tGiypyVZ<$E0gigsMFK&YNR-Ad5s0= z6*?d=>;(zKULU~UMy2y;89OclJF-nUIEtUT1g<1)VHEy0h0zZfRlq0cmx<1evg$ug zSfdY_;#}n6d?c-$c%+_?{-#U(T?rk88KNL9+0mg!Cr5o9Z4m_LA90sVaG*{B!Rg`? zXy@^yVoHM@L_}#4=ZgX#($bkX$phgxR4`3QLtYHCI5SkrYZzzF`+elqn+xLNr81agcEW^Yx)No&()}qWD#d*fl`8v})QReHGw6zep1g;?YQ$tT z+9Q(>ld1chz7sA%J|K=4Mqgx{_+-wW4M_Nra`tSTT!09}u$%C<1Co3%jwIipu>`e^ zJKTe`3qnDMEMh&1A3qC{KnD{Oec;21K_6Hzn3g^q)lQXtf{IU+q2UP81wM#4xeNoo zXk~P-lklaS@#W5Bd;w929~#T}0D3@Y41*pVN=pxZmE>qKQFgQ-V$j3WzX#JFWBn_A ztm7^$u(KCN&+t%#$<;5@wLKkH=0b$ZE1y1Z-QsVp{h|PJyDRJY2ZUL;#mbF0-;pDOrPA*sxr@- zaGAl<5}r*cYX7$IPO&DSzQAq zmU&ij*lBt~qR+Rh%(IFW#UQI>%(IHThH<|3JZthQblE(sVfE>UXPtUEJnOYP*Hq?N zQ_eMwlZ$K4v!I_KIIiIpU%FKfBfhnuzUYf}63>071oJ{0UNc}eVCMIY2xLWj+^ zr$&m7bo0(txg#=3orZq&O@Hwr6FD(`va{dB3#7*0LfQiQKql?7)pyty?=5-RZ&zQT zjkRcEPB>@o`@Rdtowc&~dTR#f72jk$;`p}AvfLpxwJ@<6n9jh}HUkq{jM30SeSzCM zGCUH9(QRz+JZUFzk-QW5@~zg>`#li%Hfc+*VO(bPo9$L9o8cT?=(ZC;5O)?Wf*A58 z(n~#Fib~vS=jh%-=jcwmjB|A3=jZyowatG$19>{*Q<90=r<=&rrA;y@a@zDp@}#r# zI3*d$`!T+W6A?KjnaHKDBofe)Y&u@qrsFO33Y!j@%gOAdeIbzYr5JU{OfG#Tk<_Yk50aio1TyFJR4Vw*=ha^V0;i_}7IWwR!58IhNY3Xb z%$KO;2>RZ%Jz{Ooem)yyw**HfZy8JQjO6`&_UY_(_!c!559#oP)RV_;{gOVbMEVRA z)822kVNx~&#UzAEU=H66)t;|}V&)LVv}8;%lwhKh-(_a zqloLu$fJmB%*dmN>&?ich-=TtqljzI$fJmB&&Z>QYtPW5i0jYLqljCOp+^z7p-CwL^f& z#Pf&i&(AC^w*U(9Ov>dp^y^W?HBUonsZ>Hc@R{rD*Q1DQ8Nj26>lwhKh--pqn;tiW zXA;*{h&1xqC%gzHF`#~#0ri*q6HZ0)*(aPcg#{(QB7%p0+y|#JFrokNyA~M_G!YO? z%b&`&muvg6?ynK!A};N~U+D{aLM2wpyMoD*BI`{LAQNmAaKisD+>yN^z8M}FF5mzO z`;-`5f?)lHee=Ls`%urtxUbP-`2%`YI9-%I0AROB@;3T2?0kPtvGYaIl=I)GTBWbz z>7}p-fc7;!w&RF044PHg`KXNUje3XR4R9~nk$kHSHY9YUSLz5Xz45QxRpGm`E_ejdx9e`;ZS+})2z6yOXs$spx@6(=b)oZF4Y10+mfqm|J{x>x zCDbS98uTp*N&0XN0;mQuvjA0e*B}{HGII@DLLNby3ji$lBtqpP?iBn5@n^BSu8$w4T}3Mp!4ZngO-p_5GrDC0JsJbddNn&G-j4t`6wP>2#(?* z3}N3Opa*<|vNYcyJi#}Jk>!^u$b#)1x^s~HsW>~S#q9d8i)K6y5BN*ISlu8YMambe zY^L^uW|lLR)hz;Mi8B_BiNg^g$Wpu*)N z>1a`SeBsoR!su&E0c7>)wfnO47HM$%@a`ch-=}vE=K43%3~|5SJAN_@VfGER2;;$Va@X@nq?`7}-?3{BMd;p{e{rUtxv&Jr^`L3+&oL1E*N{mN{1FAsWWQ~m3$E*KgVwrtR`7m*urWmNnwPGLBtS%X| zk7-twtIIwnuOtJokMO?8n0>rwhwjEwez-nNE+Zm9^jO-tgbpgkY=-3 znu*>&Kagg#Segm`m+%A0o5hkRb}~QU?oXYh4fyet0hhLn_35ryntaI4y#pPx^U1m^ zvbjtsA@q=r4W^5*YYE?pfW5S&XT$B4x+^N}7G*GfM*dp3DpKnQKFbFmXsM~GuL-o> zeg8&p9h+_eg2x@oD2j$Zr`Oj|Tj#CekKJo$^^8*ZQw{aoT5DUH>f*1+?-1Xs=6wG9 zYyIA~hUw&DLvAx#HBDMPMU#h2N;O*o_czl^a*0Xr9cUkHQocM?`7Rxxrh5v~V34Qa zo^gG8`6+uR;nNSfHH(U=C+QDhkS$?3734Kmbb8m(fJ6P2nx$HHY(oc4%JxCwW7F1H z)lPEYhJ{(bOv5VR@n=y2v`5Vfe>N-JrpHga%eq3dj9BjJEZUDuw0U|QJ_@dM$_~R; zc<;dx&aOKI?m8Wq9D#Ent#nRxSgc4Z#ky;MU@-jHEZtc}r_qSeL5nDIGP~EksW%5r z9gZTa;4vM5+hH?Y?AE#S=Dr^oG}oUW9M0-D@g-sL**wz=e$t^3q_@^_uK?OKjw6N>ihEoI=fa!)0% zInxNy(PnlH&zt*3Ab;-q{J;&N?daFcq7T$6kT{n*Z+gj}0wXF`>Ei)N4vW{nrV~5d z)H1I9<*hHNE&02C8+=C8teLd%b*w>3r(7>w1>wSo{fp?AlZKn&vQ&oTZRood-=8Ok zPKykc17`^uR&|A2T?4mJyG8hP%3yxxqVnW&C5wiXr(a@h<99R*^lOQJgTFx4^w$$O zuFX!Lsdv+d==r!d{aa3OGE4rJQ~NMwXkA;&=4S7Mx7I0-4aWP~t#|Xylct5$%Hsu! zVqUzgv~o~QrDt`edEwoQJcDW$l~$ITDHycy?&TGg=9&c+71{XlynPb=$u^5Q43{*W zL=p3)3>hNg>E1Hbq+ILI+<^!@zWLGV?Omr^@Za_3^Ynb+^!AIVTdatp=UhCuT%<(D@t{Ro-#o8HzS-?T z9?Bap=4Q&~(uzT`x%6yJE{39>PZSfOPg7X-(FHYe&ArceJ_pAo}FDVjD{vbko%#9_$A?I|91)bi0&r^=cT8?x{&TtaI4?SC? z^-QmG(nAx_CH-mSL$*`DJH7p<6dXGL3I-QI&^nQ;cS3L2))@~K85(wk+9S7)+IR+Q zmZF^cqiE)ILo?4LXP}-PIDLx+InYCqhguK?(B3%da}us>|EWL*!iNI{l0)57sS8?~ zL5T0B;M7^X;-m-<|QpyvWr5g(t;kKd$B!Izw7R&LwOhac5c%;W~mSZPf9bpZS&IBdhdf}i#G{>uwh8(R<1|E(~}FHxsduR zmkQdr_d&&E#{Pw*a^tB8Uf>nPYhwvaCG+C%Hq_S!YD=|Fh?M!1dz7AHw%=E`xi-*P zT8r6*i%+_$Z>a~7Lc1#3g1$O$Io|7>60t<_*NeRVfc{eFm*Ougyn!;WZ-ZCom!>E; z001-M05G;H-Z#J%eb8AiZbgmHyP?SsR*#AzPvY^46JB!(SeBO7%K3FyVhupxru>20 zKvUhKK%1{<@!Bm^jP6RT!?ldV!XEy*p@(udVfG5#2ms0o1SxK3k~M|^C_|~=6Afr{9dQs zQ}R4wey0(X^lzli2nHIGxLjI2TZ7G5%K@Ip1}W{|88uqjv#n2-8AvXdHp|;u*H-Uc zjFH(2kdGujpFdeAMz*e!JuQn8=$AklM?9_H8)){nZU{6sRVvD!R%KXCO>ODs&CT2D z>ZdECQkm|Lbg@&r_V`-+?+sLRpsKMSq}kE)|LlFBc#q&Dnn`->ZpFj zQq!>62RW%h84M%=j*D73ab0bIy17O~wR*R5Y$Y)t^)>n_DLxWO&)WSmEBU&{6m_~+roE4Dj%=os8 zCA`EOUV_jXUSba~p&g=b^ura#Yit6u;JE!|Th9u@3D42(i7maW{{Oav30 zJbo7Zw%)HOh2na6%B?s1329v7ia$@89ZcLKjjPG;no>Vyii?rPTc4w>LoSqq-+Bxv z#5j2FD#|k4=erbTDt?@lB9pE`cy7m!@ZdT8^o!co=k-Ls68%!H$q{`Hr^ZB|#!=GI z4ia&`Nn zi2=!LByiH1F^Z7*5ucCv0#5%EieIUxpM&^$oSu#aQY!TLC5T_9&df(##JnY9{sp~N z$Iv`gCr~WjmuEkVk}EO3bDy<^?gx7Z0kkmkuzNlW1N&k#X$r(<65ydbSVliCe`Pr^ z&&jvNCflwt$ccA+^bTIQ_(l8e^N~%l?L1GpXF50}^wvvi#J!GS4lXf2Ug8NFW^99} zA4)9b7e&8?RwN%KlH+7av%B0Dir}s&rsKD2eow7@&x}5;M(@^zPe3YO9myL}^1gq? z?%eQ^DTFqmURU7Lq29v4ZK2+xz|EoF>47Ps-WdT`sJA$9U8r|vAUD)ID=;$DJ3C+v z_09jrukn9QuSlKuL)_+}PG>Ce z2Xn0W4^LZ=h>Jp(8`0(FU9sS7bb6WXn??S-*dq6RsJfYcjd@5akRx=^-hK1R@ThwF=ue)s|PYzh4um&jT4yyg&w zj*c-Xgz~o7_UPCC9E%C{OFf9mK_!ZV|HgKV&NbcCF)i10WAt`H2Ri%Qe|L-pVzN*jI$0;}E9l zJ|}{X|IRfHd-qjL*mu81!A=T%2+qAr!C4A^g&^8X!5=6%MRwl3hLTQTAm5McYWm_4K(2CT+*6cQcw(A}N6CLH4Md7^OQGLcK{ z##p@yeiw9nGv2JM4`VMAkiW-5O{`uOJ`@XDV?hhI0AEeps5G{NVsFgesBAP*3);(L zoE=A6Mas_Vibr#3do>gELLbF4l)xvc(6-arWD@7Ui(#5>-)jG+fmcK33gGi<;aQ z>qaF~*0mxwORYAmgIC6aQBlLL{lOcG_9HjZ_42MgC}VY+;zQfJl)#+q^(vIZT3J^YuM&K9+A14qwb4?=o7@r%T+^hEid@sgC@^(w#}{)=&gge@O%tL~dOVNEb6C|UoWsdvWA}}x$JO{Q z-M%gO{=vBi2m^;#ThG%wDO!Fzw|PRf#c+_)S2&_IZl{omotR;H z+~Nq9it3d*>7j|^z{IhWDm0HPAEtE7%r%XRPR%vhmCi1&`7(N;59U8bL)H~d^^Y>^|s5i&9vkN!3Pj%7S_6FS&4`SPS6u0M3AW+xC)wK7^ zAO30Dufppu?JnzS|Gg>jxkH{F(_zmAyaz^Iq(711g=)3TqIxbxDlM^<((*0dT*9vN z{1u`@!eoX8ZJoPNt-_Y23ut3O_!N#XDR{p_Eu*xB)9`zmcq>Y={zCZm?1$Zj?|%=h zTX$ik>cUDjcp)-x#wvyu^#PkVE@i(w?PX)0k0}Sf+jz+o?CqX)*wafXyR&1S-uCT1 zO28fZ)91E2DyY0fLCDZOEK+u1h1$sl>sodz1AeL!-9+az|FKDM!)u%d|R@0zax?rU=Cpeb1uK*96r8j_bHe z3TAQ())mZDqo$JLDW@x#-H1=9q+n=Ty>vm=>ZSPOVI?)?%hBX(;);i9_Y`l%J=vyK zFGQAw_>;&oT*@*+%3{NPLX91QMoY-5i@eR=fOnw=fC|{(n%Y_+%U-X&UkXK7Q*Cq8 zLut}X(9$gP)^6$NwTCQtsWm8j!Q-1)hS%ZmrIge`A??PaA8ZP&qF6}h6_rbC^mx|N zHN;;mO1wZZEnlP;%9F1$53leMHrCJ_C0NpEMZ8!;FmJ7)xk@lkta+Fw*6`>swmD;( z`OVcLk(?d`1xH|OYaEV#0I9&K*?L50=yn<^B{)gSbC_fa7HSUjCzptT=m`VUMI5CF z-AuUE&pmm!P9R&+i6tf^Jx&Sg>w45FxUS&tI5M)KI#B9u? zU^4~n6f{!sc?$MY@D&Pv3@JJ~neJ|(;9&|NvY4Ykpx~zz97GVGKMZVb{+K9sD7BR# z9gj7tdzJPf%Ak60z|zr<+>Trufv_yBk=>#$tm8htjZ4NNDVU^fe7l z&A^*YG(OM?!64n}Yuh@%cqc_%M-g?bu+emUl%tIe*8htVOyV5A+E#xvlsYwjFYMXK z5-|gKAaNRMj^5z45H`i)K-)HZ-^0k4l2ATbo+z zMaH<%T-gg9mH?+{ib%BslAKV-$+6RONOonFn%1ovt;sfe!RCGa#b#eybK8cZlz8vv zCd4nKc;(6U*$lUj}%rw`|wNd*xYvoXf3>5EyJc=?}-%uCzY&va5}0r`vRR$JtACoJoJbeOY?j5rs|Bk)||cm z#qj#G>I`h5JM1|ra-77@S6k>1r71fZaV(8E{*hm-KZ{efvX6zUqM_{a$mmgl${w1yYM*Bq(Q7VwpQI}4w^ej zg;c)L1g4+5CI}_eZO?)JCB%bENEzC0RRUx6#!|hd;9acYQYr>a3~X!2Ly%E!r=kLr zZ~q5H*&mp4`xofX%-cae_Xj+;|C#<&o!`Llwx}x{=vwy!jRbNIx^|!s*s%%#cCTe| zT0{da^yr0+h4IuCiRgmHMe*o)iRdwnmGNk7=g|rgEe5**1l$;d_=7Y`z4(%~CM=v%gyGp9;fyEdG8Q-vlmhr78^ava_CIUf22dwmwhpHZRtpyBVg}VMy zmDp2FpPCRNY;*=)>O7sPI7<8Nj&qNaR&~yKQqkQKcDC|CMVR{O(A+ zeK((i&rncJK??;DtUvD}arV3ai-M04eA|u1<=b;7%7wO(JFqAYH1s|}>YDoSZxo!9SoRX4SPsw!>onxvTs$CRZXokrn}-4PDwIGB1e0UVySPbZEBrif=G34V>TrZ=LIIZ!K&7&|JB%zt1k zYG~l-nM{3b*3}wTOfRaM%FAolHq8$Bws{`()|D+@ggU4e_Ts3iZKlPF&2*U0kAGU3 z7w>t0*^^9hMKHy|Lc^9gaAY;0?y z24L-`R&# zPpg$ZK>%tQv1^NcUN0mnU0PZN;qkvV{rma3$_Kk^D*y-)NHNu6Sp>|W?@@P z3v7yHV6JQ{^=;U)YW^H>OLuq!(wkND3)6617=@)E6>Y5*JnKC?=||(alq`A+m_CTe zkrc@^hM&toQYfDk1$rrF|U_(r8uvdEZ5 ze1kHvG9hYWVdxPoTDZ8IbR%8)xF;bA%W{lV`gCz({Ov;Aa*h%A_1eAshw}dmew3f$ zzexcuxAEDvK_9{sw+iKjlIQ@d>|w!;frgbkY0$_-U`X zjw5)!CF#=BgB&Yo@uO=Feol0d+MC?pGl(nWREk3PWSkKTix#QYQjhe)af4sLqMbuO1RD#?KBWNa5 zk*6yiHdVPHhyIiOxVt z*aYZvSO%Mb)G73h29LY-4Bb7(z)I?-rWP;nBG2O#eSIID)-pxPE^dsiXe`%j0TIV2b4{Z=7Q;l_@lP-fbsQuB{hR>w_X0{e(f=UW zd>t47J-S8cQ6z9JPvEF&G{6(;DLCvoUVtiigjqa1>^VbqLf2e&mLU-C6dGCBMGkv7 zhD;B7To24A{14`W3J4YFA?*m6sytG5Togd(l5~~hRFwm7XRnCIK1=+3*mE*mbq3n| z7^I)M!LGnVdU@DYA1nTME&vH3LX<sg7^qF}fdjw9S9=K8%3t9FW_- z4|qNN-1Qi&j?a>j&Wk|lEY-;@2%5uywA1j$fV56l9-M4{@DhalH!+$(AZnd7%`}uc z{{r5Iwx2;dKkn4^XVkkK!|t++om#P(FCtfL=5w6)jB1IkFt03+&HO3HK25PzXJS5Q zY~~L*<~tPn95J6gHuI|-^UsuKygDPc#Sz(g@A7T;8o8n2lWJkCn%hYz8k3R% zsm@r1nRCD=K38s2A_t}PxuAyG^?_|y1gZ!iP*8+R&!P~`K!Y`CoYHx>-X5eMD-1ZC zJQ3{N9~jk0slc?Eq4N;U;rEAFDPl^brJ`pjWczV;fOw4Uu+mZp?Zp@(GL8-~4x>A6 zCoi4p;OIJTBEA5&R9jrpJ)bbnXeiPeNawpZwQi~PHPv3551=nWMd?%qRDWEnEri{< z@rDRdU2oRng_@WHVHd(N7`Hy;N8PA|;bfx{?P{WW$cohOP9`@51Gohm8X(I6#FBt% zp2mMTz=`BA${tcjsN>X%LhNZWtA}Dod5cZ(clX|d5z{xC#5S(BcS4`eoH` zlK*NOO|mlEXrkpNdth@@gE!FB;=L9cA(~d{hS!Do#PCj4Zh`LG9XItA^ zx3#nd{r^98?*d;{b*2yRog5&90|^phgeV6%Kp+tlNRSw?U`W6!67Ci+G3H_dfyCq- zBGyYV&~n(Mf0;T=J5y$KJajs3XLR~?_|!TrG?sYjcx~0GPK(Y-f{pFa+7Z0e^F7bI z_TFdja|!7DJM;VY57yb)>s_~Zy=$#^t@pB=xuZvzy9X5F%H359$vv?W(4pQD++Jd3 zSF9>w8t>Tx3{W+=OY4XW`n9&1APF8vS(dpUqLj!3pLr@}S_fL1uNw#sVm)LYuvy=s z5sL^OJjF$9mk1s|Ez@vDU^lO1Ax^@q)Y~^~tXypMUCS4?FKlXSTU{OdRI?45-?obS zL?sHc6RWa;{X@$&oSwvrD0LRma^7X|R4T#b!OpczP6jM=v(@&=lnsL;FC0knxJ;=r z!{(tzs?U=tvul88IfP^mdH8H18lO$oXMBgk%%Oa!8uQQ)+1Y*81aHk0G0XWR-CR#n zM;iok#Z5&VZ*;(k1k|`I+n`BaA5i+&k~SaltPkR?bgU0}&_k1x>vktUaisHVUI)%* z^Wem(GmiYGA=-KHs?^VgGJJ>&~YG?ozGL*}VyH z<&bP^e!&~gT{FcBq{w3Xmd!+Fe>RKgkHsT7j*_ef3igDuA=q?J^2S*2ot?SXjW;1@;z5bbGK7rUyI)ToVkeX<99&2 zETH-30?SBpf%bRDVkZd|k0Y;EK(3d%Ts#irx1TV;V{yaGj}MRR9>A}aw|q2%4EzSn zcj3Vu-_2L|&*2#wwfioObYl}8d4N3l0S4`xav~e>A3N$Ctq%jxtgyobgBe-PAPPOm_s`b>=vAr zb7jN|aa6H##rW^4T&c5i&5Tu#K37?P%=i ztGyM#%mgYLwJ;&1dC;RS;g&8ZyjF;ZCk5ss$DBRy`q%eYo#ZF;oTtC)UH-+rHgprm zM%NbLunAs0u;b=mK6-wpCctP>ipX}S8omvhiDw$U0P4W2Ba5@5t8kWC6iZLahzO2) zjNMj)RLfL*po$C)3LaIdQxjwLNt_1WHU9aP>~tv`^(wx?Xik?iUwqnKzB2 zL+?j7h9At;7jWM{PwNX>Llu+2L^;sOrVg#-AAoalBFWGqlR6dRh?kbk==8k1rJG!l!T^m=ZZp z+sKKKEbe|&4?+>+X&k*}9VNM|LnDyIFxTnN?+~0sMimNw{g;qah zY<$Y7I+oBClQk;c&kp|^x`NvHvyR*%{jr%SSC4)Hh6GGHa!|y!R<)3u? z0u>N5EoBms_hU?$oRV-3H9LGC8WEl@q6#O*U|{g4!59u+ofw<^|4WQ{i807QAd;|` zNNj@CgT3TAtrV?ge7>;4?$r&d_Sn%_56-r>nnqio1kC|N?TuwX!Wc_dIQ9M>)cR$X0uf{B!1;KI)(4K)di0AxLLOO!CMiP112$yVqff;m1j((?EE=c4 zaQX)3!^S4^Ct-UY<|;1`rZFP~9@e8@>^i<5!gt5FY8f&%o9=BU4`@askwSTb0Z89tO!E%@gJPCx;XQC> z9R8bJ{j%`mx%&Jt&Wnp8r^tPMpTT%=a&O`QGjbd+H&8Qo4FmN0WHM^dfxkR+PdcFnk3&@vft9rYUxUee)zR=9Tm@X%+&}m20t@a|BP|q6n+YIR&X7tqw2toRtFvf^N@94tLi|5J%lglbF(x5 zT8dPi`6Sz^I`hZsv-D!b(Tljy;mw`UTvfdo$=dUE0PcoSm8&Ns?8!H!Cr`!oO`UZ;?=>dEw~k5${jl<8C^CHEq24^^SQ zPbQ&-CzH?u43@&Ag;St~BRXjTeDv%i;4fz#c~uBPMkO$bNB8x-n^!3)^vCp8*kQku^~m!TFLjJHDm@k0Zv-~){!qGQn)xA^ z+k3TM`0U!X$ig&7ndRTP%?Q z|6=0>6q|mH$EuUpfLJeGaU;~vLF2JAnoGHCLHJ&@JN##qvp>cF${G;%JSy#$K%cH$ zgwgm682x6@y$S!eXC>7g(5Z^u8Fw&nUw%9B>@ z%{|8&CjOo~BeGHDzrT0VU88!=Hg$UY@rn94+#?w;gq}Xr;LkaTAUpk~A2i^5$uo8q zkWHLe`0|xMlYTX4iLkX#b0@$FzDJvb_#x z*O#N~{id~5s2_j$de`WxBhmh!XFc-DI+V5yH8A(78~m$69i#!WqcCnO4UNVwb}_oD z!1&j!N1iMEKvE&LG`)si19Grg25*k-GJwUZQlXJouwsfVAZ4_ZG7ge5Amg7!oPsDG z5#%Tg`5l{H#S^RH&>#9F>k(Sm!Ne`=kr%)gWv4%nFef+;JAs$YE$k+=tH9)?nNH0c zk2CAwsK?3wtOYuKSJ?;-^(#8!xWNA&pFtmz^Qv8ezXUw;bVH@+T257J zrszlYcz~qIEQ;M>fqciP>fMpPdw|Bn6~7JgeqKyHnEWtLC|cmuKdS4#?F5k<_Q$ zT`X{KFMMttv;sMM!u`T%b_R>Uudu(sWu6w;;20HHTsW5U9G{Y4Q%wUPOnL_)ac0Zt z0zUFhL^48b&8=fBboDwSpjEmWq7=;L^5}CxLmstffqh#@7ym3yfO$y(EZfa)=8-6p z?}ng3Ntpf=(pq#{QfV#g5|h?af=7`QjSsGB3k2FkN1akxQy3*N8`|0_jKayOc)ntS z`nnykSfJY~xbR{m`YMI^U?juN0|hC?2csxYZGdB-+B;fm>mUw+ihmkacNNa!PQ+DD z^+B87di2bOhq%?m5=L4zAAMZtB)-^W3?{~_?8ci3fnll)sbO**eVIq5IPQfq#^?yP zgQILgzp8?jXY7{>q1M9=upS{~>ksFzDd_h^{M;$!^RU{Y8fj4?)x=Vp^aCNp{~rB_ z$%m4JzyuFuK+w) zTjBuns_f02^Lo8~$eB}`cmW8dht|VxE(2w}YnLIboytOdKY5HFW7^7t)7bQ9D_-i% z`FBjc_@DjnTQdHAO3#n8%b)Fd7p0atN}W)H5;8(LJjX+syegha$K$4X?;BU(o_VBs z&+z!!q~(ruS&no*r0ezeGFFuk?geE(oOrde3-(gfZzo5jL{)uWz< zID8~_MO-XB0YYOT&fr!VGhfN?E(_fT*!Xm`?RuFJ4twQx+kPd5wLhi(%4E$lbV*_N zKdM$lzvps5pdFZhUQP(ch$;z0*V@4n;72UIE$l!(y{&*8xy#fzxP#w$J_3{Cqq_X| zEEOg(I9b*&rFz{zir*LwbA5>pOjh5R(g7$Itm}Cw8JxIPd6*IV|5JoB4-g&TINso~ zTJTDk&-w)hClT0|Pu#j$pqja6$@kt>-nFVO2JLt=Fd3QIfq!-6*mL*CT3}o>__3tI z*)B{&*KY#L2Z38IhOd|91(ZkdwVs|Uw7|rzjjF61t1M2k@Ofa2hGDAd-yph3^6Qtu zj9lUG;9R-3CCSz3^z@wYn$8r?Bag20$U{5)9dRN(I+Dgy&|C)M$6y}cAd?*xhH)ws zUtx&KW4SRrgMf(#c@Su+dLj!M+{yr_tDXoB?ey@|Fk+>4FZ61W0X;x@j%?tcILSyq z@-@EwJ>Uku3I=1~D-3W1n>O%y1d$II{DDC)gMAEW>>9Zifz6GOAS@m>=08COr^%z> z>uRNs5S!E#vDL%us@XStwy*ipE6q6mHNBvqV72lhFmG-wYVM_1!WU&LbZ3(IV}Rd+ z|7B*UfxZ)J8*e9HLS{$!67{iuyUiviH+rP^6Y?EoOD(RLc%{3O5tUXi0qYBOmW3!f zIp5)2qTziXj<~S7^9C-2EF=pnBRuX?K9`NL>M1!kJWA|#=!2h&f%)j;=-iC^AuqSH zyo=acD^aWk<@&|xmi?@<-%@K-P})axr1Vd{Rx)$)ySFv&_!E&pE11k=+O5k_a%{gO z4wV<73ees&HI?D+bbSC$OmBnHtMbfCvJls~Zoox>wpDeV%>WZUI_{>#?XnxH45p>q z+o5x5DME{VE_YYTO4wa?TYJ^*!MfJYczCkW33|0=LFF`8my0QEg(JmdAKU>ln-;S) zH3uh^W$h$ee82~E94&KHD+`(Vl31yBCxDCU(~JCUR?(`KIRBuMO(`@W8)#ZvS#E#h za3jNijdnH4R!E4&CQFgT+PTtcQw+UCj+bw|8%$Qnjc8qNd zT*JjaK9OMhLE#ci19pWsTfsMuB58^~Tl3rawc(P}Bo<&rV`jT-@WrX9lKQ;Lay+gg zm*3V1Wmt}lnw@HNK<;W9q{o3SYBUMHW+z~!52?%R97%RXV3EDOy{@B?*;>G0hYnq$ z!98<)t;+(PP~^2nCl!9D!#7R>SZQZh9fqf5D4N8OktfGm=?s?kbtNNoV5H> zs<;DOsaIoSP7YSq)LM5N#=Alj^@A5_rHR!nYinxS(8BCeksT|86Rd;tpk+GU&L9A&3Nkn06Uh8BBuPQ$R+6MMY4N$M<|1=! zvJZY4Bt(btu~nH0**5*uu=|rzhgwS+?WR<-h8Cq#;7fn_4jMHf>@u>+{kvDrc>nc@ z1P0m3p<-=*Z1#xrc%O2~U3iY75{V0kgzg@UD=GpseNRRg`fjdkNWz*=R1k(Oh*|Dd2X}~1-Nbq2 z^GM_*=aM9eQgzccNb8!(6Vtl8=UN~s2qc}e`GToqY!VmX#B41LWsCs`?!`(1Vq>P5 zFex#!0v2Jn!C7h|W>%-hjGZVIX0A((87r+DGi%Nxfs5X1fXeMaWlH=A3gP!Q9)(u< z77AZXM4<&@qwussp`1b`uG(^hk%+&wXp(d3aIA_dMJnX2L&A}YN?fJZBZZ4ojZKtN zRFd^+1ClsbnfTfzTbVW@O$t6oig9=8rgK5N`V)o{hn8v;_RJMupYuBexE@qtZLMOX z#_CUWxlqNj3{Zuek5OncZS(J7yqk}ac$*#`BtRTfX73VX2aJg{@dc!Et}G?VQl+Ac zE$2~WB5mA&R8H0)S&>QT<3=QN@@dJEC8Lp>kj_QCNm}Tplbg>cg^N~d(aWs~EP>U9 z(#5CQL!20s6mO0Eg0X4CRyJ$Ad&M>HKA4Rj%_>_xSO$TIv2Q`FT4#zuoXm* zx|4+v9%TPhN2?1mt2#Z9DuW~4|l`>PbGMtRFQ zic0MNtw@n#_LriPbpJLaagj`1dy@5jE7GKx{iPUp=WhqJi#LiZAz?4F1O2%d{h6Y# zq%+&u6Yhyywa}cnUu3*{;+A;3D^I7+K&=drWTE2Djb_ZLds!`2Jm@I3GWHRI9or=* zkD=R;yj;87UdLjwvE<9^wmDM8=g^KEW^$uqavHH55~=KVAnh(74T6psSowwy+|*9# zlUv;NAR9-)id|uA44h_6avuZ55Z5In5?sMY4<2#pp*(>|u?{~V9f%cg6Bf&~01iy+ z8{xn;0BHinBMvOYDordx%C4rTg|Xv-Dl3~*4sQZL#ubnN#P+5oszkF+H7Sb}y^^?< z+2OJm*UZY@lyF^qO`P0KNo|5CxeMKZ<2JLBpg5NYoo^9YiJpMv*yK^h;qFGKM9-#J zY7r($C_PZaxWo%@T~)NYm{{Ej;DpOzQ$lwETHMMw{0t+LJMfv;!kX@fdH*gibj7V9 z^h7LvuXh2&HM=Y@feEpodbz7e)4#}_?$X2)GD`a*J}0=%v2bh(b)8MT3q66;0^G7{ z7TJPfpxnp!h%ARZ<#Hzk)w4R?6)PZoOlnqAo&aClvJD5fc-&-O3<;oFwV3F;#*$rK zZbq>~?nYAA=Cc^G)cB+cDV0~1dyv+2JhNSCo-`=u9#49-?t2kw`o=LM)vYd!>qeaE z?Z}Gb#TSg)osg`yp>d~*yAN@^;1*-OE&v_t<`pfS?YQ`~YA3Qz>N6Y}_QVo3G$tfs zk$cc#GtgmQ)@$62)<9D4EJfTK8V+q2Lb>V7k9#{=o#@U#2EXM-pc$33q-Z zaifw!Ro?BmnOUW`5Jizmavv^mv)-tjr)URuYNmQ!5{)-ke!NL!n_DkVN$M38I#h%- zO_(*4>Ib^6NP$wK9-HSe-X95hFv@A zwzt$n;g6Sv!gGy$t)u%P%L9|()A6OA*W?19R4RfFd|gA;?Qvz)S)FZq*k^9=mISXz zQZ*m~$<@`pR$g$%6W6+(b|yUK>j;zv11+s^azup|d+EgLy^XppZUn?MqLqj~PBZDW zOtgIv&RdV3X=K3d$5q+JI#}DeJQ9zK(?#;aDo|Yk5lkyNCe{{^h+B_7-i{8K(GQ(X zr({o4Rhhp=G<4>hqrysuU!@Ka`!G57n(~dqB>s8P{NO4N->m$(l>$2}D-oCzjR&Mw z8oat5IfZk5iT%+XdrkUgm6tT~Q+zbrA^Sn)=td>B@?V8NPvd_!{x60kmvy${@Tzq) zFrQ@jvf@Nh#rnhXD?(uWZPvpYNOl>-CuPgf0n(1)7us5yl?Jb_@<+m_NTHeFGd?0e zPLbBCbS+GM1@5?!yoj`DAb6>|6yeTd!$h9V4p29E+mFT$Vt z&`;s_b_klW7Y{uJkF`U`U<5lv|F}bs!D@5p`|z+j^e8;64t*C_r4D@y?nj1T`J6lS zAan6CXk|bLf9*gdap~gc(G-8Js3CTRuRP3=ky)M9BbA5;=(s=-?qe@;Wkz z{0tdHn7#7d%N99YdzIo(t?z2vv`$Z(ARAP4D~Cpr`HP=~hh1+@54OskX;R2Cyfo12 zD~=`8vub)h{>S-Yt+EU6Ih%%?KgZCt1pbptjxiJiPo!;)z?ljBhwEqTVeeA=9dwJUkz^51qmV_h4mEVajL5qPfZ{&V{G?S8=RS$HC<66!lsS;~npFuv!DE41L4 zl4CHd&9MBlQ(OKij|DQ8Ac6Gg`W4XVM>3T~zOqNfp299N$~|e%8@(>A$Ni z{|MGYC&W%U8!W+5D-&2Vz!Q*9U5*O87nMI9%q%%Z!%ZK!gJw>jmQ_ElAwwbF;CRtR zvOtIhnjPB}uoRv7LGB=j)->(3eC04O>db%n-?IV>6_hH+&&UGXgV(uB6)QYEVM9 zcp_hCQZs4Gsn5+Uw8ME?cq)sI%t83)VR-uPejqYgh8+|!B|m`U#+wE^MJo-eBMRLOGQ44xyo_?3C10EXb%_b(Z0t0n z23|nmGpi4WB-W$*XmX6I!3w|p>A00PBYiX7 zibLPb5dD17(N`dOGJo|sVP?j|c;8O|`vFCrW?o2*Bl3xDnrEbh^=lL$>HIQ*AhI7Kkb zr$}`8LUG{UeL!Y2BQlorf4ZP^wUrqVHm_#A^e#qOps<;GSMJ`G&f~NIbYf<3cb*JL z?XXuaa7NFKm+T$e1-%f2<1v&e_-se9MKZFnT+j+*l0A@akWsVP0eC5{c2%AbVXI** zta!CE^D(;NxS608uS&`;>~G|6_tif0A0z(*^v!hScbPlCP)TT#nUqVb`RK)HE)rf~ zeE_0Lq$t>XU=#IwU|!Q~R?yU5ivh=2TAsjB-;J670l#Dk9c-C)zAUX$h;x>3e(yIx zY{rNCzOMltKJKy1$F9F9oLFDguf@``{?xu=y}xh%I`cT+`YQ!3cNypNmsx!cOP6*% z>JFi!Jp8-a(H7ZjnQ{EF+vd>yazxu(4)#ko^2x#P{rF`&oq3&a`;>AI6MwenSloWh zu7A7=iUq`e5gHTY%yoq3&a{gsxBnfa&qDVVE(NndACzUW1m>FqXHN-~ao zt@@L`sB6L{EC;`=zcY{Xt-sPmaTIW#uRfk_QccBd2;~)zp&la1H}kOCp&g!(HpB}& zhJL}|$K2rj5Sx!7m={hOI*QH5(D$(U82ZOty>jT=*nAAZ|ILJ7HnfF76N7aOXmU7oC4&nXq;Z!6!^LHTA99!Tey;wx!QXS2 zgA3EI9Q-wRIfLBgyv<$CFLU*!gTLS|=T+`Wc^G=jxXag5zE^I2%rb2WRB!rM$^x;ouaO zk;^hJfHTj*3CKlRO%gc+gA86~@GOHLGPsXH2ZLKt+Q7~5O*pUxEgIMa*LVZ#;2LiL z7p=@6_&mHF4^+cH-T-P<$ZJ^U4WL%z22iWa0n}>lzs^<2iU_O2-zD&Xsb=%8~!lPgGW5C(!Yh zxgSvs*$d$->kB(- zx9C&V&cYLl2E(3*qJ4D6)tMGLW7ZKqgf<`&XzKN5uElRbZ%!tCZsi%c7a4WT51oKx z%5f&Tq?Xvu^^i#!4Z1?9Xr$+Z*Mz-oO;PjQV*xhQm5DlH&m}U4!i3n{JTZNs}Y1D`mqM`iZsW zqbo$&^I;Ss&zrn~LgtAs>-Ao-wl`(gXxRg)Z4v*mFtaH;q4B? zVF{d^DVJZ|ajZi9YkG4gqN#J&B38KzTfZ5fiSoVt>9jL1Unw=vNC?_q+)o+d=h)IR>PC?2+$Rn@m8ZX<#@Z+J{A-Y;f zi%exOj=?AyevOW@t6jtI%4Twp?%_9E9R^@+@tWI4bqo-|Y=qew6?N|4f4lz9E?8r&Sk8|%X1{O?9YKk;D@^7a-Q?U5yofk% z2;RgmHv~>*{CqbAY|&?VM8DHaXfgh^BJp$Q=BzK(dRfms=C3o4^R4fLNc&ly2gk-z z+4XfC{adll`cglY{Zfiw*4vrK`PNsduUff(`d{lf{d`i|?NVB?lEi8ckK#|F9UMGf zDB-a^&b-gJJxUi-vi?*-feFn6iEp9&xsJadqf(&xEE5Gl>o3Ovh3FB+=$}*Di)K4c zn!nDp=i8psj+~Yo(tKU5MSgwB4AOw3C3_`FsaS)62 zje`*E-7pBj-j=}!bM-F_ej``Ee(-DD<37MWE^4}Y@Bnfd_?TH;&w$ds!5Rju7%V|B zaGE>YcXRbk1E;vNji8KylPF^VvcHW3ujlF;1|a)eKk#C%zHZ>Bx%%3Hr@6CziaT4> zuV#RF8Cb!9PKE{^U_kkz5-5sjaapduW?)IKe%-)gmQl(widjZcuD*JpAXmS3z@MvM zGvLeBKhImUuO7%_896K?J6B&dK)fh%)!Wh}_6r*eMZqijtGEQz9(f zePzH}V^xN+Hpf^_X_k{+UdP)2Y}v!IX3mlBRjQzww1vxXvenJI!dTyv5$(!}b~%KL z4gnB$ShfhrDQ(Mu$w&Waf z1tvFL3o3pY$U!RaCM2tfZgw*~sE2UQHCA$zwb2%}7$wLE*Z)-fJ}?LS#Y^_S931ll zPBFvWIA=h(qLa#WFe9;msC*G|N%=_2`8&%S$mv zDTG+N%vio;7=DmMn3U^)`$DST+7j1WTp|7^ddt~}8{~A~Yv@L{F{QB5%Pn69FpXCA z-QsA(jbvciS$PmaEHJJt+$>vX?$mwgzJ>Tw>xHLc(;t-OA}U)E0A!nin2RXcvu6nA zo!jM`NW0vSWaCnq3ysXeU0!Z8@^}+7?%deo$leDkxe$J!$NW&bc;aTWn9zygQ9qQv zrL;GpZ*NZ4x3yN^Iz@Z8U?Z&9WN7MIk6y>R~&bsM`525*IW#-`y-f|AaN~| z;ilw8>#Q1K2;6FJw&CNrj=Zw$}rxd;BJGdCLj z(M|anRu`(qZ8mTD={xhrMQ_j}w7Muvh8lGRIB|Sc>$}xaUPD}Y*xLUwa5;*a&rVk3 zxS;%IUm$a{@ssE#?2d;oiYpA|*yGyT^^0l(=6x1Nd4>7tjWyg)$!^lw=}ksWjU%&*(X!EauLSk2K*R0p&ncGYY@Xyu0zY^-z+N>JeLyxJa{n z*R_kB{`e^S1NHuCLNm|RZ4JRzu~RVnMM)ZT%I!9<1DM&gy#AbGh(~>o2sw65nqFHxXGZRM-3&{Km?@^JYwZJ505&y zxh6BlC7$aB2b1(M%Q}2kQ_`icUE2`0b`I4*Vil|Kh;&n|2L6k*n_-pm=Bi zA|B5GCW!O_h-}S{-W>Th zVk0axvXcRuqr^k3bz}{XM{G1i`LL}KI_7|YOJ7G9?=`T zatoaLR;}+wD?KLWcHvTRa|iBwKqdutCVB2mlxCGLRGl5##N*!l&^=HGdmM{sg`9XLk!JdBi(KG26L&H_DdKir))mUmsSL|^EOP9`w* zPv8_Dr}rM}oFGYonne(&rv)AaU0Dwq(+7Y8jyEx8I-INV%B$}G6TAO2q6v1LYkJT; z;l}kF<9$eKO!gyuh_9hnmBJxqMN~QSgoGIt6!v}x#l~6yIVx?jDwsjYb zoMqGfCXPKlk%OeDdt@%_J(B_U zTb{@T3{dh8vm@3bC-c#FDK0+)QH;!Ni>;}USD7o4f|WgtZW+LAa7hqh!X@%Bl_ zTZ*nw3!qGj!E)z`j6tCFEsRZ9`kfAGgvb+pS$kkZLoOpv`iSDc*FfQUM(N+|eLri@ zFHzi?Y9Eyfvi81&u;(7X7R>Cqr$Ecv^KJZXT<1G;oFxS42RR2&-@zYej+2P8_WljR zX3j@~OmL*3pD5-vT6O@P7A@O{uo*xWKn|o+n(-3>SLgh@uk$hc=+2zz&TJFq#wP#X zmjh|hmv=Y$KEbpL7}n5`etM{Yuj7jmE)U7i)uGb;!xx%BDkEVRq!h{~eOdQ;k&Tik zDB8P53-3aA_D233;eqg9A~eF7eY*D_nSc(C{Ei6zH3MwgJ&|7_2>+Np|E*lTDRMsv zaX*8Aj2GwT^o!trj51bl@B6(wqk&7D)z1H3&ld}%YYQYc`1Z|m5g_{YLY5<)tA_qc z$56Pd9rHdP9=efOf%2peQE9Ku@Zd;)<{S{-T)opA5a#$|a{X>xDF+_aIS<`~jg$xX zw8>7+$!mAtt6cmW*YHNgDuXvDc_1yDvR>^y*9*G)D@hq-PtmUKyZqT&U=mbVJrM06 zUu&1@F~Owm&`!kxN_Qx{0^z>!6f7xjF2B3m6u{z!7~IGu`mWi*Y*iqt!;6bRdmwO} z1?+vFcT`!i_$*_`+XtfOy`VTAu)b)A$IJDL-CveX(wDTp#jLt|^zPkg?g|LjR(Xtx zdtb(3fG23*-snNaIbT!Oqi%A<{)C4dd$qn#tSo@v?)yf%g3;U!+?3JtMcxkhcSvYn zGuU7CCUe1sMS@hc!t_^etj_=ja93Su1USQFBN)e>~UOh7upyJj7Q15PwrXcrjyZ^dQN0u5_$ty(^|E` zZNv>B&dM6F%NzV2V}bARgLe2zEzE7i?l4ZUy6+9+Z0nxz3wYhbs~GQAS24;SV*I9E z)YQK-vIj4~-kqF1@6`I5NyX~XyL((1T#G2jC6>HDdDCX=!f6MZf^zpU^t*8j@KqjT zT?X#*3vE1!^=b8+y-S{hmUp%Bp1QsXtqx>XY|IW`ipv;-1;)l~Ty!B9R+uO~^^d4a zLW_Bu#YY`a7%1TLp5EI%q16%N`QvY;uZ?!7t-D-*jT^E@3DQD0ox&!5<0<2&pM}tY z=*H)byCc1|df{_Og!_tlvG0q$cYT=g-nUg1a1-M??)Pu{89V(3Pv|wYZ%fGYLTJMa zBnL-tKkDplVP(xLxRD~sb(sV=`|4^fJX`we`v`kD!*$ji+Qg9E=2R zH?BS7G4jt;tj-SBR@~$bZZYnD(^%uVx==80Y|b!N;+ntTyEEQVoCpA-bS!dw^*)@fR@L`7D^s<$ z_N{O%-R8orvHs^YXHgw!Y6)}Q*0?>w;*IMJuG7c^QKYU382@lQWPxSr#qTP|cXm!1Zyv-+dHsVmR>)|4;GycmaZvV^9mpe(yWRcl}S}Pb{f8y2Tx6+g=?L zdcglAK2cLCbimKV#smJR@WcDw9uRPVJjU+_F>R^Ohew^M;>d9Cnas+C*~<`{@!EvWJSL(k^F>u`8PV^#>yZ3 zY66*=I@9qJA#{~Z0^l8kD9!{zx_f_D{-l)GHPKNpPUZZ=|6-SByjJ*gt7)q06))X0 z8DEH@(A>~24{*sA4NnKY_+rIP#NR|0w97(I%3IGKNtN-=6X1(`HvkzbMTG+FybVZU z4&^Gxoy(9F|1NxfEh;Fe7s(3S>^EM(XA?pG!cWTobLT|oC${fR6A@-M=q~2b@pV*; zweLk&SG=^-XIAU1S#e`7^yJL0ekU6>1-KB)9w7(v;k%z=dMNp4YCJnpyS{VXFV@-B z5~y$f-@9_dbk?A%fotk$md>dOV_dGHg9*MF7mP)6-pWxP0?f#USS0xP6qA~DBL~Mc zZ{+y8IoV~=C&IaI2!oY=%pP8qntY~G%M&|5(=*NMb0G)Bt)yVu3$pgmUQrH3sEL^g zQ>@~wFCXDIC|nvFo;_Q^`)u#~D!u@|*wUPXT}&TR$<>wnGxtH%!`$v^vvLA6ozq)X z@zNiW4ekhg$76Wj!EVA(*&Y&4sU+7zMj zXZA+#xz%{d=$C3PS@=>^Rr3Q>^8>q@xHq`471iWzpT+t!yz0|kJ6M;YcIM@`sNHW+ zyEEnQ-SrQsU2W3Z;cjEpj>t40-J862_2*qXwyF5|TWRNCz3-;1-a1y#T80!+Srv`_ z%3wDCTowDQWjNklujVrJsqY*lza!3w{uI-}KCDK`u3z~EsvhHa#F5&9m{+XzWm2Kb z*YDb1Q`gcF$MGci?J>a@0sPjsRwp#3jDuH#Kf?WzDY7IA$%IIOaXDlQeh*Fp|B_j| zzIta%XG@^5K|X5gW(pUNCRvohdZ&JyvksV<4tAgpqiQ?a+5*d%oa|Z>=o-dlsarec zPO{dP&HyGLP0Oqm@Y+Bd9gV^SNX)5pzw3g3QG{2Xj$K=3;xw9n+ZFrutSmjM7Z!NMp$Z1=@nGt=OuWuOJD$ zVLakfOXqDJb?wdaR@d6zTnFDlO>Gd{$rpt}?ZEB)3WrqVUEP7Je;Rkx??U0DYt@cyB*%y79Uo>b zd(w{M$0!U0KU|$`=g94T5&mOJPWmvZkl+0EYUNR9zSujKtGy$wS=8K!8gL&f53^&o z#p=(5(3LG#D0i;7jPEND#Np9Z*_b$07GwDh|J7&H^9=sxcT6MN*je-Eb%JHSG~vla zTv>w^Pq4AGf@5d3w&EKCq{&=rKE4f@f;xOxclsEEzv{PjUbeomzDOcEeYj_dV&T;- z^&KGC`c9vfFjF?m8()srh`Bpu$e;8w*bMP9T*z+Boa- zhFK*GP%~#JsZ`^;0Fzn0@w&eN=3L#I^XK@asdHE0iT*X5SP~t*JmU+@dc5&!b?C-F*Q9{=fH!<+A#vZ4 zbu;ta>M@nWO5R89V5GRzxb~m5@-Jj`l=g1YD_-kN8%{Ie0S6f_$@Of&k>AKBQG zLCfi%wP=S&+6T=jN;3MCq8X~l%^`)m^R@7$FtrV1;9M5ohYq8_V(}4pF7Y3M)HgG7 z0+%&Y$<`B@Aw!51Z9aOAA~xoOEoK_Dc->lKljGxaw7%D@)F8fG(U632l~_HBi0G&T z2#ql=LT+Bnn6mp3N?VAD45OCFEPxCwdV4|ic0ZH{o3C}lrFUjvb1Zm%J=&EY?aEU+ zyPKk21<@{l^Yw0U+GN$TCuTu967496b|lNx%JB{3UMTft?ftw+R|SP@snxxm^VG{I0q;!{a`+No^&xzIN)+{ZN9NQPo$9x z3#;>{LId)(vHgJyOWr7XM#>k_^}S=|@Phi!kg!q71Ed8PI@wy^hq0wVzlc_~us-aE z?gh)jFBnf#g^w{*<{pCM5Q2}f6=NM zr(Djc%{j)(?D%}I^)CV3Vh7x&<{aS2F?xHRLY>$M9H12iJ#Zjd5b(05COSM-6_*ml zS@%7P<5P8p&qDzOp{ld}qxiz7x9XHhyJqs9yH7Tlp3M{)MXOE@|GKy8vxxd85D;*;d3v%9p3jMFA*6}GdRxRF$Vv@;O`hbgn()$7erR`Pnj}A zZHOvRTHmEai+c2_5RNLuVZ|Pg2!%K@+dWGK8-eM99wR%{r?{0+hT>B~lNk>qhF@9i z%q2!yJ3bk?q4z>(LYG@${06YMr30GDHbl#E@J;@Hn6m+v7c4;K{jwP0ZvZSqC;+Km znN9$(N}HK-0#KPgfH#$?zj-kVRP(hfD}q?*9n)6-sC|gwBWpGoox?xUs9rEH45FVI zeu;0VI1oO;pGP1s^M_mE262E3$pF=)c(1r8{2s3@|1JM~ns=KLcR_9r`_` zsznU-{2K9fWj0-Lm>wtZg!#t<+@ay)wD1^mDHnlD(fV-YVms7eoWiN1p}`VgnR< zXecrT^;?F;!;7^gd#kNwqeKcZ#y&*WG&^*ir@uOb+4RftHggFr7|trc#uLa4{X+4u z!~cZJ=IE6$f>FH$=J7I4*65`R9fRAa9ARK-%#$2f_;JdGoa0t-tkiktGzPu9Vz^h7 zru+KL8P!xP5i}a(1IQtiA+r>^MAmhQL09G(G9|#epZwy*gfteyq+rHYy~eo5)4Rs2 zl(M$!^z`BHt;w)f;yjoP_|`{pe264;R=~_uQOh$zYrTfdpAU5-Ivus21Rc;qfJ`N5 znbb(B$x501m8!Xw(ps}E+Tl%F1dMla9 zgWsCr$TY@>aV;DZzM2+v%Mq*f`5Y*p-t%q&rc|Ifn{B~wj`{2A0&{N7+Vcy<0{_|8 zG6HE8+Mcc2UbsAC>RNB%^6aT=bAVpqK=!_TZ|+?fwVm0>yTHs_I3M6m@eYCz;9Fmr zJrPWUps{dy-c)ddw|n&JyosCg)szlXlJ;!6dIWX)jXXnkr6$_TALg_j5`=4LBYSiUlJ{UFL+tciJDD9eVB&g_kiooeVk&q zLjT$G6gO$s9O3~&b9&B317mv5W(H;s!x}7ju>wV2$}0zF!TsPd_j#vP4&Q&mGflH( zY@8jj>4qZNW!!nsr>5?uVQ@-*Y8DpJk_D6DVyohqc4w*+gsh|Kj=e)*VkPXIY)wUI zIR2;6CoK3lEj$i>lBhpksP(Ou!!OBA_gkXVC>&(uk?J{{`?_M}eWGf#ROCzCd};*|CArp0l6J z+VdSG?>SqWwdZf;#h+-TJYY$iE;jK0<-|0dwTQecQ_pLSi;shqxa@0O+&l1+u z>J@Z}56JIcjCRaK#3mb6AS<8k{4=A*I)U-N^D)ZGI-2D~VGbrSAK1XR5XA<*^EzIL ztE{8btb`aqfxIZ@L;BUpIy%}e2wiXrh2@_})9eNqFIZl5fybZp+?}BX7D^d`g}qpX zP&Me`Vc)MP5wm!aagnMJHYwOmWP`N+4bFE_m(WcaHtuiovI0O1+Xfu?g^&eNMU&PYsTlwwp0CMCP06Fq&xY+t8PJ3s4GYj9oxd1%SH?jIm zJ@QwWGLP)UM0o^^KwkJGyoFzdXJ~F3rc!-9jq2-ZO8pr0}+N!`12EjYf(Sf19@1DZ(hIi9|3xsJD0v7V??Y{xvfn|7ap%)UhsX~yG>WQsd} zj_T~#8Ok_!d_jD?*VY`7lk-H)k?w450&fqvvA%6bXIpFIpF&K$3YbbJCg#i#6BElF zQVShoV(Vf9T+t*|yBzoFu!^?K0ir3Ylq}ai7rO-^0l2N5C(gXfXv_LkIa0`lgWW^R zv@6der)?u=MLDM}mM###%#Yre=VG=mA#VIR{2?oz+QHj}`Qff8Hl;CXcfYiAf zqT*!>iXrh;5~Y=mf%Sm~b-fTIIp=Zh#5sgK^B`hzZ{w!ECp^6=lc^}iI0XK_1# z*pGddGLwJ`BJ}Y`N2ZHv%4SDyP)+gENm+(u2FGMz)n$z1n`{_R40sYwkK85{#1{j1 zwENS+%=>9*040!c4mh~TLKX(DB&KK**HXI%4j(=m$D#FrN|QgIQqiOvLR~d~v<%hGveK6-?zFH}t}Q0CqxDSy{8OddoKUBlb1PTU_7P(dY)H(nhkH zLUP{NYL-o{jbwd})|e2~;7HaJoq@*oc4>sv3!A^Bg~584g$WGRJCb!l6YeZ(-DLt% z*F$dDbN3TwS%*@LsTeU0uyRG$!q|PXRdMN3T}bD{n#b#&eeo0#e>>a;PCBWe7Fa9$ z^&>$ow4iPzlw3#WNf@l^2F+~(0eviYGfKC&bk=Xfdc`WdL;q?_o}zIar2Wn11#e8YmKejK%L1dSgU$? zo174+8{-ovH8u6E4|J?7Sx|QiGfF^u$pU-k1Kjeuc0%EjX*aG)ilNc323hB}I|!m3 zoQa-J82gI>SIJ?s?Jj{*_ov2XRtEi*O)@K^NTK(g9Ea0EdUEM#9Qa~@*I3iDE5!_? zP^z8RXadOrjUb0jz(WbasPJD=vvuN{^n5VNj7d*rX z9qrb-M+Tf^11=jGFvkL1c8;Pa+wDF_j=5Hjns4NyFSK*aP6PxSXFYn}L!7ehE(R?) zV=sD$Q?)bJiLog?OMQseMbOSmWm5IQR0Wup6wp~-zMS^i<)JH`u@^r?f=(5C$wOT4 z9I+4G4ARE4JQ!$(vSLd;X5*E(i55zzGLbWm4}mZR+FF4eMf`7Xm}KAL^7?|VdK4X9Mfs*$-i`vIIh=Q z7#dHC8Xg_Gn7_tkhCLsS4vgygFe^Bb0 z;cOfM@-+RT@My|)4pO#2Ckq4chU|&l#t!%v-$W=tcPzeFnEmtrMd$m^MhKJ z@*$$Mv@YkLB8uHakm>w0$V}U$R|_2HEr>3QK=@vPL7!0-C1JiTO!^ z+YK`Xe)Q?kcc6w3tc7pE-;XgW>u-&!k3)H(8c%3d24pU@k{6?0Xa|9=-XM&6^ckWq zaV;`wRy`J~I>qd|v;KA|>eSt_bhB~yDPG@(FQGA^T2E+AMrgD5 zG5C4mmzCL}+MLjuywK)+`mB>rzEG_{w5A}mxu~}L?#JMa#jK4{bqe|wJ$Ikd0@=~v zDU-%L#_F@;j_{dK)#=dcKSYE0cUmIN!+z%tNJ=0j5=I;u+0BG>_DeX5rdV%w_$W@M z!{4Tw1mt*^P&pzk@&iG_Uz-@fk3Lh7K)djy>LC49X9)}p^T)(6hC_$C(g;o8_-<(R z>CjDQLscJJ7{k!$?vNYJhzM$fy!$YdLo4KA_OMa)hlexd_w2*OJbFwtR_%67(IQ_a z>DR4rC7kYeQ1= z(Px?T$x5B5`lD0~7+H$8cXv#n18MxVZ}rEBL#_U(1t5N@`uHb<1rgL}Kiy}z4TX9UI#d&(n$QPt%qI{w2>2H-+Eddi0E$D97Da`#C2 zL79|Y>nOVbqD??$L$CxtCi9U<1i_HZ(%Fb7>*%$UqR9%p2EwJcA!nivG-XlZmzPvhz?@Aa))ax8q}F zu+gk*#eT=yX!1Zb6&Q?AEHEC2CI_qE0Sguj3==~Nu!fe~S^^dr&qb5x*4oz9*kOV3 za5OnsJM0eZ+`tW_0CR1r!Ahh63%277(JGYZq;WfH;%#wD=N+y#fD=iPo!IeM+3}Dx zMH^^vV}XGeN&!~aS>MuPf$^v`S#E(g3vpdMO5tf~axkl@0>)#~5f1y{QM9dn4AbxUo&gA2qz+gc}1ok?Cnf*vPk9Pud z?Hmbsf)kh=>`1^_PGAh65rM&R%Tnb7T+*e=iH(U)U{0nZRpSCDaQ8WYCpm#Z;v?n^ z4VqY;HzxrmlWRWuWB?0)u~XJy*XoiBC&Owv^#L3^4_QvrdzbsvVm($?G3R=8p({mN zEX7GjiidtHd)L@Tm4rFpy-_7sVDBvdw>O-upNTL2aKrf^U+~CctzHv0%;sm2Zblx3 z?tbJcAWXczyS+4G-ibX{=aA-Ql$$${3%CQB=-7c+o-JeQ5otM{) zx$f!LtVG;dCZ`R|o7c;a1bQYmfY8Pc_;b<&;4S+e2N$B1ynN<&;1)Bwe_VXszFcsE zybZc9_!juWY~z>Elg%llqYU8>(_bybo8?;mI!D&y$cEBH3aMZzz-!QsLvK}_(}QEA z6kq8n^*jYH_250Jg`0=mQ4QfbQC)I_emE1d9XMFWDb`uARUS7V*250A9`28lKBinf zT@Fmt-O?6m3Yrp0Q?luXHMY=aFwpd;AkJp21Lr1A7r`w=RZ14LbZ)9^ZE09h-&{uq zN`&6zC|!bhf(mIgkS@0=$tB4$HB``qB0rfLs>_5TJDFIy;y~NR%JnTf8XE726-$=# z9H3U&WGl}BYE=MzmjZM{bzB9=UMA1g2DK_c4)YwKRs|BcOu>0WV?AVuX#6$Xwg|(Q zz-79?f)-c;m+1oQvcM9!OaX(LHw(RHd0m&1qLIsVF{5sfovUes$RJOJ+nN>?ZgZKCLq%WWV-~6@>SQ)NswvgcPG21M&SG-XNRT< z7aeNZ(SUQ=1DlmRQ=FEluk{I8 z*V#FY19Q2&y}fl;S3?PWfYfep+>R=hEP`i|JdmR#*oZTNpe+5Ic4E#p3 zwVkmmPT&x2N17x}A}0AC{Y3Yo|D7j^7{~P~J?`I;RO5#r=z4h=l8x&&kZ=g>rN`AqFXg;AJ*c_O@jL4AKBmwL|24N{N zeQ*VKCxftDOB;l#TH2r&!N9u=e##)sfFiO1f(#Hu>zfzLPag*+)jW~~`-#I*@06^g zy9uCfOCldQSyC-^r1CP67YQ<&4DVID-{KVw<|yIlfSANFI+m%cd5ALe(Z|c?^~Y#k zUyJn-^f7_<;<$r^H^@R1H4lY|{SugQ9vWw79nDG4I=Y`JPzu7pxN7}5IP@JX|7hoA zT=$s|JV(p&5S}6sIBVOxKgza4$krHShL zoPOe{_ugnAR>hyA`wFv;{u6jM8K>tLH!PeIKn`Olz$D*Dlae?8VH`|H+bLS$mEHf`2VJ8T59) zb+Y>d)aM`YZOQ3iHcXx_?tbgEeET}TowdH5m2Z3b?c<cNo| zuD`}DNsCcoKV}ABlTmu-?m_n1nG@ZpPS&1p0d)5#Qqd-mCuWJRn|s&jK(sGNJ3Zv~ zP&A=Gr^c>;d;Crcll>zrqYN-WVTdk_QnC-_(0_SwS>mK%-_{vc&0PlgyCUk6e?=Ic0FU3`;W_Gm9i-jawmVq$oY>0{HCRSI(f9s?| zQ_*(w(J$VErk-OqMokWT*rSGwT;z5=3YgR)SK51n=ZR`=%hhNJnAv zs@&@vUO$F=M#tdwGN<5p3uc+H8gphc^)qGSb!U?QnKBu#^*!Zi&c){8ptt9vd%Gs= zyTo`^_!hacZ}&$+*q1269=-p$?zcYI{Y>}1>vTYot}Q5%c9A0O(Z+Mf-x+NK?tjIk z&`ofIL|u?r8qoF?inb*U78Wb>SC0RBw4E$gYC3WtX-lcN6O9bD`RJE`8pN>|ao+cj z)_3&qG&N~su*#tyeuYa@X4D{^Sl`oek+&SfC2*6>%owGiSFqN1HbL01^KuNQ?6r=O zBnd(21?w@8N((+LWtS9_kyAHKjM(|z6r)wul5*YOY57w`u?PpN5jnihfL z*Bn|0&xowy+XlRaVIf%%fxn^)VK(k)lCS63*&31Ht0}4En9wXJ4dgmO>-&iVcDl)3 zq-uYWqy2EOMMK+yKnJQQ*5OcL@cw|UzfM}eIR=cmyR`6Eu{J*etpY#BYC-6EMxSDx)MZP*aU$i4mAH+spyO*Xq}&9oaJ|+JV-&-@YYs1hm=S>; z{haW6Vr8E+5<4#I(Pt=gY2#^gn$2nojWb>mLY8~^P%lsK?j*BKdK2a_k88TQCJiY` z+>%o3`;k=&Xldp-Xz6jnDq~*ESNZFl#XKr*a%)3|<8wXYhxyzRjTT zyBWN+*dM-~D;=Dx_`{E3b)Y-2G;s$OhK+Jo_>f@5In&GnhGR2Lw}mZG$85O_2Caqciq9XU!$1z&)R~=&)tHSTpg>mlWyjs7B<~j zaws{Bi<3ijUjQ{#2zFa`G_~CrXsKOZ`KORVeT=?4w-jo=R#dxUu~nNgsZB}A2Gs6q z)DBgnInS!P&gRwCH9M88i4v*Hv`a@$wg{(Yb*-IDg><&)R1DHbEY1|UIulZCHBT!T zxxlhOXUm<9t4$+4%COFzM6A-RB$Q<>(27ScrF2K*9RZ}MTx_9;C;F6a$x(et%*?NH z(VAPgHr5C1lVHG6u$BCrd!l)^P44Fc$2s>To^#)u@|+u&#F)jva;CDiuCsFsEl5jZ z7XR`Qbx_tgrGQs=wAuA9YinxS(1Io{UvEa0l&)!N!XdTYLhXP-g`fD8rF65+ggdG1 zlMvh4Ro8Cz;!bUr4Pe%Haa((pNg)=dKqav6H}f&U%HV2XJF;=WXa}~^F4+yYDA1;e z6eJ4EJ$Ixn@@Hl1v>bG?)wUSg@U>i!MY^{UrXAdkLwT4&y2gavr|7N!kG*$+udAx_ z#aEiprfu4!O(>z%l0bn%TbiVAi`ulIJUe!1p%59vY0gP{XkN`ZX$s;H1@BOT4qSB} z4mfmVX27fCIKEIEd6ZE{xe6*ut<~zJEi*XtftlVJb^QNxzu&d@+IzkBIj7Ll>ScdE zXP!~WcVt^+R|76bvQ-C0BJ+YuT55Ex={}qO>KIgp)=p9YpBQk?ZX+)1WRT!>yoc^mi&o zm&?RJlm|oJJ#-bEV#o8#q1|~7q@GEGK=MDw^*QQBFZuN9pXBS{A9_BDoD(keQUf2_ zS%k>-gMkbZWFVOXD5w(b@VD6eUG=o!xiZ)vNq%tIOYDZNbQ-n*paPt2{!m)3L0O-_ z5vX+`2(wg0?0z0Nk$h?4X#Rn)p?|vizw%8;O4W$uU{fWa1g@F?(!4ELGi}!RHCP6o z|A*>cnkt>+<;h6_tNs$+&3vq_{vWqY1;d^nq|KbhpIGANG2-D|%h?(<%d#lDC0@fINVpdt@*e?kEe#G7PxTA4l>_KFF7(*7fiDUP2 z!K-_?9x&vO31fF+>8mm73FYFI%&Vt`=!m`bS{#RzJEJy+i)T%t*VN?5#rX-@Y#1Ws zGPifjE)1)TAp5?0OA-%sru&Dso|wEb)OHp}1;gBE24iz7HF zwYCc_=*F^KfJ>EdZx6yCP*@?Bl~i5%c11wrp2n^-H#84P5aGi(O7cp!tj2Mmu5txqE@k%@5zPntc z5S<3KaFD`agcO>1)TM8hJ$3*eA#+KFgfz&w_FvswBmy6`JcXhkWC2nJMUD z@)GckiR3Smd6bjgge+r(h3mPynmd}d1LjeOUy^UAM=6^!D%U62Q-dSm@K8xJ2uX&S zi@i6fVt78fVFnn;f_y!&YvkwEA^RbeaQWHWzdd>Pw?}7{Usq9nU1j-oRb@Z8T^w$e4&Yw`TTiu$4`_bIHc@H4mwS|)W8vgH9D{61PP2Mt?(pknHQwyBi|pzy_~;XuWb18qzAcO^be2cZ1; z5x#$N@T0lOw@&&J?LsfD(T?t%B<~yBI#?s; zQv@?-Mz}>%6jOmQf>o>36b~FMO@Q*J+EoEi>I23f`EMx3KVJcqdH|F;N!d#++%#dr6$eYfI8-cSQ6_295;Va=!+{6UOPcuF++dv#^w4(}fu;hG{G*Qef?Wihg zVv~h<@O7*HyZXKP0F=l~_ITBGIw)Zw9y37+kG>wDBpxtgWR|Ei@d>>8drpLnr8IbA zS`}7Fbix+t;H1+JPD-lkhbA)GA=0BH+%*B1n3yP`ZYi+DG%qDw$OR>(RdXPTiKi0o z_68t16#z-621wrL0+Q%7MPu8<(peCYuxboQ=4pUL8xRHI2}zn@g<;an#Axn(!ge2yLUO;ndce)KL3jX-%qpS`*6bGO?SZHMuc<;8Nkpn_@T; zXidtmt069_BQE(T6PNt8cKKJQIN4H2ak78ml>J!AbN|BG`+H_ju`vmiBac$|RrVB> zKJUNe^Y6dp@7bW$zZ(9B7^PS`l(i;GxjaBAH!75(pw#sWr6lT5p2nSu=}`7BoVvef z>XiMr&ASMnhW!hd?C)8^zgOb3W`7S3^~_uI<9$FXKpIkqa=CF->Q>m|mzr?=B7Cki zO5??7N8{2aUb!4^>PzxXefRx!kB6&6QmJxd0i_Bnt#*_uJo*(jiRR4`E8I><2ME{fg(#2{6XQ1BvZ+fJ|uq@u@~UH+SJnsTCanmEeL8;T+YEGwH&2PKW>(-)1FOS2EY2J$7a)Q&0Svu-#M9H=orc)xXa2&_^gVQTJ zRDO+g8Y(hz-_005mOITrG(=uTAKFGTwoeX`HDnpC@+rKhiT3W53~|r*0~=XTq!i^- znhl6HqCJl3lVu~zS`D9!wh-OPH-Yb1X*Pg=?#A|W?y&tY;6t>k>f)!dGJeA8*?n?^fd z743Xe$6kg#@X+Nba_DLl;R@!{52aD$P!Ec58S|-!P;E*OhRTSjL!aPI2BhB4UjwiL z9@<80;Y~0F9=Z{Fp+m4QmLJ*-dmyvCRvwZen$NN@q3j`A1`kzWH}-4pp5g9qX-kAv zaZ=!o0;^<~bbjRq@2A>%I_o9UZos0*u*aW6U*vb=?h8U6(1Wt~*fi+=0!o%vF3B zUrj&!XCO$Z>n@~OjURd7UDfzWOI>(gSsa^y;R0pe7h{;rgJSP9TFYT!bbR0xJZ>ro zk7cCq1~{HIFi0W-$@J9^9nYY|gAesjD#n-oWITTWYpWdyB0IS3V_rt!F)D)4oxWua zgWokwf7PMsPnEG?syZxnll`;GPCrh76|03ywjI2qvKgbN^L6d{I(ClWr8~0CBq3rE zxI4jTEjA`f(rX$MQP9!XoiKA^X>ix0baRY}T`q*8>r+Wp{ZQAVuXFF30CY{*C-od| z-6WXnQMS32U65N^H3#CFm^`7Weu!C9;tTF~`-bqglsotP@03>Y;>h@<@^9^w8@c};$;5K^8C4t+huK{kG#l@OhaV5ZQFkxbB+ZAKm zt}cmfx4GE1KN=w~vzx6E5;>tuROaY0gF6;Nwz5P)J!Thg>uf}Z9MC6AkC{~s4_n6e z_>paYSi<~bc}|>D0@=!EG22H@`3ABz{pF5>=J)OKTTa&e(x0ja{&N3`DBzlW&Gv6i z-uM-eA7P=|h5*$@;Sn)348tQ#BXmiqc3;JP`w(}xui}IF z3P3DTEls!lgs7JGS$+c4t59u&57qLZ8UOtnQSGHgQSH({A4fFBi+ue_XmWT3)Z|LII;#C~XYNC2i^Zck0O!SY6y~u5TtXk}aZ1cSk zFcwPyahtl$-&AN@eA?S?1w)2SXBbtdp#$&sq0enRKi=@>Aodc zcZxpjPXEIqA?JO!xNvM+^gJ&oG&xo^S`WKZJpm!Bu@b^&m}XyD5awtWgg5=aU_rR;wObJ4OqiyvAnLdvwmH&PM>7dx z)<)}GL^Z@D=Fw!NmOpaGyj4WRFupv|yip5Z^bDa?G=v0G+gL-0Rpk)c$dgVqZ?~1Y z`$3ixd;Yy#4!EtiufLemu#=9!-9G{3bi*N{;Y9q+t&VmdLzkk zG9M!+AXj>Ow;C5@dr1x1-Zl7UdsQ74EVaFoX0pODZcJXT+WP|TFXslX5x?J*aYeS5 zQ;+R^Ic%@0!-8wL3%5e=S58n>@EE@HdVI2Hit+v3C1)f*i_Vlc>S{kL!q*1D#MyWGs zl$u4O)af)z)zK(bdkEFeJoF0|`8A3h7ASJK4n+>nL6O7rP~LV|3_hs%r%N@;PM@C@AI_r8Y{j6I(?hDVr0L*HpMKUUD%S59l>1V#>)jor&~4cze& z#x`?zHFtBaLogveb@Z!@QpNdXB`P0hk&;R~}@^71Ec+K)zNJ??XlfNF_cgKI15C4389+Gq7#!RZpq-k*3 zprMFeE%xfEzzT)~*l~a~lntHEjF%0}(DWjo4Ox$nh$2pWEpHgP_Fp1bI{PdO1{(tp znGF%IWWM>{kP=B*1ruHS^D7Iv^;dtTZff;cDwZsGHVOk|Vl=qg4~{`);&roU0X&xF zW-s%pS=l5=S*uAys5} z0Za}u4=-?~dV$i(5GUs21d?$W0h`~t4qerR&qCE*yT1nITqSi#3(%kR$ixttPfZtw z$V1o29@FiQwU4svBKzZ;%m=C)J^fD5<~<|W6*Oa>ZeC`Nd6`+Gr!NJ&+S7zx!ONUs zUgj+GGWDaUkMS}GeU~8?3^ydQOiKK+`}@29PdOrik&JKJ_VKCJpPyd-%k``NZSX%# z-&Oq$%{JRKI|}!d7}c`Sj?{^nic89PPpq_dA~afgyn^ByEmJkJg3%OckFL|oy3#Cd zvn5n?bZ(P@UZ`Z6Et1hqh~tEhFQr14};=jkg4~h`1+QhAa}rqLCkKRK$IkyI#D!qZ|?k z*{{gb7R8lClPQ9!-5M+?0{TpeP>N1GKEfTgs2#1+Y7rdN_5?7TlN1f>@u4U- zf{$-2BpS+@>#J1c7#6;l4d=DVFy(~6ciisn#ueCJ&ULo;S$x=DRR=#y_NhF`!mnaW zhq5z_O_;aG&iw?R{4CLMomLSaiGp>VX~ zPZv~tG(TBNIZ7P-my;$A)|>JQ#KEWW;`cm(og?=AP1q&)DuX!q8pP(4@P;g@ahCbq zkQ$@4J)Gy(MJr2cJUtSvBu}(NEBU@gP8YR`6iWH3r@!xnxC}f28ed$%GIQ6_yRDTC z(j}}O7pGFfDy61h#4@D;|2-3AEYok+U)3i`P{>*&7HC+;U)PngN~-0ES!O7k|6YC+ z4>nlJtL=3=g@RTI@2A)Iekf^`(B@u$n-fH>9wicywcDarPb5B&k=v37t0szCz3RGz zUud{r@K7OO&@BpvfYGqa;uJ{U2nX}!KQ=9?(OXUsFwD|XU&E9;MHeu-UEhn|sOt~1 zLoA7u_l+gebG=j6ls|}O!KA(##CVZ>DU%eBk8p=A#>G9s0c%fu%z=8+Gg6-8I?DAto*Z^G5s5=5bO21WKUdr2GG1yWudNwh%j2S~N1lShlAfr+p zGAezmc^n~Cm(hBKpeq_?n3J-BS(Nab=@jw*mldNGzr@d)(K-0~WyR{}Zaeq(iq(4u z-?aL<+ZWx2U&9w%w(7qIpJSp0l;e^vbM$0KjMU<>ok7xWiPd>b%W-*}g0K+GMcqfZ zF$gOee{=Gyg23PYyq+b!zjep@{)Q&t?VYvyIerK4?)l^P?kr?p8$oJG<{e1w;OP^U z{^?cYX*>H<#)WPPc-pC1GM;v7mX4>Lsy@7!fTx|hCE;neRw;PespZF}33%GBeY4vs z#M2&3?9}w%7l_*D;FwX^)rW~Q5is&$VpdJW#5b$!22>#d6Tgun!CWjvUr7Ysg+)^& zL~pqyOdRz!FmaQyh7J|!ava4$WSKaKER&HzWFF*vb2LB>lJZ-~nXM~;oaGG*A!imS zjGQ&sjF9v2s}i4+iJY-4c9g@*kDPDTS{t;N)8v#u&TPBUy4Q}JW!Cdz*${x7XAn8p z5II*9IZr2Yo<`(cMdUn{$azX}1m@w?1>2yJ?7H&k*O9Ka)%atFD%Cz35G9#Fo)^9)>(|nPHVf&ugf7`ryNEs%7 z#F-J0C~F=+VGJ35GNYE28DS|P>!W}gaZ0iBaby#Fm{OULpq3@X-XE)nP{2IMMjyq( z1xdrWR8XjI4?KS8tpj&6AoKbl6MH@dPqX>JmO)wsCP}>H39RQ4i*V@lR&Q-;+0U@MZKj}b71dsV|ko}yZP}aac?Ov zIPdlifo~}q%EB5aOU?0Z&Du9Du^ko(5y zw^PbP5BVQD!E+}cJ=e=@orU(;bopFsNWQI;L+X9`V$_DB>psY;Nec8gJa=B3un_fu z<+&4$xdb7?_1uX@zphxn()HZo9p#XCnf>ZykqGFrDFLjZT2}12JMi6+B_IM&2hD9n z?seUHE<9p>oooqUNHsic7TZHfKu!&O$GU&V?L^jKc~SsM1TWx2-xyUFKTG!Ik@J)l zj&U2-e0g@E?_~es8gaXaj4QIeCo@dR(EZDIZ!}L3<}iGT+b(?5mxtelbpL#Jk{%t4 zFVD*`5m4%=rC-cUN+L5TyVNjzrkde1(-}TfN4J|=I^fKtE6xmh@YFDTrkde1(+@-V znRa*t=77VuaYuigAi9L18G%<%1ATew>C02|I)s=!i~D**OrF7s*VC8h57>jj#*mWG z^Tr8{sKR=ob->~^0Q~g;_j6bUK%Gl4Nqqj&{OwOp-u-0PXzhD`Ha-ry;K%J4?s)3|$0A9S?)X(%{@X9Ts1*@=HS^M|uuz;)HhwGyinmG^pwEU+ zj;|9M7xH-B4b_iVyz`Wb3vnHRXs+>RgL_tBNOyJ%c32b<7yiE41S;7;t+c;x9^D&BDy_LA52@(;TZU6H5b%Ts83j-8DoLCQ1dbH)hs5?`RXjq=__I*(F&LQ^gF85gw81y z7y~mjM-?s&{(3m7EQ`fXaZgW?#lHb6LsT3stL>3#N?ZY4+|yUmD&PfI0QYAF@N4tM zeIr24rsqnOF`$NXkaCnZx+6)ci6`BPv0!QY$;)wTV(n*njcC127T|w&JGT+J*D#;P z@xoK`OJQwl!)PleRvp2|w-xf^mQUoXROFbB{nRt)Rrnf-y}4Ba%Tg5KcOmR2!u2|9 z=<`ucpO5ME`IttZk1Dz?Po>Yt6e6F=bo{8~qMehxi*`OlM`vKZ(-?E@&#ZeKe4LS@ zMQvqMp@6KY{z{o#X8nA17!O{x31_PAo&gY4`Q}=wiOgg9#&<|1Yok_hnk3_QJL@<|M{ z4$T0zrEH8g_tv=_f=WZvAJeJiVGj`MtmHOMEgx^dc>SaKMw)S_n#mZ*Oo~;ANiA3c zW^MvYsMc75Vh=^g-Q_lJH)`_ow{N{U z(`l_zE z&*N|MJXIGzjja&RYcNWd{znl^`a1fWh^a3g4lnl$eDj6zJBjBt;GB5i_r)003N>TU zUsR7#S24DWJnuI0ybenB#>1vzIq zd1$ys^#F?q?k?eODR&F8iyW(-kgY-f1r`!_hk6?x#AdJm8?MlOBDlsJytd+8!!-Rg zbMf1-O&aqUbanJ(9;MZF84p>AX-rAF?~0Dhj-gafZvEgOoH#(_$wo@MZR`Ld>)tb2 zOzh}b$HZ5>4!MhIlu2rWhXs<;n66Aom3^F$qKhfeCDk?=Vh!q*_SPI}i6*GhZmF>< zyd_$n{8HA*c6~CWticjlYKd|bWDnC+v8>;dMf--L3Em=+E@EB@+;Cb)N4g_5IGDPn zGnIo%{k}UL<~XRBV*{y($s7lx>#yNSlR2`YWRCapoU_b}n(HQyJjk+Q&p82G3Cl!g z40%%g;&$~duZ%wt+Zhbb*n6^?27JhN=Ho-Qqw3JobN6L(CJ17aDUwxEIGaQ3#(5QT zv5`SuLH!**7k}p9TvfQ}u3VwxrCHk1os;BE2*P-ay-Tz!Pv1y6@Icvt)=IR$^1y@x zYb)(`NdN^=?V&o^u=}*?)pz`S9zk4_yutyr0-p+qiVF{vA6Qq3KXdTmQ&*sgbzu{O z_4d|iN7ZV-3vsLpCFd9=`7r9JDv5RWMxT1e9Z%15&|S@=AnrtWZ_^q&13{o@=N#3} z$^&z_JW9QM-~%^Q9ys$r#XQ`m@<4m#f!TLF9i%bR!RpM7+j!lZ%Wkf@xlFzyWQV#z zMqoZP4R)Nd2^>30ygkT!TjH(bAJZw5vY!aJQkn+UR7}!^BWRHZR(ANoN+~t{P{q`u z`tKP5l^r``pi;^$W0)dqdSHsl^ZmC^04XL?@>flQD5hq>U)KdFrMxRIJSpXNZ-A3* zNus>C=R|^&_d4KYhXN;5pjzN$M+8oqc+vzXtQhNjZ4ZlZW}DFDSzaa5`UXYfM6g0U z0a)_H?IW_321#~=2g0vPe6z8HA`SQuij3gn+X_Ju`Aoh_MUELzBw?M4N5g9ztJb%c zTHl#=q#xkKbfSwe(hmyXsa}PzR18Bjo=gN&Nh~vosAeLi=THKsX@9JqyQ{f-)tN2i zXbB!N(E5&+mA6*7AOy=dRN+&DPX#^>vwsRqj=bIjLRj^M7=&nlhtI{I8l0;%L5Ox# z2O+qH2ZZb^+t*q_5VCK=zO@y{214oxLK@^1_MsK{5QNOxSH5pu1^(3F!>6u56BSMh zL5Ox#L5qbrR*8}|CJ51vs*(zX1ZY85iPt>JS>b{ZW>TzE?X1`*K}d~!;C(k#>^pN` z1((~X*w)Qy<#xxTwO5P(V%*K};($^-zIlL^`hW%s4d zly+a0tbkgJ*F)id^0gCJ9zX4b&&r!B!0}UsI6f=J9N)I`%Kk3M?=ihd4cM{V;ItyQ zk?=cGL8QV1;nyj}@55)%TZo~2BCNdN_n}?^{Jt`Y-%p~Np_rBTIPiPd%KQ1(Zsq-a zVCDV%Yqs+4#bO_7E35gE>=9~!ATDz$PF+$iz@+T>=}rcuod^b1ns(n5$Cx-rHb~=8 zoqlP#go=I^WwJK!9V1z}von^JOSoYyD$9xQYk1PF7_0E@ z6h6U(Hksx@UL@AvlLq1cY4T{adtyA);EV9rz2T{diFQV1>p8@Zz^d>}p_qyD}zdR(kZVCnD6*UH@gdkqyn0$1ztIR~E#e5Sw1 z3+O6*bZIO-cW9TN7FMnJ@ji%^!wtsYTPF-&fCIejba@`qGTj$mnr$4-O}OX+ zo3%SkhiF;3|HA#*DSVRs7wx}!iqpKxpn0`Yk^iS!WhnBOQifh5FMvSa>G)8FzGVM` z{oAMD&&BvKj+f6pFKlEWLtkzjWh1{tUjGuqe5d1cu~C|j6d#RCD_J^-^EG8@#ISi} zX{pdx?VYm!5~B@(p`uUWheJ2(&Gg2R|h?0zt@SF`1g8nxl!m}(G z>Ct5g{8tcx(IDJLeTM_11fHd%fV61-YHdI9h0Q%kN!ytCSr9zDT% zdQ>`3ueP11&r;Q4@}EYQJX%J6ykLT3sGhFe5YN@BRByTtmEh$F-di=gWOwuK+II#{ zk-8qZCNf4>_;}Y0(-r^UN?%aM99OBqk-Z=KHcWV%x)CZ?w}w`U!Q zZbUX_d66Ym_HZQn(3woIIjOeETFA;wyKrJfhrN)Om3q_PMBnUE9m!%3vDn9}v%hyB zHJI73e&f!KJE7Mo(b?=2bisY09DEam3b_|_R5pLJiGiqYQM4jWiD?OEI}{XWKg|q zYDl8Eb{kSFR;|9S0?8KVN->CjOd-9}A$*lGhh3^Q0f{xMf;2?dI&es5$@D#M-Mwlz z?m_49|K9!9-PcvfsNBFPreD0M=XP6sQ~ei&A-Pcm=WmMO^0msN=B|+4y1^`3@;^m- z>A9^)uU?r_&%@z?U*MZU6~94ryjug07WdqS3-&R3Zo^t#!EmS7>bY&_2TJ!3ZS6UU z5u~R0La&^lMH;I~`!%|y)O4AY%VzxdjC8u`bga`Y<(9EhSJfnwF=Z|PEj>(;Vw1_+ z{8fE&8bv493CVrCCO55dIHLcK4lAWHx0Ktxq0K!teV)>a9oCbCnd~qfu|vs&Om@hM zu?5ujc?!py$qS$5En-{c5r?|{!AVXeY>U77s}w%R1LBBI_>t;V<+Z1 z<-H7lDfL(lbYZSgc@}ZmN`8W~@k1$9=zQ(M)zS-md`CqPi#I-4G2Zeb&s(nFI_io% zoEB&of}6GUaDtn4;MxTLYUx@1YP^|hOOs;b+uQoslk8q?3U{<+$_8oZqRWpiN~q`u z7p|7mxnqPay1HU)QNj&lXrU?+T9}~3`-ln1!UQGWnn}RIRRB9r>EenKUX2%4lyI{* zP{pZ$DqIC{R{>PfRR~qEVvH(m1#mFf3V{k)0%S=kfCESB7$8J8;jWl=@z<#YD%3OR zEqpBs;NKWfk)!}N5CwgK>8Pt%?>XUtfZM*SS~~GY=VRt8b-)IqFs}5j#pZSDjq5~+ z0;!Uz3&6#U+7Y7QQTQ)2TFgQe7-4&_jk~mL`bKj88aO0NKv4xxWaz5ZQ#H^XIRX?$ zTW*b?=?bir+G_Ic$>#A_n{*!f%9}s%7t}(wupxoeXE*JB?NE5@h|@ zx>{PQkBc>(Xu>6p{8!?h50=mj4Nx=}y@3N(vuvq zSYKq(Y%b;gdVEf%+^?Pi&4@OJT}wWI?_-tw{We-Cf2UG_pF&YS3}k|MAI4N8!s#?> z1uCc&D5q8+T;o@UVvo@=OXdQ(b5>c|n2dFL?HR6AjP0|0YL8iyhvjDLo3j$soID2| zQ(7W%3Rf;X+6= zp{cI&+|4F5s7GfMQs=S@bDS*CSsf)XA}(@eL=)!%>j6sfwBzC^3P zFZErw`+bX!&5g2<@L=1I%2li8dxNZO-i zj#*e(s1YBA$vYRcWQF$^ZGy(~bl~s1xWiU;(C@2Y^KWs_yNWKuX+edPr|yXtgH4nZ zTyspcK&eOF6E7axM516ic|>c6j_{mqjtS;OK`z6QfSSr2BQJyhk(h8Z{&==iipzx0 zpf~fim}7n`!~{EkNl$-Y_sJvICS>QFXL~e~*5j8Dir2H|eJCQB?7??Go5qAPf~kh` zRdlFXC?vQ^MeIk^Naj6Luq0T=)$2BFTqCo@Qe-ftA>XavkQw?V;#aA``v)$SNqaY} zUl$&NEO1IJPSI09X6Pv-Gq7STGuUZMbuX7yuA$3bHC^_m(`9cOUG}P&|8y!f^u=M2(lLxU$-*v80fVxr!^Rio=A+yNch)h|)TBbzPcdCGIITO6#}^8#fo$X1%%v zGLja@aJ5|<73Y%V!?a{?j5t>V&zh15D@x8az;m{?i-X8yTu-o=*sE(wroi8(V$@C5 zB-g^IO3;+F$m__Rp;B2;d&^|0CSio=?q~n&g*#plPri6|5HG5G*hDK{=%J?5O`VGt zYN}VQmSl3TNL&|VW866X7uhX0TFUvGmU8*p@NI9(fMXx${|4W|5{@au0i&zXGfoZa z=pGJ_{sP~}DY`1QluI9YStchS*0(h> zrOHEgJ(u&4gP07a60l4SNw9G&klbD-y%D4 z#V@<2$?IxLdMggIV>DIqTWMSb%>%_qP&>Y{xW$P~dokjeax#j!HITTO%q`a2t>HTZujz>EtbiVW^%WKEEgrlVgdeFVi|v9ixOkWtKvYUb<4=}&W^mI0Uz>>`S_4; zsJi%RY=!v78lzXhvCu6@x3iYjOBDybkkk#n+JnGo!5P zL!an+Vbl)JBg#r0mAR-SW*QEota$r&?RgPp#dV<@_FuT~i6E)eoc$N!=WSuU7y`%| zm|JS$y!gSYaQPq#%y5jZm%hpuYZnh3qxWA30W!FD-TsS$-!HOM6mK=#<0Q=)0VnAN z+T~Qd6|!K-^j9@Ve&n{?9o$vSwk#G>4UsaA@@3A+sou?>n8$ml;)vfDnw~7 zlMT{j)|?-4lu*$RIZRgWy`u*NP-=CFAMBi(sGK$lNVVmJ{QTaO+0C`cvg%xueK#E7)BZ@C^$ci6v>ks-8u;?5=C9#qjD9>&Ll9+!Tc};=3iJ?NPI9Y8RZuEi z!6mDz9}jXyKc0{?dID-#kv(CGtKcS8U8767b~ksaG*<=nqo<2n1<&XYIK(xcPXxbt z0?L5mt3A4GLpDg`H`_|(H%`S;`HfStWPan+ES=vtRZHPFP9-nDDgI8ky6+UE<-WWl z2yH7sCASr#lB^h0Nt1$ZRTurboCygs?+h)<>ZC83@Ege=J&1^3RIe9iw0OfF12R~)fYJPJoB!?fAC60Zk2tD<;>YeLXAdnT~tk_%dYnLyvNIKX)JE?jG(oLtH;Z{~NdivA&z2^z+rzP6?>iNNh$!dM|60n3R_4+C%K?zr@ zY(JulBwV$=UB?R~{64U6gc%s#MV`Rl;}~Y(>ZZ3V^h9CM5?r@OOq-P2V%n@2Lo!=8 zEeC|jv&peyxs?U@U+Jbt_y=3W`?d%F?fuE-*#-{`pFwXUUn6-rx8oD-dkV^}y7hc& zg7v(LYZoM0&sPR7i2KM(C`_-s`unP zk3w0zdo}Wv%4`*dWZL*z@MN>)Te^vz2>JHa>QjfLb6!(4ZF>D2$>c0lHaZpkEXm|7 z-iir4$_v3X6!h9P+i!_-k@8@8p)bz73 zlM(svnZU!$Y)}5GNs^W6((144axs%p`)j?y#!gK(<|g9E7hq%gLTro`V>V_d;t1zV zK|U55)s!A^BqTQxPz=JnVLz*?DyGkuE;-<4!AP z99*asohAh`btR+$tn3<{{hoi~Wf$yq{gbCZdOYofsvWj|Z)bltee$@GDKb!P#`b8u zXs4eS6|d*#L?&_f-7kR;nas~uF^LPg`aSy*T^{7>_v|`e4phRejBpI7N={K@o#se; zlEN`g@cQOE3-G0#h4>OH#(c@v`pIEZh%2!GNkO94Z>J&@=J%<@mDDrnEj*E0KVFZ;Mf@Vf-WmAuez2~ccP~rvJzPsi6Yj3vKUu)C~23)B6D}js3R}x%Q zXhejJq*tt#>?^p#-Q{V)goy$B;}0K^>NC zkj9aQ{2Zx-ihh=4au)9$6L^v-R(WeCF(ubu(s@jmE168!dp|E*D&b}ty+`20smqrP zC(Dx(CU_zPCtNMykYZC(v159a3>9KitQfN?TMHNrwnBVLmH>fJTEN8hLWg3~#$V)9 zY%4u98t|cq#t1&XO-W|Hb4|X3B^=YOQ|cM?Y9~kw2qsi4mK~uHlS=WIkWm&_(`lfM zyGyt`#wEmmGo>dZS$n*g=mcL_K#7ZqqUR}Z!AhAK>`V3B*vrJ-7pHQ)GyZ5LJcQaV zyXNiJZk(`w!-VVKUcP?AT6``oU%P2j`SovKi_fJMZLOPIE7rZe?b3?%SGR6Htz+}0 z*KhvdpG*>uU}8)udpP)2KBesA!LNx^%Kkd|RXHg*TOlgKUqVctB+q8g64R!ZJ^hhN zF=4!He8PD74Ih~xs;Db6Lx><=ehF7hW@} zk6B`QzMnCPlxmASCL-6jT@4QkO(8h9tePIEtbsmn}^V z%kz*;%(oMWYG5hGdn1Xl-y5h6YA=%%Vfm(8dbjpRX}mr)JLE_GgSS{z{?1xvhYp{o zd3p4R8~Y{PGbG_Hbpq`V%SJ1D;~4@b(7t_3-E43b3As8`Hs?!E6iYRp)68YqTRX#r zJT)peXz2-#Hpt-+?8T7yHzB^e=p8r)IB+*G0I1%BSK;qh#P}3>YlaRrc2pB*WCW@v6-vM+t&ouyH4v=YUd)PGCe zg;B|t*l%l7J_X(<%g4NBOWmrt?6UZ(xm*a}E96vjQkW`^3k8S%9i~kOHYXUjoYy2(V zEyO3z-+v~4_2VI9g+B6c^^mnbCZjFbOdcn09F&|1xOGFemE!&X; zm|kXdL&I!xKGlH%Zdpz-VPG(j1fHJ*<)G@Pm~L+#8tBQyD(EeB8n3lVxqZ1HzGC$5 zJ0iqkcIB2jl#brDM^-cD-!m867B})ti=Ho^Z!DhXmq_AgJ9?fYzc^#bq#Eux@>1$f?CRQJ>I?B#-LnN@A4dQ{;6gDz74u(${LbO#JIb_wEq9bbEtH002!y+T zup={&?dk8HTVsui$XgTy%A)$i7%);3Joh|coaVUm*7ZPmP@@Sm(7JijmTj?aJh{y_x1Ecq@IGVaYUmH(wji^6U-0OS<~|k(@Rf zd>glC+go=&GQ;5W&5{p=h(Mz?JIn!Up@X27k9!$91@Nw5`#T|i|D8g>l~P7J&R>SZ z0sB9MUmp=?Z4}=UFGF_8N&M4>PHy?sY!m56D`7ma$nM=Jd&2b>5JN;y+_8zhVD*IJ z>}%J?-9vmGaCU1Jfop@hhm^sF>{1I8o{R2jzBlx!ftnNFw&enk_pS2+QUowJ%>bA+ z?}K-u-$$ai0Oe_Y+V3(0pk$r$_^Eu1M1QzoW~j5s-O@Xd$_|2Ir%O>>GzdZ3-~T`` z9@Yx+zTj7=^w^AlpPfR)F9|>kW=yQxeYB-M&VTM#)$$XO=k|o0nk_Zr%p+ zmCp8cw{9RT!@Mk>6!Mvibp%Y@)XJBxy}|A78-%nBBp=ak)}rxP>#9`z{%SAMkrvBJ zB~i>#txV({7u!p>1*|%*&>3I+-4_L~^i{2g;reLp}0mYc7}V?(2Y7r$`BCcZ!sN#->OKXl{y> zfCi^X321VPlz>L3NC{|m&LRh7_vbSm8Ko@l2sF`iYvc^MBI1z2451koK^Rh8#o|%8_p9BD#AWK-{ut2 ziWQHX&u3o};l@j$!vcMmZ~#o!qZ`QP(%J589=d@nbORCQ2g8V&Rx?P= zCN>Fi=0AyT@8#L?N-{wh^BUhfT~uITH?F7?Q_!kFK52wRVxhWdIrz47f!|x=-h?$o zv$Uw;;A-~*Q^ESyq3!M4zd1KqcVi;oEp?h^C{`=Bg}s-chtYXU5`MB)j0S$vd)%mH z_9aT{c!8Wn$^>y&b{irDqyv5QvF}}LkAdZ2>#-#SXS7&C5QdAjJt+Ub8EQZw-hagz z{Fgm@q4+C6gB!%(ohC{D%IQ+}!(8YjHV0m{dYzeGB#CPpDN#?R5~__Dry6y4XyF$c@B5X_UTvvwx1#;d}zVE zh7T>6C14XOau?W!ij?pn4)ZQP#9@~3Ar7;I4{?|!e2Bv=0mK2FNpq9z6Q9EP@FWvg zkQhtF>P=d>0Xvu*1wL+ofFG1U8s~EuTqDG#!#DB3Cx!TGfd8m=X#C_<5y}7QPF)+2 z?u0hLymOTL37!JhypHEB48EMVs2S+$maU`4PPO^*>C)yO$$->7U7qU6Lx9+dIcKBr zKrtQ@*IX>ae_^pJi3OltlOsA^Il`lFYjq^JE{nppovTxEN^fo)ok90^9kc3|opZdl zr*WY-!<~jCU;`Wi{%p}FI({5p{LH(5E@!;#{zuM-vyapT-&+ogTsR8lTVIJ2fS7~% z_1X5Fw1gUZ|Hv`@6&n$3@^?F=LWN(YMzF6tBGFI{ZiiKGj~^FE-C$G}8rIfSahpyI z(YDl4(-WZgNOxd#l`Ij-l>yo_8N>bab)N5Xn{HD_0B)muct{C|9%voufaOc5au<~L{CSE}FZuiUuvDhy&EoWgasTXnX# z?}UEDUKQ9{DJ7;z@a)lbJbpVtT>O#qb(+G`j?TdxS0(Em{#uTf4NJuz${*s3^R|gK zkp4vNcX$ByKl`<>lFon>V*?$Iro|^J!&n6>YhHdUwfGx{zBw1DjM~2Drh!3dM>~45 zxqRz(yeo{ACC~<~SlhF`HJ^{DKI}|D# z1wKPfpSWL$75KVB+92T|f>YE{Vl1sg-EawYi!O zKcwmEaWPJ4i`_GqTKZu2ugDE{4y5wiT2sIP`kaz)cAfqLGzmM`V9-*x*HSKrw|bf~ znta7EjL4Y8w`sABJDiyqPg~5wDWPPL@6VlL;=u0wZ1G}{nDD{xvB%%iNF$&SZ61Dmm|d2nbr|sXBvo4;(<$dz%*Q=aRR7MJGVRfpU9pAEXJ`AzhF65Oxqx+1IL0? zJ*|WSV^?k<)t7}1N|W)MpzsK-G0|dw8y`PWV`cUL(;u zfmq=7f7n7MgvX2C!CW<%wU%j%eML9Xr~y@Sw6S z!&x8jZ(Ss+!jU%61IL#V#@Y**;wvBTl0gyD><<+Xw}%A)zzsAEeE{@-650rHy77TU z?CsRmnLc{^8Tc-xc)67QO&+}re&d;*_3hx%F8}W6O7&)YZoxU)i$kwq+mx?p%zbkL zj*)7$IR-|HX3^K6gtX+@eE=O_jPjaS>5lC*UgSEm@VU}4nbhzor>eN01`S{ct)@;F z96g}PouLcVDZ5WIWH)>He7lBi(XeYkMNxFC7he<~cpk|AFU7j^RDkC%#lONeIFJs< zCk5hH<6SlEbxnb%>1{y!m8EW()Q4xKukaPnjQ}FtRfC>a*1B-Us!rWfr$3d{w|f28 zVv>5aLHB@2)X*B8lUq=j`&)^p!4vep^y=Z_27&k4Gc=SDP5zI$?^pvJq@Q;=6wp4f zNPzaG`p|T(>DFCqx?8*3w{}*Xu9uG#VVxCILkiI~mg+!v<(NImHyvX#Qxvp_b*nPI3RN0f(Dbe-WUh0AL{F*|GYL>go*cIIWipP;*o); zAU?E=zxS5&IAk>I_=-9mvHAG8IR%>*>*c+O+89IczR0HB9?zSOj9h(oeLCHqg^vXg zsn&1iaOkX1p5}a`85nHU|0I1qdgHim|1>{<{BL1I8%O}hfb{vg@=Wo-v!8E=PdMoR zWaZY-_{fZj#Dd+8m>)X7&(L8PR8?w-^Zjp^3-UVNL3I9;SP`_(96fXxlxKjJ5-7=L z1RY39;qfBY>HNem>sfUGxBgc;I%`og<$>Ysn+mT{+1QJ~8_7Doz z67yZn8Zxf+EBNu2ym;aFuxR$b!yGKeG1DXe|IpmanI71G*Gcm)?2oY?sAF4ztmoF4 zvph;>`>`h1S8I6y1SL!)2eEWOEBXhnU{`NgzrB4cBtqbH)r*e*rj3HO)PeV_(jIMs zHSf@C;0p!HyVtkpwqt>_tH1=OW0(Y;pVhGIFVOGfuVbZW19F%tEyJCuzD_VvKSEH3Cl3?i)xSjhN%q3}>Zg zxZ>hSN=zGGg6UyMi4r%)7K;dv9G(QNo#8cX&{=p0n>qz0sj0b?YtUwMJPv4khYc=C zOB9a=T?ExU{By&pflyw9@L0@tXo3oG##-^M>@Ony^#f44khSk4XTsQz-^%ama$rnsdzAi zAvfp<{0YX#lGt=Qe zwN=KJSnh*c>cAC4$`TC`n>Jv?#mFU&Ej5|=mbzt{wlP_1vM+wL0i7CewdaVzd*t80 z{6-K6AOw`YEj;vl;_u(a?|rjL+Y$KL10_HZmxZueyt7*~gLrz*(7+n$Lnn?UC|Wf0 zk@IOmvPJc{n{Za?147U6orpA}#+lB(F$#>{W5RUTX{JYa=<-^OZhNju8mIa6SSnZ8 zHgxIIPnmPE;s{iE7O8SN1Mi$|ZQ0yFe=c(=9uMXda8~8R34jG1j*{4jt4dJmu*XW? z{stw_65@9F|AHm_v-JOc;Qe10u={L@E;0^YAB6s|gK`8dl+;`ixQ>BHup3)wo{3im zf97JduiF@@6*&%J+0UWIZpbjQ2&j>W>p%e;N%8cAvgE{76RB&F0w@KR=9D6@1xw$@&ilfL|F?nH9mx=o?nH!K|lJ<~{tL3Io;Pcm-5&jrW!d$^jDWV-Crf zfNL__kf#FU0N7up4^upht;qjN z#(&b+8`d|oZ{sA%yP92(^K2?)rm;gMTP4WTU@Zd*f3AQQuSn{_F2^^|xO98lOmA&!sy+0c@$SHJvWv?`f6r_mEuzo%8gWEtA&V|LJQ za`x6mx^znF?)r&Z3jx{&?#CCmt8NeI{|DY$ z3;U0JyYv8fY%(zbZ5@rUXvE{f@CzBHUx>60!3zZGqK5j0fz}We9HWHgO*TpxjT#j!`tmFQSN!WrG$V+~D>huBaXP^fJ*i|Ic{rALVS8 zV*u%AFuTo}87Kal+hopWCd!drg|_&kL9deqCvx`^=ahA*$oD}E%f5_<^zzz zSFB#yQil-~QUQ&b6F22Ec$Z3xyrs@T?+Qo6Gj`AhSL5?_Z!}K?aNNa+{=<4=nQc_j>fe&|qeL zPpUf?^f$DJO1cZRd{WQSqZBP(-D-gKE%@%{Y5>L3baq)|dOToIUd|>P>u>Z`=t5oGQ@) zqhhR}kUrdyNfe5RH3q5~33_ID_Jno(R;7e$v@J(6YLW(Fz*XKMve2Mj%=@Jr^R-dm zX2AylD{X_8XY;+!%L88~)DuV^dl`d)f^FAN#hW|NmH3bOe*#nQbg2!Zbpza>59}cD z1X0-`83gcRwM7}?#GoIuc*I84sW3X3<0VQMI<}BrG^)QPnk9`u#xMqgAU;&n6~?`# z^gB9RFc6@Ja+}}`)LX{@K8|a>T<|%2z6Zj(Ip5!XkxobaGuUj(4;R>&PkLEkrcCY_ zfVluk>0Xs<@e9!M1NI~K8}eV1xbkN9`&pm@flY|s0gpGlQYCqRKxG<%u_wxOzm1Q! z2ssv1o|7!c0x({>Bfo91e|XK(xq-i6qy>xc_Ff zO540F-QCg=t>h$a&4JgjrKfF}?bRCv0jNeu?H0$6%+}ADT)XxneI`o2ARWlH=eyaR zz>l1-j{??myvVKLWsV!xaAJe48pRU9ei(6IA4iD)=I?(+h}2(*cgc*O;vW~)iarnm zY68XQ$Il4mE0x(35-M%Hp3I)%8Bb=<@C>B;gsXWndxmv9nLWcZp3I)%8Bb=<@C>B( zgcd+rPdMYr>=|Co%BdFK5*@S3;tItZ=Gem)QiDAhxps0#kDf>-Bshw+to_mVhvW$J@xu zK1|pk>n#*tg6n^7y!k)nkm4vfr4F&xJ@=17tZmEwu%$c-RGl`nC9 zYqmApzSYWHAoc%l^l^NBc$go{R{t}xSgiRg*!#r3e-U@G>K7;ueqDM3V^C}bhZvs} z%>KqZ%INPUM{;9Tv(g1Cu7G^c3A*5f5}GbJp@gOjPAH-2f)h$;y5NKonl3n@gr*Bl zD52?s6G~{h;Di#IE;ykCxQ&6hdWpCq?+j*V!}v01WlFJt#88m8Fwgrp?iXWf;51MR zfW8Md6rU6C7vTT!@QF}dD&k4C7n%2p7Iy|M)8=WU$3X;FXC|CIiQW-;_-S~(BhH@- zlofb|HaBHYgO|4lits(DIBZhLk> z&WqQP>&HDzM=#|4q76uV>W}4dOnhty5C^>RBJmFl3Z(xxtU0$JolUkAet@|=B0Ef) z&>8joyDu`&tc%XvKi{Ml(IQaLXvsJq#D|;jr;PHqI|_nWkAzVWYkotw`vkR%gBQaE z4m3h%C4CxOsAE8PW?GApVpiIEVmlK+wA?0iANsX9gKaytF}~nG?~E^LJTTuM6tqP) z+1YoC@5*BHALG|qVy*a#W%9sgAs7!h4&0YYU6#pT0|UxXCW!rv`9V7B;U6wA`@StY zlUrc+Jy!>i^Z>D~RwQujhONqAZnwr-y&w;z14&JnIRAqiT0(_$ZH8esHf zh?z87NbKHDT*g=jL$=*gXVZsZ)f=#_@;&06HC3W%Jw!K zW_yFBKlCZJSOdIDK{q@)hUM@SYh`M9I*Muhqk!XZjEz8PmOI*bkJZ=3V6gtK&}$}Q zLbvMC277+nK4eyA5|DMB=J>q^%<-_RnYslG69;AduJ{nUx}G~_^ZOgo9sDICY&!1? zGU^{HC7behM?JY5wjmYg79GUfgghClVTUk;Tu!#+KcS6Hb#rf{$NK#Jx{+2>p0%K z=48d&lhGlmyeB$D<@tu5@HnKHl>yioAW>F&$t5K@Hr&M-67QjfDeBoD8(PbmuH zSqtg|drzc;l~Q_SA2s=4Zh=0(-EpwfCE6GXdan}qSp=lp8f*y4wds@XzY{mU<6`^j zwme{69TI^q|H_eR+n_Qrql;H(S&&H11$LS2lyoT~kNkDpso5nrppv{Prgml8X_9@m9 zH!ok`3N10xk#QC)olp#;gZNmfiEul7OC3B~!a9*&*H_G-5abn}>^_#~%H0?0|GB^bJD*siYHj=xe*Lxl_bbW&A^(-Z-x)j{l0Xmz zsB{6QY!{{SMpPW>Lkv~pNKB>ecjyBaiOdWPz!Vn5fg9dI)C{i7=5}f6zP*Szyp2gz z1MeV}$fCI!hPZVp=p(cFTh?y}$yo)0+A`2Hlxqe7%04nf?-8#?%_j4Zjr2Lo8R&TS zn-~Fl5BQ8k6iVWXK(x~g$3yNIL-e5DI{z56#tY=^(~v|f+vm8aBLHYSJild6|K;Nt z4D;|4B%$?xhQ`3z`(>;L@+b^txaM1+4a&s9pwK~^BOprl2|XC?lJN)#g%yoOnCpVj z{9-Nqr(yW!SQ98`X@Y8pzJ^L`6l;9pWXLsLBApBP187O~_Swf0FPf~uqsa?;)hu>p zi`^q`j#$g}7YGsUjP9@XzIkc%w#w?om1SO)n}_UN{|@N?_s;AE$irz6#-$H2^&7VH z#NV~n1{NVH|C9eTg3B-#Aaw;2fH49nK!QtJK-n4JspTX#!uais#8Ki;#AmosBS<3K z62xse@tG@nQ+-2N7cwE+r&=SB>i_`XFNsO}rD{C*BDgUUFiMqWAvb{dwyS~HX<4|c zl_BAePY0a}&M)gmpm?g)NLq_H5IjZTpuYkuL~g|TE8uF9#zEfFse;57X6{0pj^r8) z>CVr|O+xa>`Nc<{r692FgzwuVdtHc?4I~F2l>a^=_qBT{zw0DPJ>2ydK$BIFkJ>a? zk7Y_k>1HL%uiC3&GrV^?E_U9ACt}K|f_N#6wKz|cF?yLZD_BJ#$eE?GIbyLZN16^_ z;&03sF7QpsyVy;cFv8T874zrB^EWV474bzJx3MYIfX&5}F-1p#*Y0 zMD(P2Ip~Qs=BO~16YBOx69F1CQ5C|Bg#JtO72A}seyipY7J<4r)-%TAX7-L?|JjsA_%}-Zo*viH5_tJ(uOV9Q?dW-0&ZaO9zqym^v2Dx@uG@HR zfbkp*sIT>HM+9)?x0Q(PU6StW9}c(#=63jwKrLc4Hnvq7X5{UYt7my!^7P3G#w5ePO6hFmF|6WbWZ8V+y>PK;?^lW zXN;{m-DbZ?=qz;mjznD^f0_s-f=}vlHOspZS}~p2)y!M~QEZlmbD2RP+qW|{m`%a$ z#~gQ~Gpc2dCN9;pwm+Zm@4d5DaT&PTpFl2COV{6z23+8*uOjFp*m~gp)h=ETSDs7K z!2BP||IgC-Be@fF{wDgTE3dTed9(bxLNQoAbedK&oVhDvf?M<3m0!?UFGaPtM zqdS!UL9qL;jdBJAiwfB~g5}EgkP2-NhU_UWlWq+2(MR;j&mk;ggLQO^Z2wR%?iDQui1<^o z=w$%{_|G696luWzzexekZ+y7c>}e+Fll_TIU{-&oRA;<$ESo>y9f zWP-nya%msizo!}gJ@D@N=3L#z?rQG3eu`y0V+qaszI)xCJbIo( z-yKbyeWypx*Leu<OckP@Q0nd9+05B<`qixPqn4m7K&<&i0yIA0BSSbvHS8a6pdvvt1&t>cpKJ@LBXeA^xmZd_!6VRBJvhzB9{;KM&V^z#uYvJX*{b zVF#wBS6aB$ctHPPJa}h1)U&B?&c$3<632O{%rMDgLwe$-T20duG!&Y5xie;r>4X-= znnZu}R!m6bYSR%F_Tas^C}eqkBywE2wx1}~P*+!b7PcRy?UBCpYND#%I04^ZymK*P z{ov|b`%D=5H6-tHNbdi9?dEYvW-|W|7WaYr5Z*u#hmqY|8sF^IfTJaUA!pc>>N$^?q%(|EO#5fs3`6gi^gij}UGsB2daIS{y-B_usX8DbJ62VC3{a@D!8)GCjX z(a}qI;(#qG1KpL5KBY|PsTIWq1c^%=ougz8CLFXf4|utO)tE0VhAuJ2ovY+3kR+h= zq>Y}J>t~wVEf2u--%aiBr-XP^eD!S6{4W9f7wfqAw-8?uqsaeAc+&{28ohr4dqyKP z${zcV%HSBS1zWTXbOS}pz=Nk~8F=y(Ed!69qGjOOQ?v{`e2SJ)zS@YC!o2C|&2?k$ zVD01pOZ7cmi+Lm`1XoS(==;=c3qeH@ZP#C*@xC~|QCU1qHjf^LCM&{`CP{R8OfURC zRtH1k>OY6jC%22lqc^-sh(8GbisvTEG(wHgs!Zz6^da?g zkw_YVXLetm`Uf!_u+Cl9g5)I9K8LHT5&=zE0+Jx7yVr{^!~yzz*D+Y)+%&|=aU;Ki zrjOTD8`^qu;N&(2bFFr4bqsVcVy+NXCeH;K3)SQpXgX#h91B+dnx~%Td;bT*zU@ zH-#tr2h*8B8&6&pWO?|2fD9lL#-P)~kr0dmcz}Q0>Sd;H3TeI7%W*1L=)WE7-7=UE z8C(a@hUZiEHYbwj@#(rO?1|F1dgFmbb}t7jq?x_!O4v^9w9yHZ7C7>qt0#2jJKL@n zzQj}YYq4nT7B^rJ2)Xq0pNsp#$^RH*g1-UZA7}{2U2o>l@`DKQ#B*LR@35ZN%R4;h z_3{qSdA+>Db6zj+@SNAnJ3Qz0@(#~=y}ZM7UN7(P9I&4?GvcJVuxFaGvGRhFQwmfL zNWLW&WHzhSNlZ^Da9v7QW+dwpYcfbBnakW;K8xA_i3nE#&Gx6mY;;72_|K5*u+gS}207qK2k83qgtFV_+)*w;27 zGIM>9`#YAkNQCd~Y|p;?BHMG^q(BJP1@eqavM!@)_AWKDK-|U%0`eDwBp(tlX zjQ0clX$H0DbiAKy&9!e0)&$Vj42Up{sItadoM0BX(X#w_qwg_u6;+fr1eGZ$NED5h zDym_7h9x+Y**;=&{+cfq`fYnmIN2WJX%5Y?u5I$mnR&a9@$^7NG3v8qs*L`QGp(8S zt)HA)MLn}xsKFKeqp|Qq{#pq>@K+*pD}Mg5cv9@Hl?y>GkUF4oY4ZnAS(t%DVr|^kI*U9Fdap{2gD(@fDZv3H z>#~7Q=F6HjKyh_+%o;XFF)Ltj7T7)mPtW>q1_kH=ej(F)_BMN}_ zKcsPOyt7uW1RN>=Z*P?2g6o2)QHJF}BCQq-*B-4_v~0@t7ic}onHp(S=QcsdW%vrvLQ70k*|R@anDJK_pJ z=lVSM&PZ44!>n|?N?f1Am8%>~O# zMz$qM#V}+pU|+w7yN+i#?GLx&=O0TC;HA?3~wM?dN zS%#48Vc&}%{4@8T`3LT?z56n8!*(qG%SZrG`-hJIXIpk>5bGUTd2A0+tAyXitZ=o*Ta@!O@$Hv8>TW*Kc4c12Z@V(fKySfr4YvDU zQoqC%E4bF96!@?nRPQ_FiGAX0pZnOj+csps(?B&O zPCQ}n-gsOP=YL7kKo<;dd+ViYk@SjVq}F=^A5y4W*2 z&fvWiI5Q0k0n7rDLes!)uG8-N`fPQ%HFQw6R>t-OivfWfDeg${F**d+D+LEc-ld@0 z#VrXjY`FWv(>ezG`>_gKC1pFpJ|~f1P+Aj&L~a z72?|!>CCo9 z29Rv-AHd41)mk)3Pd10%JUw&-V7}1f64uS`EN#0nnDe{E*--t4+nHC1)z1&0--URL z_}~EJeG}&O=f`kLf^r~uIced9LJ!~AkwGnSr+{CX zrBe*^cduO=7hraQ#8F`Ns-ima$g*?4#S;wlQJ2+dd$MviS<>P&MywIXjjKJhAUS-W z?U55oB<9G0f6e5Mz9_fzG|u>J?($Sm9zyMFp7yG*gYQOB`|zK=1*srm`+bhqprISO zKljx8dGcq_|9NaYLp{s@?6>g*=lnLF;GEx96P)wgYJziqTTO7zZ>tH;`E519Iq*wK z*SZE%y;#nyFWr+F1g*35TXAZ;z=EOsBt*%qZf~?^1Os8ES?85=amJKrmq4|pY@z0v zRUi;S5H!5ZHD8%P3$iL$1r^GT%bHuT%p_wMBU^;rsAfN5;gC4R6?8<$w zae6rTN?PwcPAUgJX}#Gf!18E=X)g;Sy*zQ4-~}x))rnX2b?rNb=83Lvme_dyT<8eo zdiIEgy()7{F3v{Q-oup#c+9h^fR}28b_|_r;fX@36)`QZKZ)+0o}7i!6cph$qi^Ws zYs95OoSj)*E50foI}-y!Dh1@KfI|EaAwD)<8Ag9JqOZvdWCV2Ml`U~x2o{FIIsHG! zMK!eqD&uu8lVF?v!jX#`xTMv;(b6$;1r05dFS3Uki;NCWaOVjWkbxdBSTNYDE$Hma z5B7xGg5{V;>})Ep67{z(nuHEl=NYo5#}70HiR1HYaVJ6+;#W|J&`_pps(gBMh_d;#J0IV3?rcLR_89p=B;Yh1BG5;gCN4e|_D zY_R5XDq{aG{iN5BdXenKB;*AjIbYM|P+N@G+<)!n_2w#|xTi@;ms1YP^ni>e z`id=8w?G+JpOo)c`lMlazhb_r>jP>AmdxPp&q^)QBgXlFNXYnM(m)`5%~BY{0X1Oa5rC55DPdbwE?FzdqPqf*3X|2T*q|vo z9&OOIyROEf+vPEMV~C%PMxz>I<~V#{k#2?dagc2Mbl@Jr_6PL{`9Jda3s(v8p*^7c zH*LZy0L=f32w(_+qW4p@|4U0+} zJdkh((m=u)$N~vxAPFR#fgE7+Ij%)1hcc+9c_wmzgbLl_b8#}5j$^tMp2_Nx zMOL*A^WMROGH|q7Nw==`*&eQVbQSbpSYcxZ#^&3%-kj+qhzbz|Ms_qtBo0wIjm?1q z?yR;4@#6-_d7$@QUz9$8aQuHW4$i0Uhms&t0|oh?d;8(l(m#kbrgr8rHzZY8$AGpT3{Hxf5Zj=$l@U)=Kau4^9ANJ611;0Y0Ev4^-2 z4j6lAwFNxwMyLb(T-b)_%n_qTpc4cTi|mm0eIu!{fb`2ieK5#*RfwKhc2o}d&NqlS zmfjiAN04=i7(3LE_unATaD!Gp7Nf3B1m+CjZbW$N9?5AKYlJYykrAacmNf$ys^P2B VAlnAf=Y}0IXAIHCu7I6t1^|FaB$ogH literal 0 HcmV?d00001 diff --git a/src/core/bitmanip.d b/src/core/bitmanip.d new file mode 100644 index 0000000..11397c9 --- /dev/null +++ b/src/core/bitmanip.d @@ -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 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 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
    + * 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 bitmanip; + + int main() + { + uint array[2]; + + array[0] = 2; + array[1] = 0x100; + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bts(array, 35) = %d\n", bts(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btr(array, 35) = %d\n", btr(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bt(array, 1) = %d\n", bt(array, 1)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + return 0; + } + * --- + * Output: +
    +    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
    +    
    + */ + 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 ); + } +} diff --git a/src/core/exception.d b/src/core/exception.d new file mode 100644 index 0000000..24a5bdc --- /dev/null +++ b/src/core/exception.d @@ -0,0 +1,251 @@ +/** + * The exception module defines all system-level exceptions and provides a + * mechanism to alter system-level error handling. + * + * Copyright: Copyright (c) 2005-2008, The D Runtime Project + * License: BSD Style, see LICENSE + * Authors: Sean Kelly + */ +module exception; + + +private +{ + alias void function( char[] file, size_t line, char[] msg = null ) assertHandlerType; + + assertHandlerType assertHandler = null; +} + + +/** + * Thrown on an array bounds error. + */ +class ArrayBoundsException : Exception +{ + this( char[] file, size_t line ) + { + super( "Array index out of bounds", file, line ); + } +} + + +/** + * Thrown on an assert error. + */ +class AssertException : Exception +{ + this( char[] file, size_t line ) + { + super( "Assertion failure", file, line ); + } + + this( char[] msg, char[] file, size_t line ) + { + super( msg, file, line ); + } +} + + +/** + * Thrown on finalize error. + */ +class FinalizeException : Exception +{ + ClassInfo info; + + this( ClassInfo c, Exception e = null ) + { + super( "Finalization error", e ); + info = c; + } + + string toString() + { + return "An exception was thrown while finalizing an instance of class " ~ info.name; + } +} + + +/** + * Thrown on an out of memory error. + */ +class OutOfMemoryException : Exception +{ + this( char[] file, size_t line ) + { + super( "Memory allocation failed", file, line ); + } + + string toString() + { + return msg ? super.toString() : "Memory allocation failed"; + } +} + + +/** + * Thrown on a switch error. + */ +class SwitchException : Exception +{ + this( char[] 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( char[] 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 AssertException 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( char[] file, size_t line ) +{ + if( assertHandler is null ) + throw new AssertException( 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 AssertException 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( char[] file, size_t line, char[] msg ) +{ + if( assertHandler is null ) + throw new AssertException( msg, file, line ); + assertHandler( file, line, msg ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Internal Error Callbacks +/////////////////////////////////////////////////////////////////////////////// + + +/** + * A callback for array bounds errors in D. An ArrayBoundsException will be + * thrown. + * + * Params: + * file = The name of the file that signaled this error. + * line = The line number on which this error occurred. + * + * Throws: + * ArrayBoundsException. + */ +extern (C) void onArrayBoundsError( char[] file, size_t line ) +{ + throw new ArrayBoundsException( file, line ); +} + + +/** + * A callback for finalize errors in D. A FinalizeException will be thrown. + * + * Params: + * e = The exception thrown during finalization. + * + * Throws: + * FinalizeException. + */ +extern (C) void onFinalizeError( ClassInfo info, Exception ex ) +{ + throw new FinalizeException( info, ex ); +} + + +/** + * A callback for out of memory errors in D. An OutOfMemoryException will be + * thrown. + * + * Throws: + * OutOfMemoryException. + */ +extern (C) void onOutOfMemoryError() +{ + // NOTE: Since an out of memory condition exists, no allocation must occur + // while generating this object. + throw cast(OutOfMemoryException) cast(void*) OutOfMemoryException.classinfo.init; +} + + +/** + * A callback for switch errors in D. A SwitchException will be thrown. + * + * Params: + * file = The name of the file that signaled this error. + * line = The line number on which this error occurred. + * + * Throws: + * SwitchException. + */ +extern (C) void onSwitchError( char[] file, size_t line ) +{ + throw new SwitchException( 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( char[] msg, size_t idx ) +{ + throw new UnicodeException( msg, idx ); +} diff --git a/src/core/memory.d b/src/core/memory.d new file mode 100644 index 0000000..9bdd3d6 --- /dev/null +++ b/src/core/memory.d @@ -0,0 +1,444 @@ +/** + * The memory module provides an interface to the garbage collector and to + * any other OS or API-level memory management facilities. + * + * Copyright: Copyright (c) 2005-2008, The D Runtime Project + * License: BSD Style, see LICENSE + * Authors: Sean Kelly + */ +module 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 the garbage collector 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 the garbage + * collector is enabled. + */ + static void enable() + { + gc_enable(); + } + + + /** + * Disables the garbage collector. 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 ); + } +} diff --git a/src/core/posix.mak b/src/core/posix.mak new file mode 100644 index 0000000..9e7c82d --- /dev/null +++ b/src/core/posix.mak @@ -0,0 +1,129 @@ +# Makefile to build the D runtime library core components for Posix +# Designed to work with GNU make +# Targets: +# make +# Same as make all +# make lib +# Build the common library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=libdruntime-core.a +LIB_MASK=libdruntime-core*.a + +CP=cp -f +RM=rm -f +MD=mkdir -p + +ADD_CFLAGS= +ADD_DFLAGS= + +CFLAGS=-O $(ADD_CFLAGS) +#CFLAGS=-g $(ADD_CFLAGS) + +DFLAGS=-release -O -inline -w -nofloat -version=Posix $(ADD_DFLAGS) +#DFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS) + +TFLAGS=-O -inline -w -nofloat -version=Posix $(ADD_DFLAGS) +#TFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS) + +DOCFLAGS=-version=DDoc -version=Posix + +CC=gcc +LC=$(AR) -qsv +DC=dmd + +INC_DEST=../../import +LIB_DEST=../../lib +DOC_DEST=../../doc + +.SUFFIXES: .s .S .c .cpp .d .html .o + +.s.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.S.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.c.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.cpp.o: + g++ -c $(CFLAGS) $< -o$@ + +.d.o: + $(DC) -c $(DFLAGS) -Hf$*.di $< -of$@ +# $(DC) -c $(DFLAGS) $< -of$@ + +.d.html: + $(DC) -c -o- $(DOCFLAGS) -Df$*.html $< + +targets : lib doc +all : lib doc +core : lib +lib : core.lib +doc : core.doc + +###################################################### + +OBJ_CORE= \ + bitmanip.o \ + exception.o \ + memory.o \ + runtime.o \ + thread.o + +OBJ_STDC= \ + stdc.o + +ALL_OBJS= \ + $(OBJ_CORE) \ + $(OBJ_STDC) + +###################################################### + +DOC_CORE= \ + bitmanip.html \ + exception.html \ + memory.html \ + runtime.html \ + thread.html + + +ALL_DOCS= + +###################################################### + +core.lib : $(LIB_TARGET) + +$(LIB_TARGET) : $(ALL_OBJS) + $(RM) $@ + $(LC) $@ $(ALL_OBJS) + +core.doc : $(ALL_DOCS) + echo Documentation generated. + +###################################################### + +### bitmanip + +bitmanip.o : bitmanip.d + $(DC) -c $(DFLAGS) bitmanip.d -of$@ + +###################################################### + +clean : + find . -name "*.di" | xargs $(RM) + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + find . -name "$(LIB_MASK)" | xargs $(RM) + +install : + $(MD) $(INC_DEST) + find . -name "*.di" -exec cp -f {} $(INC_DEST)/{} \; + $(MD) $(DOC_DEST) + find . -name "*.html" -exec cp -f {} $(DOC_DEST)/{} \; + $(MD) $(LIB_DEST) + find . -name "$(LIB_MASK)" -exec cp -f {} $(LIB_DEST)/{} \; diff --git a/src/core/runtime.d b/src/core/runtime.d new file mode 100644 index 0000000..5263374 --- /dev/null +++ b/src/core/runtime.d @@ -0,0 +1,171 @@ +/** + * The runtime module exposes information specific to the D runtime code. + * + * Copyright: Copyright (c) 2005-2008, The D Runtime Project + * License: BSD Style, see LICENSE + * Authors: Sean Kelly + */ +module 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( Exception ) ExceptionHandler; + extern (C) bool rt_init( ExceptionHandler dg = null ); + extern (C) bool rt_term( ExceptionHandler dg = null ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// 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( void delegate( Exception ) 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( void delegate( Exception ) 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(); + } + + + /** + * 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: + static 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(); +} diff --git a/src/core/stdc.c b/src/core/stdc.c new file mode 100644 index 0000000..6e4ac64 --- /dev/null +++ b/src/core/stdc.c @@ -0,0 +1,21 @@ +/** + * This file contains wrapper functions for macro-defined C rouines. + * + * Copyright: Copyright (c) 2005-2008, The D Runtime Project + * License: BSD Style, see LICENSE + * Authors: Sean Kelly + */ +#include + + +int _d_getErrno() +{ + return errno; +} + + +int _d_setErrno( int val ) +{ + errno = val; + return val; +} diff --git a/src/core/thread.d b/src/core/thread.d new file mode 100644 index 0000000..1a912d0 --- /dev/null +++ b/src/core/thread.d @@ -0,0 +1,3199 @@ +/** + * The thread module provides support for thread creation and management. + * + * Copyright: Copyright (c) 2005-2008, The D Runtime Project + * License: BSD Style, see LICENSE + * Authors: Sean Kelly + */ +module thread; + + +// this should be true for most architectures +version = StackGrowsDown; + + +/////////////////////////////////////////////////////////////////////////////// +// Thread and Fiber Exceptions +/////////////////////////////////////////////////////////////////////////////// + + +/** + * Base class for thread exceptions. + */ +class ThreadException : Exception +{ + this( char[] msg ) + { + super( msg ); + } +} + + +/** + * Base class for fiber exceptions. + */ +class FiberException : Exception +{ + this( char[] msg ) + { + super( msg ); + } +} + + +private +{ + // + // exposed by compiler runtime + // + extern (C) void* rt_stackBottom(); + extern (C) void* rt_stackTop(); + + + void* getStackBottom() + { + return rt_stackBottom(); + } + + + void* getStackTop() + { + version( D_InlineAsm_X86 ) + { + asm + { + naked; + mov EAX, ESP; + ret; + } + } + else + { + return rt_stackTop(); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Thread Entry Point and Signal Handlers +/////////////////////////////////////////////////////////////////////////////// + + +version( Windows ) +{ + private + { + import stdc.stdint : uintptr_t; // for _beginthreadex decl below + import sys.windows.windows; + + const DWORD TLS_OUT_OF_INDEXES = 0xFFFFFFFF; + + extern (Windows) alias uint function(void*) btex_fptr; + extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*); + + + // + // entry point for Windows threads + // + extern (Windows) uint thread_entryPoint( void* arg ) + { + Thread obj = cast(Thread) arg; + assert( obj ); + scope( exit ) Thread.remove( obj ); + + assert( obj.m_curr is &obj.m_main ); + obj.m_main.bstack = getStackBottom(); + obj.m_main.tstack = obj.m_main.bstack; + Thread.add( &obj.m_main ); + Thread.setThis( obj ); + + // NOTE: No GC allocations may occur until the stack pointers have + // been set and Thread.getThis returns a valid reference to + // this thread object (this latter condition is not strictly + // necessary on Win32 but it should be followed for the sake + // of consistency). + + // TODO: Consider putting an auto exception object here (using + // alloca) forOutOfMemoryError plus something to track + // whether an exception is in-flight? + + try + { + obj.run(); + } + catch( Object o ) + { + obj.m_unhandled = o; + } + return 0; + } + + + // + // copy of the same-named function in phobos.std.thread--it uses the + // Windows naming convention to be consistent with GetCurrentThreadId + // + HANDLE GetCurrentThreadHandle() + { + const uint DUPLICATE_SAME_ACCESS = 0x00000002; + + HANDLE curr = GetCurrentThread(), + proc = GetCurrentProcess(), + hndl; + + DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS ); + return hndl; + } + } +} +else version( Posix ) +{ + private + { + import stdc.posix.semaphore; + import stdc.posix.pthread; + import stdc.posix.signal; + import stdc.posix.time; + import stdc.errno; + + extern (C) int _d_getErrno(); + alias _d_getErrno getErrno; + + version( GNU ) + { + import gcc.builtins; + } + + + // + // entry point for POSIX threads + // + extern (C) void* thread_entryPoint( void* arg ) + { + Thread obj = cast(Thread) arg; + assert( obj ); + scope( exit ) + { + // NOTE: isRunning should be set to false after the thread is + // removed or a double-removal could occur between this + // function and thread_suspendAll. + Thread.remove( obj ); + obj.m_isRunning = false; + } + + static extern (C) void thread_cleanupHandler( void* arg ) + { + Thread obj = cast(Thread) arg; + assert( obj ); + + // NOTE: If the thread terminated abnormally, just set it as + // not running and let thread_suspendAll remove it from + // the thread list. This is safer and is consistent + // with the Windows thread code. + obj.m_isRunning = false; + } + + // NOTE: Using void to skip the initialization here relies on + // knowledge of how pthread_cleanup is implemented. It may + // not be appropriate for all platforms. However, it does + // avoid the need to link the pthread module. If any + // implementation actually requires default initialization + // then pthread_cleanup should be restructured to maintain + // the current lack of a link dependency. + pthread_cleanup cleanup = void; + cleanup.push( &thread_cleanupHandler, cast(void*) obj ); + + // NOTE: For some reason this does not always work for threads. + //obj.m_main.bstack = getStackBottom(); + version( D_InlineAsm_X86 ) + { + static void* getBasePtr() + { + asm + { + naked; + mov EAX, EBP; + ret; + } + } + + obj.m_main.bstack = getBasePtr(); + } + else version( StackGrowsDown ) + obj.m_main.bstack = &obj + 1; + else + obj.m_main.bstack = &obj; + obj.m_main.tstack = obj.m_main.bstack; + assert( obj.m_curr == &obj.m_main ); + Thread.add( &obj.m_main ); + Thread.setThis( obj ); + + // NOTE: No GC allocations may occur until the stack pointers have + // been set and Thread.getThis returns a valid reference to + // this thread object (this latter condition is not strictly + // necessary on Win32 but it should be followed for the sake + // of consistency). + + // TODO: Consider putting an auto exception object here (using + // alloca) forOutOfMemoryError plus something to track + // whether an exception is in-flight? + + try + { + obj.run(); + } + catch( Object o ) + { + obj.m_unhandled = o; + } + return null; + } + + + // + // used to track the number of suspended threads + // + sem_t suspendCount; + + + extern (C) void thread_suspendHandler( int sig ) + in + { + assert( sig == SIGUSR1 ); + } + body + { + version( D_InlineAsm_X86 ) + { + asm + { + pushad; + } + } + else version( GNU ) + { + __builtin_unwind_init(); + } + else + { + static assert( false, "Architecture not supported." ); + } + + // NOTE: Since registers are being pushed and popped from the + // stack, any other stack data used by this function should + // be gone before the stack cleanup code is called below. + { + Thread obj = Thread.getThis(); + + // NOTE: The thread reference returned by getThis is set within + // the thread startup code, so it is possible that this + // handler may be called before the reference is set. In + // this case it is safe to simply suspend and not worry + // about the stack pointers as the thread will not have + // any references to GC-managed data. + if( obj && !obj.m_lock ) + { + obj.m_curr.tstack = getStackTop(); + } + + sigset_t sigres = void; + int status; + + status = sigfillset( &sigres ); + assert( status == 0 ); + + status = sigdelset( &sigres, SIGUSR2 ); + assert( status == 0 ); + + status = sem_post( &suspendCount ); + assert( status == 0 ); + + sigsuspend( &sigres ); + + if( obj && !obj.m_lock ) + { + obj.m_curr.tstack = obj.m_curr.bstack; + } + } + + version( D_InlineAsm_X86 ) + { + asm + { + popad; + } + } + else version( GNU ) + { + // registers will be popped automatically + } + else + { + static assert( false, "Architecture not supported." ); + } + } + + + extern (C) void thread_resumeHandler( int sig ) + in + { + assert( sig == SIGUSR2 ); + } + body + { + + } + } +} +else +{ + // NOTE: This is the only place threading versions are checked. If a new + // version is added, the module code will need to be searched for + // places where version-specific code may be required. This can be + // easily accomlished by searching for 'Windows' or 'Posix'. + static assert( false, "Unknown threading implementation." ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Thread +/////////////////////////////////////////////////////////////////////////////// + + +/** + * This class encapsulates all threading functionality for the D + * programming language. As thread manipulation is a required facility + * for garbage collection, all user threads should derive from this + * class, and instances of this class should never be explicitly deleted. + * A new thread may be created using either derivation or composition, as + * in the following example. + * + * Example: + * ---------------------------------------------------------------------------- + * + * class DerivedThread : Thread + * { + * this() + * { + * super( &run ); + * } + * + * private : + * void run() + * { + * printf( "Derived thread running.\n" ); + * } + * } + * + * void threadFunc() + * { + * printf( "Composed thread running.\n" ); + * } + * + * // create instances of each type + * Thread derived = new DerivedThread(); + * Thread composed = new Thread( &threadFunc ); + * + * // start both threads + * derived.start(); + * composed.start(); + * + * ---------------------------------------------------------------------------- + */ +class Thread +{ + /////////////////////////////////////////////////////////////////////////// + // Initialization + /////////////////////////////////////////////////////////////////////////// + + + /** + * Initializes a thread object which is associated with a static + * D function. + * + * Params: + * fn = The thread function. + * sz = The stack size for this thread. + * + * In: + * fn must not be null. + */ + this( void function() fn, size_t sz = 0 ) + in + { + assert( fn ); + } + body + { + m_fn = fn; + m_sz = sz; + m_call = Call.FN; + m_curr = &m_main; + } + + + /** + * Initializes a thread object which is associated with a dynamic + * D function. + * + * Params: + * dg = The thread function. + * sz = The stack size for this thread. + * + * In: + * dg must not be null. + */ + this( void delegate() dg, size_t sz = 0 ) + in + { + assert( dg ); + } + body + { + m_dg = dg; + m_sz = sz; + m_call = Call.DG; + m_curr = &m_main; + } + + + /** + * Cleans up any remaining resources used by this object. + */ + ~this() + { + if( m_addr == m_addr.init ) + { + return; + } + + version( Win32 ) + { + m_addr = m_addr.init; + CloseHandle( m_hndl ); + m_hndl = m_hndl.init; + } + else version( Posix ) + { + pthread_detach( m_addr ); + m_addr = m_addr.init; + } + } + + + /////////////////////////////////////////////////////////////////////////// + // General Actions + /////////////////////////////////////////////////////////////////////////// + + + /** + * Starts the thread and invokes the function or delegate passed upon + * construction. + * + * In: + * This routine may only be called once per thread instance. + * + * Throws: + * ThreadException if the thread fails to start. + */ + final void start() + in + { + assert( !next && !prev ); + } + body + { + version( Win32 ) {} else + version( Posix ) + { + pthread_attr_t attr; + + if( pthread_attr_init( &attr ) ) + throw new ThreadException( "Error initializing thread attributes" ); + if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) ) + throw new ThreadException( "Error initializing thread stack size" ); + if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) ) + throw new ThreadException( "Error setting thread joinable" ); + } + + // NOTE: This operation needs to be synchronized to avoid a race + // condition with the GC. Without this lock, the thread + // could start and allocate memory before being added to + // the global thread list, preventing it from being scanned + // and causing memory to be collected that is still in use. + synchronized( slock ) + { + version( Win32 ) + { + m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr ); + if( cast(size_t) m_hndl == 0 ) + throw new ThreadException( "Error creating thread" ); + } + else version( Posix ) + { + m_isRunning = true; + scope( failure ) m_isRunning = false; + + if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 ) + throw new ThreadException( "Error creating thread" ); + } + multiThreadedFlag = true; + add( this ); + } + } + + + /** + * Waits for this thread to complete. If the thread terminated as the + * result of an unhandled exception, this exception will be rethrown. + * + * Params: + * rethrow = Rethrow any unhandled exception which may have caused this + * thread to terminate. + * + * Throws: + * ThreadException if the operation fails. + * Any exception not handled by the joined thread. + * + * Returns: + * Any exception not handled by this thread if rethrow = false, null + * otherwise. + */ + final Object join( bool rethrow = true ) + { + version( Win32 ) + { + if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 ) + throw new ThreadException( "Unable to join thread" ); + // NOTE: m_addr must be cleared before m_hndl is closed to avoid + // a race condition with isRunning. The operation is labeled + // volatile to prevent compiler reordering. + volatile m_addr = m_addr.init; + CloseHandle( m_hndl ); + m_hndl = m_hndl.init; + } + else version( Posix ) + { + if( pthread_join( m_addr, null ) != 0 ) + throw new ThreadException( "Unable to join thread" ); + // NOTE: pthread_join acts as a substitute for pthread_detach, + // which is normally called by the dtor. Setting m_addr + // to zero ensures that pthread_detach will not be called + // on object destruction. + volatile m_addr = m_addr.init; + } + if( m_unhandled ) + { + if( rethrow ) + throw m_unhandled; + return m_unhandled; + } + return null; + } + + + /////////////////////////////////////////////////////////////////////////// + // General Properties + /////////////////////////////////////////////////////////////////////////// + + + /** + * Gets the user-readable label for this thread. + * + * Returns: + * The name of this thread. + */ + final char[] name() + { + synchronized( this ) + { + return m_name; + } + } + + + /** + * Sets the user-readable label for this thread. + * + * Params: + * val = The new name of this thread. + */ + final void name( char[] val ) + { + synchronized( this ) + { + m_name = val.dup; + } + } + + + /** + * Gets the daemon status for this thread. While the runtime will wait for + * all normal threads to complete before tearing down the process, daemon + * threads are effectively ignored and thus will not prevent the process + * from terminating. In effect, daemon threads will be terminated + * automatically by the OS when the process exits. + * + * Returns: + * true if this is a daemon thread. + */ + final bool isDaemon() + { + synchronized( this ) + { + return m_isDaemon; + } + } + + + /** + * Sets the daemon status for this thread. While the runtime will wait for + * all normal threads to complete before tearing down the process, daemon + * threads are effectively ignored and thus will not prevent the process + * from terminating. In effect, daemon threads will be terminated + * automatically by the OS when the process exits. + * + * Params: + * val = The new daemon status for this thread. + */ + final void isDaemon( bool val ) + { + synchronized( this ) + { + m_isDaemon = val; + } + } + + + /** + * Tests whether this thread is running. + * + * Returns: + * true if the thread is running, false if not. + */ + final bool isRunning() + { + if( m_addr == m_addr.init ) + { + return false; + } + + version( Win32 ) + { + uint ecode = 0; + GetExitCodeThread( m_hndl, &ecode ); + return ecode == STILL_ACTIVE; + } + else version( Posix ) + { + // NOTE: It should be safe to access this value without + // memory barriers because word-tearing and such + // really isn't an issue for boolean values. + return m_isRunning; + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Thread Priority Actions + /////////////////////////////////////////////////////////////////////////// + + + /** + * The minimum scheduling priority that may be set for a thread. On + * systems where multiple scheduling policies are defined, this value + * represents the minimum valid priority for the scheduling policy of + * the process. + */ + static const int PRIORITY_MIN; + + + /** + * The maximum scheduling priority that may be set for a thread. On + * systems where multiple scheduling policies are defined, this value + * represents the minimum valid priority for the scheduling policy of + * the process. + */ + static const int PRIORITY_MAX; + + + /** + * Gets the scheduling priority for the associated thread. + * + * Returns: + * The scheduling priority of this thread. + */ + final int priority() + { + version( Win32 ) + { + return GetThreadPriority( m_hndl ); + } + else version( Posix ) + { + int policy; + sched_param param; + + if( pthread_getschedparam( m_addr, &policy, ¶m ) ) + throw new ThreadException( "Unable to get thread priority" ); + return param.sched_priority; + } + } + + + /** + * Sets the scheduling priority for the associated thread. + * + * Params: + * val = The new scheduling priority of this thread. + */ + final void priority( int val ) + { + version( Win32 ) + { + if( !SetThreadPriority( m_hndl, val ) ) + throw new ThreadException( "Unable to set thread priority" ); + } + else version( Posix ) + { + // NOTE: pthread_setschedprio is not implemented on linux, so use + // the more complicated get/set sequence below. + //if( pthread_setschedprio( m_addr, val ) ) + // throw new ThreadException( "Unable to set thread priority" ); + + int policy; + sched_param param; + + if( pthread_getschedparam( m_addr, &policy, ¶m ) ) + throw new ThreadException( "Unable to set thread priority" ); + param.sched_priority = val; + if( pthread_setschedparam( m_addr, policy, ¶m ) ) + throw new ThreadException( "Unable to set thread priority" ); + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Actions on Calling Thread + /////////////////////////////////////////////////////////////////////////// + + + /** + * Suspends the calling thread for at least the supplied time, up to a + * maximum of (uint.max - 1) milliseconds. + * + * Params: + * period = The minimum duration the calling thread should be suspended, + * in seconds. Sub-second durations are specified as fractional + * values. + * + * In: + * period must be less than (uint.max - 1) milliseconds. + * + * Example: + * ------------------------------------------------------------------------ + * + * Thread.sleep( 0.05 ); // sleep for 50 milliseconds + * Thread.sleep( 5 ); // sleep for 5 seconds + * + * ------------------------------------------------------------------------ + */ + static void sleep( double period ) + in + { + // NOTE: The fractional value added to period is to correct fp error. + assert( period * 1000 + 0.1 < uint.max - 1 ); + } + body + { + version( Win32 ) + { + Sleep( cast(uint)( period * 1000 + 0.1 ) ); + } + else version( Posix ) + { + timespec tin = void; + timespec tout = void; + + period += 0.000_000_000_1; + + if( tin.tv_sec.max < period ) + { + tin.tv_sec = tin.tv_sec.max; + tin.tv_nsec = 0; + } + else + { + tin.tv_sec = cast(typeof(tin.tv_sec)) period; + tin.tv_nsec = cast(typeof(tin.tv_nsec)) ((period % 1.0) * 1_000_000_000); + } + + while( true ) + { + if( !nanosleep( &tin, &tout ) ) + return; + if( getErrno() != EINTR ) + throw new ThreadException( "Unable to sleep for specified duration" ); + tin = tout; + } + } + } + + + /** + * Forces a context switch to occur away from the calling thread. + */ + static void yield() + { + version( Win32 ) + { + // NOTE: Sleep(1) is necessary because Sleep(0) does not give + // lower priority threads any timeslice, so looping on + // Sleep(0) could be resource-intensive in some cases. + Sleep( 1 ); + } + else version( Posix ) + { + sched_yield(); + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Thread Accessors + /////////////////////////////////////////////////////////////////////////// + + + /** + * Provides a reference to the calling thread. + * + * Returns: + * The thread object representing the calling thread. The result of + * deleting this object is undefined. + */ + static Thread getThis() + { + // NOTE: This function may not be called until thread_init has + // completed. See thread_suspendAll for more information + // on why this might occur. + version( Win32 ) + { + return cast(Thread) TlsGetValue( sm_this ); + } + else version( Posix ) + { + return cast(Thread) pthread_getspecific( sm_this ); + } + } + + + /** + * Provides a list of all threads currently being tracked by the system. + * + * Returns: + * An array containing references to all threads currently being + * tracked by the system. The result of deleting any contained + * objects is undefined. + */ + static Thread[] getAll() + { + synchronized( slock ) + { + size_t pos = 0; + Thread[] buf = new Thread[sm_tlen]; + + foreach( Thread t; Thread ) + { + buf[pos++] = t; + } + return buf; + } + } + + + /** + * Operates on all threads currently being tracked by the system. The + * result of deleting any Thread object is undefined. + * + * Params: + * dg = The supplied code as a delegate. + * + * Returns: + * Zero if all elemented are visited, nonzero if not. + */ + static int opApply( int delegate( inout Thread ) dg ) + { + synchronized( slock ) + { + int ret = 0; + + for( Thread t = sm_tbeg; t; t = t.next ) + { + ret = dg( t ); + if( ret ) + break; + } + return ret; + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Local Storage Actions + /////////////////////////////////////////////////////////////////////////// + + + /** + * Indicates the number of local storage pointers available at program + * startup. It is recommended that this number be at least 64. + */ + static const uint LOCAL_MAX = 64; + + + /** + * Reserves a local storage pointer for use and initializes this location + * to null for all running threads. + * + * Returns: + * A key representing the array offset of this memory location. + */ + static uint createLocal() + { + synchronized( slock ) + { + foreach( uint key, inout bool set; sm_local ) + { + if( !set ) + { + //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139) + for( Thread t = sm_tbeg; t; t = t.next ) + { + t.m_local[key] = null; + } + set = true; + return key; + } + } + throw new ThreadException( "No more local storage slots available" ); + } + } + + + /** + * Marks the supplied key as available and sets the associated location + * to null for all running threads. It is assumed that any key passed + * to this function is valid. The result of calling this function for + * a key which is still in use is undefined. + * + * Params: + * key = The key to delete. + */ + static void deleteLocal( uint key ) + { + synchronized( slock ) + { + sm_local[key] = false; + // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139) + for( Thread t = sm_tbeg; t; t = t.next ) + { + t.m_local[key] = null; + } + } + } + + + /** + * Loads the value stored at key within a thread-local static array. It is + * assumed that any key passed to this function is valid. + * + * Params: + * key = The location which holds the desired data. + * + * Returns: + * The data associated with the supplied key. + */ + static void* getLocal( uint key ) + { + return getThis().m_local[key]; + } + + + /** + * Stores the supplied value at key within a thread-local static array. It + * is assumed that any key passed to this function is valid. + * + * Params: + * key = The location to store the supplied data. + * val = The data to store. + * + * Returns: + * A copy of the data which has just been stored. + */ + static void* setLocal( uint key, void* val ) + { + return getThis().m_local[key] = val; + } + + + /////////////////////////////////////////////////////////////////////////// + // Static Initalizer + /////////////////////////////////////////////////////////////////////////// + + + /** + * This initializer is used to set thread constants. All functional + * initialization occurs within thread_init(). + */ + static this() + { + version( Win32 ) + { + PRIORITY_MIN = -15; + PRIORITY_MAX = 15; + } + else version( Posix ) + { + int policy; + sched_param param; + pthread_t self = pthread_self(); + + int status = pthread_getschedparam( self, &policy, ¶m ); + assert( status == 0 ); + + PRIORITY_MIN = sched_get_priority_min( policy ); + assert( PRIORITY_MIN != -1 ); + + PRIORITY_MAX = sched_get_priority_max( policy ); + assert( PRIORITY_MAX != -1 ); + } + } + + +private: + // + // Initializes a thread object which has no associated executable function. + // This is used for the main thread initialized in thread_init(). + // + this() + { + m_call = Call.NO; + m_curr = &m_main; + } + + + // + // Thread entry point. Invokes the function or delegate passed on + // construction (if any). + // + final void run() + { + switch( m_call ) + { + case Call.FN: + m_fn(); + break; + case Call.DG: + m_dg(); + break; + default: + break; + } + } + + +private: + // + // The type of routine passed on thread construction. + // + enum Call + { + NO, + FN, + DG + } + + + // + // Standard types + // + version( Win32 ) + { + alias uint TLSKey; + alias uint ThreadAddr; + } + else version( Posix ) + { + alias pthread_key_t TLSKey; + alias pthread_t ThreadAddr; + } + + + // + // Local storage + // + static bool[LOCAL_MAX] sm_local; + static TLSKey sm_this; + + void*[LOCAL_MAX] m_local; + + + // + // Standard thread data + // + version( Win32 ) + { + HANDLE m_hndl; + } + ThreadAddr m_addr; + Call m_call; + char[] m_name; + union + { + void function() m_fn; + void delegate() m_dg; + } + size_t m_sz; + version( Posix ) + { + bool m_isRunning; + } + bool m_isDaemon; + Object m_unhandled; + + +private: + /////////////////////////////////////////////////////////////////////////// + // Storage of Active Thread + /////////////////////////////////////////////////////////////////////////// + + + // + // Sets a thread-local reference to the current thread object. + // + static void setThis( Thread t ) + { + version( Win32 ) + { + TlsSetValue( sm_this, cast(void*) t ); + } + else version( Posix ) + { + pthread_setspecific( sm_this, cast(void*) t ); + } + } + + +private: + /////////////////////////////////////////////////////////////////////////// + // Thread Context and GC Scanning Support + /////////////////////////////////////////////////////////////////////////// + + + final void pushContext( Context* c ) + in + { + assert( !c.within ); + } + body + { + c.within = m_curr; + m_curr = c; + } + + + final void popContext() + in + { + assert( m_curr && m_curr.within ); + } + body + { + Context* c = m_curr; + m_curr = c.within; + c.within = null; + } + + + final Context* topContext() + in + { + assert( m_curr ); + } + body + { + return m_curr; + } + + + static struct Context + { + void* bstack, + tstack; + Context* within; + Context* next, + prev; + } + + + Context m_main; + Context* m_curr; + bool m_lock; + + version( Win32 ) + { + uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax + } + + +private: + /////////////////////////////////////////////////////////////////////////// + // GC Scanning Support + /////////////////////////////////////////////////////////////////////////// + + + // NOTE: The GC scanning process works like so: + // + // 1. Suspend all threads. + // 2. Scan the stacks of all suspended threads for roots. + // 3. Resume all threads. + // + // Step 1 and 3 require a list of all threads in the system, while + // step 2 requires a list of all thread stacks (each represented by + // a Context struct). Traditionally, there was one stack per thread + // and the Context structs were not necessary. However, Fibers have + // changed things so that each thread has its own 'main' stack plus + // an arbitrary number of nested stacks (normally referenced via + // m_curr). Also, there may be 'free-floating' stacks in the system, + // which are Fibers that are not currently executing on any specific + // thread but are still being processed and still contain valid + // roots. + // + // To support all of this, the Context struct has been created to + // represent a stack range, and a global list of Context structs has + // been added to enable scanning of these stack ranges. The lifetime + // (and presence in the Context list) of a thread's 'main' stack will + // be equivalent to the thread's lifetime. So the Ccontext will be + // added to the list on thread entry, and removed from the list on + // thread exit (which is essentially the same as the presence of a + // Thread object in its own global list). The lifetime of a Fiber's + // context, however, will be tied to the lifetime of the Fiber object + // itself, and Fibers are expected to add/remove their Context struct + // on construction/deletion. + + + // + // All use of the global lists should synchronize on this lock. + // + static Object slock() + { + return Thread.classinfo; + } + + + static Context* sm_cbeg; + static size_t sm_clen; + + static Thread sm_tbeg; + static size_t sm_tlen; + + // + // Used for ordering threads in the global thread list. + // + Thread prev; + Thread next; + + + /////////////////////////////////////////////////////////////////////////// + // Global Context List Operations + /////////////////////////////////////////////////////////////////////////// + + + // + // Add a context to the global context list. + // + static void add( Context* c ) + in + { + assert( c ); + assert( !c.next && !c.prev ); + } + body + { + synchronized( slock ) + { + if( sm_cbeg ) + { + c.next = sm_cbeg; + sm_cbeg.prev = c; + } + sm_cbeg = c; + ++sm_clen; + } + } + + + // + // Remove a context from the global context list. + // + static void remove( Context* c ) + in + { + assert( c ); + assert( c.next || c.prev ); + } + body + { + synchronized( slock ) + { + if( c.prev ) + c.prev.next = c.next; + if( c.next ) + c.next.prev = c.prev; + if( sm_cbeg == c ) + sm_cbeg = c.next; + --sm_clen; + } + // NOTE: Don't null out c.next or c.prev because opApply currently + // follows c.next after removing a node. This could be easily + // addressed by simply returning the next node from this + // function, however, a context should never be re-added to the + // list anyway and having next and prev be non-null is a good way + // to ensure that. + } + + + /////////////////////////////////////////////////////////////////////////// + // Global Thread List Operations + /////////////////////////////////////////////////////////////////////////// + + + // + // Add a thread to the global thread list. + // + static void add( Thread t ) + in + { + assert( t ); + assert( !t.next && !t.prev ); + assert( t.isRunning ); + } + body + { + synchronized( slock ) + { + if( sm_tbeg ) + { + t.next = sm_tbeg; + sm_tbeg.prev = t; + } + sm_tbeg = t; + ++sm_tlen; + } + } + + + // + // Remove a thread from the global thread list. + // + static void remove( Thread t ) + in + { + assert( t ); + assert( t.next || t.prev ); + version( Win32 ) + { + // NOTE: This doesn't work for Posix as m_isRunning must be set to + // false after the thread is removed during normal execution. + assert( !t.isRunning ); + } + } + body + { + synchronized( slock ) + { + // NOTE: When a thread is removed from the global thread list its + // main context is invalid and should be removed as well. + // It is possible that t.m_curr could reference more + // than just the main context if the thread exited abnormally + // (if it was terminated), but we must assume that the user + // retains a reference to them and that they may be re-used + // elsewhere. Therefore, it is the responsibility of any + // object that creates contexts to clean them up properly + // when it is done with them. + remove( &t.m_main ); + + if( t.prev ) + t.prev.next = t.next; + if( t.next ) + t.next.prev = t.prev; + if( sm_tbeg == t ) + sm_tbeg = t.next; + --sm_tlen; + } + // NOTE: Don't null out t.next or t.prev because opApply currently + // follows t.next after removing a node. This could be easily + // addressed by simply returning the next node from this + // function, however, a thread should never be re-added to the + // list anyway and having next and prev be non-null is a good way + // to ensure that. + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// GC Support Routines +/////////////////////////////////////////////////////////////////////////////// + + +/** + * Initializes the thread module. This function must be called by the + * garbage collector on startup and before any other thread routines + * are called. + */ +extern (C) void thread_init() +{ + // NOTE: If thread_init itself performs any allocations then the thread + // routines reserved for garbage collector use may be called while + // thread_init is being processed. However, since no memory should + // exist to be scanned at this point, it is sufficient for these + // functions to detect the condition and return immediately. + + version( Win32 ) + { + Thread.sm_this = TlsAlloc(); + assert( Thread.sm_this != TLS_OUT_OF_INDEXES ); + } + else version( Posix ) + { + int status; + sigaction_t sigusr1 = void; + sigaction_t sigusr2 = void; + + // This is a quick way to zero-initialize the structs without using + // memset or creating a link dependency on their static initializer. + (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0; + (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0; + + // NOTE: SA_RESTART indicates that system calls should restart if they + // are interrupted by a signal, but this is not available on all + // Posix systems, even those that support multithreading. + static if( is( typeof( SA_RESTART ) ) ) + sigusr1.sa_flags = SA_RESTART; + else + sigusr1.sa_flags = 0; + sigusr1.sa_handler = &thread_suspendHandler; + // NOTE: We want to ignore all signals while in this handler, so fill + // sa_mask to indicate this. + status = sigfillset( &sigusr1.sa_mask ); + assert( status == 0 ); + + // NOTE: Since SIGUSR2 should only be issued for threads within the + // suspend handler, we don't want this signal to trigger a + // restart. + sigusr2.sa_flags = 0; + sigusr2.sa_handler = &thread_resumeHandler; + // NOTE: We want to ignore all signals while in this handler, so fill + // sa_mask to indicate this. + status = sigfillset( &sigusr2.sa_mask ); + assert( status == 0 ); + + status = sigaction( SIGUSR1, &sigusr1, null ); + assert( status == 0 ); + + status = sigaction( SIGUSR2, &sigusr2, null ); + assert( status == 0 ); + + status = sem_init( &suspendCount, 0, 0 ); + assert( status == 0 ); + + status = pthread_key_create( &Thread.sm_this, null ); + assert( status == 0 ); + } + + thread_attachThis(); +} + + +/** + * Registers the calling thread for use with the D Runtime. If this routine + * is called for a thread which is already registered, the result is undefined. + */ +extern (C) void thread_attachThis() +{ + version( Win32 ) + { + Thread thisThread = new Thread(); + Thread.Context* thisContext = &thisThread.m_main; + assert( thisContext == thisThread.m_curr ); + + thisThread.m_addr = GetCurrentThreadId(); + thisThread.m_hndl = GetCurrentThreadHandle(); + thisContext.bstack = getStackBottom(); + thisContext.tstack = thisContext.bstack; + + thisThread.m_isDaemon = true; + + Thread.setThis( thisThread ); + } + else version( Posix ) + { + Thread thisThread = new Thread(); + Thread.Context* thisContext = thisThread.m_curr; + assert( thisContext == &thisThread.m_main ); + + thisThread.m_addr = pthread_self(); + thisContext.bstack = getStackBottom(); + thisContext.tstack = thisContext.bstack; + + thisThread.m_isRunning = true; + thisThread.m_isDaemon = true; + + Thread.setThis( thisThread ); + } + + Thread.add( thisThread ); + Thread.add( thisContext ); +} + + +/** + * Deregisters the calling thread from use with the runtime. If this routine + * is called for a thread which is already registered, the result is undefined. + */ +extern (C) void thread_detachThis() +{ + Thread.remove( Thread.getThis() ); +} + + +/** + * Joins all non-daemon threads that are currently running. This is done by + * performing successive scans through the thread list until a scan consists + * of only daemon threads. + */ +extern (C) void thread_joinAll() +{ + + while( true ) + { + Thread nonDaemon = null; + + foreach( t; Thread ) + { + if( !t.isDaemon ) + { + nonDaemon = t; + break; + } + } + if( nonDaemon is null ) + return; + nonDaemon.join(); + } +} + + +/** + * Performs intermediate shutdown of the thread module. + */ +static ~this() +{ + // NOTE: The functionality related to garbage collection must be minimally + // operable after this dtor completes. Therefore, only minimal + // cleanup may occur. + + for( Thread t = Thread.sm_tbeg; t; t = t.next ) + { + if( !t.isRunning ) + Thread.remove( t ); + } +} + + +// Used for needLock below +private bool multiThreadedFlag = false; + + +/** + * This function is used to determine whether the the process is + * multi-threaded. Optimizations may only be performed on this + * value if the programmer can guarantee that no path from the + * enclosed code will start a thread. + * + * Returns: + * True if Thread.start() has been called in this process. + */ +extern (C) bool thread_needLock() +{ + return multiThreadedFlag; +} + + +// Used for suspendAll/resumeAll below +private uint suspendDepth = 0; + + +/** + * Suspend all threads but the calling thread for "stop the world" garbage + * collection runs. This function may be called multiple times, and must + * be followed by a matching number of calls to thread_resumeAll before + * processing is resumed. + * + * Throws: + * ThreadException if the suspend operation fails for a running thread. + */ +extern (C) void thread_suspendAll() +{ + /** + * Suspend the specified thread and load stack and register information for + * use by thread_scanAll. If the supplied thread is the calling thread, + * stack and register information will be loaded but the thread will not + * be suspended. If the suspend operation fails and the thread is not + * running then it will be removed from the global thread list, otherwise + * an exception will be thrown. + * + * Params: + * t = The thread to suspend. + * + * Throws: + * ThreadException if the suspend operation fails for a running thread. + */ + void suspend( Thread t ) + { + version( Win32 ) + { + if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF ) + { + if( !t.isRunning ) + { + Thread.remove( t ); + return; + } + throw new ThreadException( "Unable to suspend thread" ); + } + + CONTEXT context = void; + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + + if( !GetThreadContext( t.m_hndl, &context ) ) + throw new ThreadException( "Unable to load thread context" ); + if( !t.m_lock ) + t.m_curr.tstack = cast(void*) context.Esp; + // edi,esi,ebp,esp,ebx,edx,ecx,eax + t.m_reg[0] = context.Edi; + t.m_reg[1] = context.Esi; + t.m_reg[2] = context.Ebp; + t.m_reg[3] = context.Esp; + t.m_reg[4] = context.Ebx; + t.m_reg[5] = context.Edx; + t.m_reg[6] = context.Ecx; + t.m_reg[7] = context.Eax; + } + else version( Posix ) + { + if( t.m_addr != pthread_self() ) + { + if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 ) + { + if( !t.isRunning ) + { + Thread.remove( t ); + return; + } + throw new ThreadException( "Unable to suspend thread" ); + } + // NOTE: It's really not ideal to wait for each thread to + // signal individually -- rather, it would be better to + // suspend them all and wait once at the end. However, + // semaphores don't really work this way, and the obvious + // alternative (looping on an atomic suspend count) + // requires either the atomic module (which only works on + // x86) or other specialized functionality. It would + // also be possible to simply loop on sem_wait at the + // end, but I'm not convinced that this would be much + // faster than the current approach. + sem_wait( &suspendCount ); + } + else if( !t.m_lock ) + { + t.m_curr.tstack = getStackTop(); + } + } + } + + + // NOTE: We've got an odd chicken & egg problem here, because while the GC + // is required to call thread_init before calling any other thread + // routines, thread_init may allocate memory which could in turn + // trigger a collection. Thus, thread_suspendAll, thread_scanAll, + // and thread_resumeAll must be callable before thread_init + // completes, with the assumption that no other GC memory has yet + // been allocated by the system, and thus there is no risk of losing + // data if the global thread list is empty. The check of + // Thread.sm_tbeg below is done to ensure thread_init has completed, + // and therefore that calling Thread.getThis will not result in an + // error. For the short time when Thread.sm_tbeg is null, there is + // no reason not to simply call the multithreaded code below, with + // the expectation that the foreach loop will never be entered. + if( !multiThreadedFlag && Thread.sm_tbeg ) + { + if( ++suspendDepth == 1 ) + suspend( Thread.getThis() ); + return; + } + synchronized( Thread.slock ) + { + if( ++suspendDepth > 1 ) + return; + + // NOTE: I'd really prefer not to check isRunning within this loop but + // not doing so could be problematic if threads are termianted + // abnormally and a new thread is created with the same thread + // address before the next GC run. This situation might cause + // the same thread to be suspended twice, which would likely + // cause the second suspend to fail, the garbage collection to + // abort, and Bad Things to occur. + for( Thread t = Thread.sm_tbeg; t; t = t.next ) + { + if( t.isRunning ) + suspend( t ); + else + Thread.remove( t ); + } + + version( Posix ) + { + // wait on semaphore -- see note in suspend for + // why this is currently not implemented + } + } +} + + +/** + * Resume all threads but the calling thread for "stop the world" garbage + * collection runs. This function must be called once for each preceding + * call to thread_suspendAll before the threads are actually resumed. + * + * In: + * This routine must be preceded by a call to thread_suspendAll. + * + * Throws: + * ThreadException if the resume operation fails for a running thread. + */ +extern (C) void thread_resumeAll() +in +{ + assert( suspendDepth > 0 ); +} +body +{ + /** + * Resume the specified thread and unload stack and register information. + * If the supplied thread is the calling thread, stack and register + * information will be unloaded but the thread will not be resumed. If + * the resume operation fails and the thread is not running then it will + * be removed from the global thread list, otherwise an exception will be + * thrown. + * + * Params: + * t = The thread to resume. + * + * Throws: + * ThreadException if the resume fails for a running thread. + */ + void resume( Thread t ) + { + version( Win32 ) + { + if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF ) + { + if( !t.isRunning ) + { + Thread.remove( t ); + return; + } + throw new ThreadException( "Unable to resume thread" ); + } + + if( !t.m_lock ) + t.m_curr.tstack = t.m_curr.bstack; + t.m_reg[0 .. $] = 0; + } + else version( Posix ) + { + if( t.m_addr != pthread_self() ) + { + if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 ) + { + if( !t.isRunning ) + { + Thread.remove( t ); + return; + } + throw new ThreadException( "Unable to resume thread" ); + } + } + else if( !t.m_lock ) + { + t.m_curr.tstack = t.m_curr.bstack; + } + } + } + + + // NOTE: See thread_suspendAll for the logic behind this. + if( !multiThreadedFlag && Thread.sm_tbeg ) + { + if( --suspendDepth == 0 ) + resume( Thread.getThis() ); + return; + } + synchronized( Thread.slock ) + { + if( --suspendDepth > 0 ) + return; + + for( Thread t = Thread.sm_tbeg; t; t = t.next ) + { + resume( t ); + } + } +} + + +private alias void delegate( void*, void* ) scanAllThreadsFn; + + +/** + * The main entry point for garbage collection. The supplied delegate + * will be passed ranges representing both stack and register values. + * + * Params: + * scan = The scanner function. It should scan from p1 through p2 - 1. + * curStackTop = An optional pointer to the top of the calling thread's stack. + * + * In: + * This routine must be preceded by a call to thread_suspendAll. + */ +extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null ) +in +{ + assert( suspendDepth > 0 ); +} +body +{ + Thread thisThread = null; + void* oldStackTop = null; + + if( curStackTop && Thread.sm_tbeg ) + { + thisThread = Thread.getThis(); + if( !thisThread.m_lock ) + { + oldStackTop = thisThread.m_curr.tstack; + thisThread.m_curr.tstack = curStackTop; + } + } + + scope( exit ) + { + if( curStackTop && Thread.sm_tbeg ) + { + if( !thisThread.m_lock ) + { + thisThread.m_curr.tstack = oldStackTop; + } + } + } + + // NOTE: Synchronizing on Thread.slock is not needed because this + // function may only be called after all other threads have + // been suspended from within the same lock. + for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next ) + { + version( StackGrowsDown ) + { + // NOTE: We can't index past the bottom of the stack + // so don't do the "+1" for StackGrowsDown. + if( c.tstack && c.tstack < c.bstack ) + scan( c.tstack, c.bstack ); + } + else + { + if( c.bstack && c.bstack < c.tstack ) + scan( c.bstack, c.tstack + 1 ); + } + } + version( Win32 ) + { + for( Thread t = Thread.sm_tbeg; t; t = t.next ) + { + scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length ); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Thread Local +/////////////////////////////////////////////////////////////////////////////// + + +/** + * This class encapsulates the operations required to initialize, access, and + * destroy thread local data. + */ +class ThreadLocal( T ) +{ + /////////////////////////////////////////////////////////////////////////// + // Initialization + /////////////////////////////////////////////////////////////////////////// + + + /** + * Initializes thread local storage for the indicated value which will be + * initialized to def for all threads. + * + * Params: + * def = The default value to return if no value has been explicitly set. + */ + this( T def = T.init ) + { + m_def = def; + m_key = Thread.createLocal(); + } + + + ~this() + { + Thread.deleteLocal( m_key ); + } + + + /////////////////////////////////////////////////////////////////////////// + // Accessors + /////////////////////////////////////////////////////////////////////////// + + + /** + * Gets the value last set by the calling thread, or def if no such value + * has been set. + * + * Returns: + * The stored value or def if no value is stored. + */ + T val() + { + Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key ); + + return wrap ? wrap.val : m_def; + } + + + /** + * Copies newval to a location specific to the calling thread, and returns + * newval. + * + * Params: + * newval = The value to set. + * + * Returns: + * The value passed to this function. + */ + T val( T newval ) + { + Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key ); + + if( wrap is null ) + { + wrap = new Wrap; + Thread.setLocal( m_key, wrap ); + } + wrap.val = newval; + return newval; + } + + +private: + // + // A wrapper for the stored data. This is needed for determining whether + // set has ever been called for this thread (and therefore whether the + // default value should be returned) and also to flatten the differences + // between data that is smaller and larger than (void*).sizeof. The + // obvious tradeoff here is an extra per-thread allocation for each + // ThreadLocal value as compared to calling the Thread routines directly. + // + struct Wrap + { + T val; + } + + + T m_def; + uint m_key; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Thread Group +/////////////////////////////////////////////////////////////////////////////// + + +/** + * This class is intended to simplify certain common programming techniques. + */ +class ThreadGroup +{ + /** + * Creates and starts a new Thread object that executes fn and adds it to + * the list of tracked threads. + * + * Params: + * fn = The thread function. + * + * Returns: + * A reference to the newly created thread. + */ + final Thread create( void function() fn ) + { + Thread t = new Thread( fn ); + + t.start(); + synchronized( this ) + { + m_all[t] = t; + } + return t; + } + + + /** + * Creates and starts a new Thread object that executes dg and adds it to + * the list of tracked threads. + * + * Params: + * dg = The thread function. + * + * Returns: + * A reference to the newly created thread. + */ + final Thread create( void delegate() dg ) + { + Thread t = new Thread( dg ); + + t.start(); + synchronized( this ) + { + m_all[t] = t; + } + return t; + } + + + /** + * Add t to the list of tracked threads if it is not already being tracked. + * + * Params: + * t = The thread to add. + * + * In: + * t must not be null. + */ + final void add( Thread t ) + in + { + assert( t ); + } + body + { + synchronized( this ) + { + m_all[t] = t; + } + } + + + /** + * Removes t from the list of tracked threads. No operation will be + * performed if t is not currently being tracked by this object. + * + * Params: + * t = The thread to remove. + * + * In: + * t must not be null. + */ + final void remove( Thread t ) + in + { + assert( t ); + } + body + { + synchronized( this ) + { + m_all.remove( t ); + } + } + + + /** + * Operates on all threads currently tracked by this object. + */ + final int opApply( int delegate( inout Thread ) dg ) + { + synchronized( this ) + { + int ret = 0; + + // NOTE: This loop relies on the knowledge that m_all uses the + // Thread object for both the key and the mapped value. + foreach( Thread t; m_all.keys ) + { + ret = dg( t ); + if( ret ) + break; + } + return ret; + } + } + + + /** + * Iteratively joins all tracked threads. This function will block add, + * remove, and opApply until it completes. + * + * Params: + * rethrow = Rethrow any unhandled exception which may have caused the + * current thread to terminate. + * + * Throws: + * Any exception not handled by the joined threads. + */ + final void joinAll( bool rethrow = true ) + { + synchronized( this ) + { + // NOTE: This loop relies on the knowledge that m_all uses the + // Thread object for both the key and the mapped value. + foreach( Thread t; m_all.keys ) + { + t.join( rethrow ); + } + } + } + + +private: + Thread[Thread] m_all; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Fiber Platform Detection and Memory Allocation +/////////////////////////////////////////////////////////////////////////////// + + +private +{ + version( D_InlineAsm_X86 ) + { + version( X86_64 ) + { + + } + else + { + version( Win32 ) + version = AsmX86_Win32; + else version( Posix ) + version = AsmX86_Posix; + } + } + else version( PPC ) + { + version( Posix ) + version = AsmPPC_Posix; + } + + + version( Posix ) + { + import stdc.posix.unistd; // for sysconf + import stdc.posix.sys.mman; // for mmap + import stdc.posix.stdlib; // for malloc, valloc, free + + version( AsmX86_Win32 ) {} else + version( AsmX86_Posix ) {} else + version( AsmPPC_Posix ) {} else + { + // NOTE: The ucontext implementation requires architecture specific + // data definitions to operate so testing for it must be done + // by checking for the existence of ucontext_t rather than by + // a version identifier. Please note that this is considered + // an obsolescent feature according to the POSIX spec, so a + // custom solution is still preferred. + import stdc.posix.ucontext; + } + } + + const size_t PAGESIZE; +} + + +static this() +{ + static if( is( typeof( GetSystemInfo ) ) ) + { + SYSTEM_INFO info; + GetSystemInfo( &info ); + + PAGESIZE = info.dwPageSize; + assert( PAGESIZE < int.max ); + } + else static if( is( typeof( sysconf ) ) && + is( typeof( _SC_PAGESIZE ) ) ) + { + PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE ); + assert( PAGESIZE < int.max ); + } + else + { + version( PPC ) + PAGESIZE = 8192; + else + PAGESIZE = 4096; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Fiber Entry Point and Context Switch +/////////////////////////////////////////////////////////////////////////////// + + +private +{ + extern (C) void fiber_entryPoint() + { + Fiber obj = Fiber.getThis(); + assert( obj ); + + assert( Thread.getThis().m_curr is obj.m_ctxt ); + volatile Thread.getThis().m_lock = false; + obj.m_ctxt.tstack = obj.m_ctxt.bstack; + obj.m_state = Fiber.State.EXEC; + + try + { + obj.run(); + } + catch( Object o ) + { + obj.m_unhandled = o; + } + + static if( is( ucontext_t ) ) + obj.m_ucur = &obj.m_utxt; + + obj.m_state = Fiber.State.TERM; + obj.switchOut(); + } + + + // NOTE: If AsmPPC_Posix is defined then the context switch routine will + // be defined externally until GDC supports inline PPC ASM. + version( AsmPPC_Posix ) + extern (C) void fiber_switchContext( void** oldp, void* newp ); + else + extern (C) void fiber_switchContext( void** oldp, void* newp ) + { + // NOTE: The data pushed and popped in this routine must match the + // default stack created by Fiber.initStack or the initial + // switch into a new context will fail. + + version( AsmX86_Win32 ) + { + asm + { + naked; + + // save current stack state + push EBP; + mov EBP, ESP; + push EAX; + push dword ptr FS:[0]; + push dword ptr FS:[4]; + push dword ptr FS:[8]; + push EBX; + push ESI; + push EDI; + + // store oldp again with more accurate address + mov EAX, dword ptr 8[EBP]; + mov [EAX], ESP; + // load newp to begin context switch + mov ESP, dword ptr 12[EBP]; + + // load saved state from new stack + pop EDI; + pop ESI; + pop EBX; + pop dword ptr FS:[8]; + pop dword ptr FS:[4]; + pop dword ptr FS:[0]; + pop EAX; + pop EBP; + + // 'return' to complete switch + ret; + } + } + else version( AsmX86_Posix ) + { + asm + { + naked; + + // save current stack state + push EBP; + mov EBP, ESP; + push EAX; + push EBX; + push ESI; + push EDI; + + // store oldp again with more accurate address + mov EAX, dword ptr 8[EBP]; + mov [EAX], ESP; + // load newp to begin context switch + mov ESP, dword ptr 12[EBP]; + + // load saved state from new stack + pop EDI; + pop ESI; + pop EBX; + pop EAX; + pop EBP; + + // 'return' to complete switch + ret; + } + } + else static if( is( ucontext_t ) ) + { + Fiber cfib = Fiber.getThis(); + void* ucur = cfib.m_ucur; + + *oldp = &ucur; + swapcontext( **(cast(ucontext_t***) oldp), + *(cast(ucontext_t**) newp) ); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Fiber +/////////////////////////////////////////////////////////////////////////////// + + +/** + * This class provides a cooperative concurrency mechanism integrated with the + * threading and garbage collection functionality. Calling a fiber may be + * considered a blocking operation that returns when the fiber yields (via + * Fiber.yield()). Execution occurs within the context of the calling thread + * so synchronization is not necessary to guarantee memory visibility so long + * as the same thread calls the fiber each time. Please note that there is no + * requirement that a fiber be bound to one specific thread. Rather, fibers + * may be freely passed between threads so long as they are not currently + * executing. Like threads, a new fiber thread may be created using either + * derivation or composition, as in the following example. + * + * Example: + * ---------------------------------------------------------------------- + * + * class DerivedFiber : Fiber + * { + * this() + * { + * super( &run ); + * } + * + * private : + * void run() + * { + * printf( "Derived fiber running.\n" ); + * } + * } + * + * void fiberFunc() + * { + * printf( "Composed fiber running.\n" ); + * Fiber.yield(); + * printf( "Composed fiber running.\n" ); + * } + * + * // create instances of each type + * Fiber derived = new DerivedFiber(); + * Fiber composed = new Fiber( &fiberFunc ); + * + * // call both fibers once + * derived.call(); + * composed.call(); + * printf( "Execution returned to calling context.\n" ); + * composed.call(); + * + * // since each fiber has run to completion, each should have state TERM + * assert( derived.state == Fiber.State.TERM ); + * assert( composed.state == Fiber.State.TERM ); + * + * ---------------------------------------------------------------------- + * + * Authors: Based on a design by Mikola Lysenko. + */ +class Fiber +{ + /////////////////////////////////////////////////////////////////////////// + // Initialization + /////////////////////////////////////////////////////////////////////////// + + + /** + * Initializes a fiber object which is associated with a static + * D function. + * + * Params: + * fn = The thread function. + * sz = The stack size for this fiber. + * + * In: + * fn must not be null. + */ + this( void function() fn, size_t sz = PAGESIZE ) + in + { + assert( fn ); + } + body + { + m_fn = fn; + m_call = Call.FN; + m_state = State.HOLD; + allocStack( sz ); + initStack(); + } + + + /** + * Initializes a fiber object which is associated with a dynamic + * D function. + * + * Params: + * dg = The thread function. + * sz = The stack size for this fiber. + * + * In: + * dg must not be null. + */ + this( void delegate() dg, size_t sz = PAGESIZE ) + in + { + assert( dg ); + } + body + { + m_dg = dg; + m_call = Call.DG; + m_state = State.HOLD; + allocStack( sz ); + initStack(); + } + + + /** + * Cleans up any remaining resources used by this object. + */ + ~this() + { + // NOTE: A live reference to this object will exist on its associated + // stack from the first time its call() method has been called + // until its execution completes with State.TERM. Thus, the only + // times this dtor should be called are either if the fiber has + // terminated (and therefore has no active stack) or if the user + // explicitly deletes this object. The latter case is an error + // but is not easily tested for, since State.HOLD may imply that + // the fiber was just created but has never been run. There is + // not a compelling case to create a State.INIT just to offer a + // means of ensuring the user isn't violating this object's + // contract, so for now this requirement will be enforced by + // documentation only. + freeStack(); + } + + + /////////////////////////////////////////////////////////////////////////// + // General Actions + /////////////////////////////////////////////////////////////////////////// + + + /** + * Transfers execution to this fiber object. The calling context will be + * suspended until the fiber calls Fiber.yield() or until it terminates + * via an unhandled exception. + * + * Params: + * rethrow = Rethrow any unhandled exception which may have caused this + * fiber to terminate. + * + * In: + * This fiber must be in state HOLD. + * + * Throws: + * Any exception not handled by the joined thread. + * + * Returns: + * Any exception not handled by this fiber if rethrow = false, null + * otherwise. + */ + final Object call( bool rethrow = true ) + in + { + assert( m_state == State.HOLD ); + } + body + { + Fiber cur = getThis(); + + static if( is( ucontext_t ) ) + m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt; + + setThis( this ); + this.switchIn(); + setThis( cur ); + + static if( is( ucontext_t ) ) + m_ucur = null; + + // NOTE: If the fiber has terminated then the stack pointers must be + // reset. This ensures that the stack for this fiber is not + // scanned if the fiber has terminated. This is necessary to + // prevent any references lingering on the stack from delaying + // the collection of otherwise dead objects. The most notable + // being the current object, which is referenced at the top of + // fiber_entryPoint. + if( m_state == State.TERM ) + { + m_ctxt.tstack = m_ctxt.bstack; + } + if( m_unhandled ) + { + Object obj = m_unhandled; + m_unhandled = null; + if( rethrow ) + throw obj; + return obj; + } + return null; + } + + + /** + * Resets this fiber so that it may be re-used. This routine may only be + * called for fibers that have terminated, as doing otherwise could result + * in scope-dependent functionality that is not executed. Stack-based + * classes, for example, may not be cleaned up properly if a fiber is reset + * before it has terminated. + * + * In: + * This fiber must be in state TERM. + */ + final void reset() + in + { + assert( m_state == State.TERM ); + assert( m_ctxt.tstack == m_ctxt.bstack ); + } + body + { + m_state = State.HOLD; + initStack(); + m_unhandled = null; + } + + + /////////////////////////////////////////////////////////////////////////// + // General Properties + /////////////////////////////////////////////////////////////////////////// + + + /** + * A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD + * state applies to any fiber that is suspended and ready to be called. + * The EXEC state will be set for any fiber that is currently executing. + * And the TERM state is set when a fiber terminates. Once a fiber + * terminates, it must be reset before it may be called again. + */ + enum State + { + HOLD, /// + EXEC, /// + TERM /// + } + + + /** + * Gets the current state of this fiber. + * + * Returns: + * The state of this fiber as an enumerated value. + */ + final State state() + { + return m_state; + } + + + /////////////////////////////////////////////////////////////////////////// + // Actions on Calling Fiber + /////////////////////////////////////////////////////////////////////////// + + + /** + * Forces a context switch to occur away from the calling fiber. + */ + static void yield() + { + Fiber cur = getThis(); + assert( cur, "Fiber.yield() called with no active fiber" ); + assert( cur.m_state == State.EXEC ); + + static if( is( ucontext_t ) ) + cur.m_ucur = &cur.m_utxt; + + cur.m_state = State.HOLD; + cur.switchOut(); + cur.m_state = State.EXEC; + } + + + /** + * Forces a context switch to occur away from the calling fiber and then + * throws obj in the calling fiber. + * + * Params: + * obj = The object to throw. + * + * In: + * obj must not be null. + */ + static void yieldAndThrow( Object obj ) + in + { + assert( obj ); + } + body + { + Fiber cur = getThis(); + assert( cur, "Fiber.yield() called with no active fiber" ); + assert( cur.m_state == State.EXEC ); + + static if( is( ucontext_t ) ) + cur.m_ucur = &cur.m_utxt; + + cur.m_unhandled = obj; + cur.m_state = State.HOLD; + cur.switchOut(); + cur.m_state = State.EXEC; + } + + + /////////////////////////////////////////////////////////////////////////// + // Fiber Accessors + /////////////////////////////////////////////////////////////////////////// + + + /** + * Provides a reference to the calling fiber or null if no fiber is + * currently active. + * + * Returns: + * The fiber object representing the calling fiber or null if no fiber + * is currently active. The result of deleting this object is undefined. + */ + static Fiber getThis() + { + version( Win32 ) + { + return cast(Fiber) TlsGetValue( sm_this ); + } + else version( Posix ) + { + return cast(Fiber) pthread_getspecific( sm_this ); + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Static Initialization + /////////////////////////////////////////////////////////////////////////// + + + static this() + { + version( Win32 ) + { + sm_this = TlsAlloc(); + assert( sm_this != TLS_OUT_OF_INDEXES ); + } + else version( Posix ) + { + int status; + + status = pthread_key_create( &sm_this, null ); + assert( status == 0 ); + + static if( is( ucontext_t ) ) + { + status = getcontext( &sm_utxt ); + assert( status == 0 ); + } + } + } + + +private: + // + // Initializes a fiber object which has no associated executable function. + // + this() + { + m_call = Call.NO; + } + + + // + // Fiber entry point. Invokes the function or delegate passed on + // construction (if any). + // + final void run() + { + switch( m_call ) + { + case Call.FN: + m_fn(); + break; + case Call.DG: + m_dg(); + break; + default: + break; + } + } + + +private: + // + // The type of routine passed on fiber construction. + // + enum Call + { + NO, + FN, + DG + } + + + // + // Standard fiber data + // + Call m_call; + union + { + void function() m_fn; + void delegate() m_dg; + } + bool m_isRunning; + Object m_unhandled; + State m_state; + + +private: + /////////////////////////////////////////////////////////////////////////// + // Stack Management + /////////////////////////////////////////////////////////////////////////// + + + // + // Allocate a new stack for this fiber. + // + final void allocStack( size_t sz ) + in + { + assert( !m_pmem && !m_ctxt ); + } + body + { + // adjust alloc size to a multiple of PAGESIZE + sz += PAGESIZE - 1; + sz -= sz % PAGESIZE; + + // NOTE: This instance of Thread.Context is dynamic so Fiber objects + // can be collected by the GC so long as no user level references + // to the object exist. If m_ctxt were not dynamic then its + // presence in the global context list would be enough to keep + // this object alive indefinitely. An alternative to allocating + // room for this struct explicitly would be to mash it into the + // base of the stack being allocated below. However, doing so + // requires too much special logic to be worthwhile. + m_ctxt = new Thread.Context; + + static if( is( typeof( VirtualAlloc ) ) ) + { + // reserve memory for stack + m_pmem = VirtualAlloc( null, + sz + PAGESIZE, + MEM_RESERVE, + PAGE_NOACCESS ); + if( !m_pmem ) + { + throw new FiberException( "Unable to reserve memory for stack" ); + } + + version( StackGrowsDown ) + { + void* stack = m_pmem + PAGESIZE; + void* guard = m_pmem; + void* pbase = stack + sz; + } + else + { + void* stack = m_pmem; + void* guard = m_pmem + sz; + void* pbase = stack; + } + + // allocate reserved stack segment + stack = VirtualAlloc( stack, + sz, + MEM_COMMIT, + PAGE_READWRITE ); + if( !stack ) + { + throw new FiberException( "Unable to allocate memory for stack" ); + } + + // allocate reserved guard page + guard = VirtualAlloc( guard, + PAGESIZE, + MEM_COMMIT, + PAGE_READWRITE | PAGE_GUARD ); + if( !guard ) + { + throw new FiberException( "Unable to create guard page for stack" ); + } + + m_ctxt.bstack = pbase; + m_ctxt.tstack = pbase; + m_size = sz; + } + else + { static if( is( typeof( mmap ) ) ) + { + m_pmem = mmap( null, + sz, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + -1, + 0 ); + if( m_pmem == MAP_FAILED ) + m_pmem = null; + } + else static if( is( typeof( valloc ) ) ) + { + m_pmem = valloc( sz ); + } + else static if( is( typeof( malloc ) ) ) + { + m_pmem = malloc( sz ); + } + else + { + m_pmem = null; + } + + if( !m_pmem ) + { + throw new FiberException( "Unable to allocate memory for stack" ); + } + + version( StackGrowsDown ) + { + m_ctxt.bstack = m_pmem + sz; + m_ctxt.tstack = m_pmem + sz; + } + else + { + m_ctxt.bstack = m_pmem; + m_ctxt.tstack = m_pmem; + } + m_size = sz; + } + + Thread.add( m_ctxt ); + } + + + // + // Free this fiber's stack. + // + final void freeStack() + in + { + assert( m_pmem && m_ctxt ); + } + body + { + // NOTE: Since this routine is only ever expected to be called from + // the dtor, pointers to freed data are not set to null. + + // NOTE: m_ctxt is guaranteed to be alive because it is held in the + // global context list. + Thread.remove( m_ctxt ); + + static if( is( typeof( VirtualAlloc ) ) ) + { + VirtualFree( m_pmem, 0, MEM_RELEASE ); + } + else static if( is( typeof( mmap ) ) ) + { + munmap( m_pmem, m_size ); + } + else static if( is( typeof( valloc ) ) ) + { + free( m_pmem ); + } + else static if( is( typeof( malloc ) ) ) + { + free( m_pmem ); + } + delete m_ctxt; + } + + + // + // Initialize the allocated stack. + // + final void initStack() + in + { + assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack ); + assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 ); + } + body + { + void* pstack = m_ctxt.tstack; + scope( exit ) m_ctxt.tstack = pstack; + + void push( size_t val ) + { + version( StackGrowsDown ) + { + pstack -= size_t.sizeof; + *(cast(size_t*) pstack) = val; + } + else + { + pstack += size_t.sizeof; + *(cast(size_t*) pstack) = val; + } + } + + // NOTE: On OS X the stack must be 16-byte aligned according to the + // IA-32 call spec. + version( darwin ) + { + pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F)); + } + + version( AsmX86_Win32 ) + { + push( cast(size_t) &fiber_entryPoint ); // EIP + push( 0xFFFFFFFF ); // EBP + push( 0x00000000 ); // EAX + push( 0xFFFFFFFF ); // FS:[0] + version( StackGrowsDown ) + { + push( cast(size_t) m_ctxt.bstack ); // FS:[4] + push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8] + } + else + { + push( cast(size_t) m_ctxt.bstack ); // FS:[4] + push( cast(size_t) m_ctxt.bstack + m_size ); // FS:[8] + } + push( 0x00000000 ); // EBX + push( 0x00000000 ); // ESI + push( 0x00000000 ); // EDI + } + else version( AsmX86_Posix ) + { + push( cast(size_t) &fiber_entryPoint ); // EIP + push( 0x00000000 ); // EBP + push( 0x00000000 ); // EAX + push( 0x00000000 ); // EBX + push( 0x00000000 ); // ESI + push( 0x00000000 ); // EDI + } + else version( AsmPPC_Posix ) + { + version( StackGrowsDown ) + { + pstack -= int.sizeof * 5; + } + else + { + pstack += int.sizeof * 5; + } + + push( cast(size_t) &fiber_entryPoint ); // link register + push( 0x00000000 ); // control register + push( 0x00000000 ); // old stack pointer + + // GPR values + version( StackGrowsDown ) + { + pstack -= int.sizeof * 20; + } + else + { + pstack += int.sizeof * 20; + } + + assert( cast(uint) pstack & 0x0f == 0 ); + } + else static if( is( ucontext_t ) ) + { + getcontext( &m_utxt ); + m_utxt.uc_stack.ss_sp = m_ctxt.bstack; + m_utxt.uc_stack.ss_size = m_size; + makecontext( &m_utxt, &fiber_entryPoint, 0 ); + // NOTE: If ucontext is being used then the top of the stack will + // be a pointer to the ucontext_t struct for that fiber. + push( cast(size_t) &m_utxt ); + } + } + + + Thread.Context* m_ctxt; + size_t m_size; + void* m_pmem; + + static if( is( ucontext_t ) ) + { + // NOTE: The static ucontext instance is used to represent the context + // of the main application thread. + static ucontext_t sm_utxt = void; + ucontext_t m_utxt = void; + ucontext_t* m_ucur = null; + } + + +private: + /////////////////////////////////////////////////////////////////////////// + // Storage of Active Fiber + /////////////////////////////////////////////////////////////////////////// + + + // + // Sets a thread-local reference to the current fiber object. + // + static void setThis( Fiber f ) + { + version( Win32 ) + { + TlsSetValue( sm_this, cast(void*) f ); + } + else version( Posix ) + { + pthread_setspecific( sm_this, cast(void*) f ); + } + } + + + static Thread.TLSKey sm_this; + + +private: + /////////////////////////////////////////////////////////////////////////// + // Context Switching + /////////////////////////////////////////////////////////////////////////// + + + // + // Switches into the stack held by this fiber. + // + final void switchIn() + { + Thread tobj = Thread.getThis(); + void** oldp = &tobj.m_curr.tstack; + void* newp = m_ctxt.tstack; + + // NOTE: The order of operations here is very important. The current + // stack top must be stored before m_lock is set, and pushContext + // must not be called until after m_lock is set. This process + // is intended to prevent a race condition with the suspend + // mechanism used for garbage collection. If it is not followed, + // a badly timed collection could cause the GC to scan from the + // bottom of one stack to the top of another, or to miss scanning + // a stack that still contains valid data. The old stack pointer + // oldp will be set again before the context switch to guarantee + // that it points to exactly the correct stack location so the + // successive pop operations will succeed. + *oldp = getStackTop(); + volatile tobj.m_lock = true; + tobj.pushContext( m_ctxt ); + + fiber_switchContext( oldp, newp ); + + // NOTE: As above, these operations must be performed in a strict order + // to prevent Bad Things from happening. + tobj.popContext(); + volatile tobj.m_lock = false; + tobj.m_curr.tstack = tobj.m_curr.bstack; + } + + + // + // Switches out of the current stack and into the enclosing stack. + // + final void switchOut() + { + Thread tobj = Thread.getThis(); + void** oldp = &m_ctxt.tstack; + void* newp = tobj.m_curr.within.tstack; + + // NOTE: The order of operations here is very important. The current + // stack top must be stored before m_lock is set, and pushContext + // must not be called until after m_lock is set. This process + // is intended to prevent a race condition with the suspend + // mechanism used for garbage collection. If it is not followed, + // a badly timed collection could cause the GC to scan from the + // bottom of one stack to the top of another, or to miss scanning + // a stack that still contains valid data. The old stack pointer + // oldp will be set again before the context switch to guarantee + // that it points to exactly the correct stack location so the + // successive pop operations will succeed. + *oldp = getStackTop(); + volatile tobj.m_lock = true; + + fiber_switchContext( oldp, newp ); + + // NOTE: As above, these operations must be performed in a strict order + // to prevent Bad Things from happening. + volatile tobj.m_lock = false; + tobj.m_curr.tstack = tobj.m_curr.bstack; + } +} diff --git a/src/core/win32.mak b/src/core/win32.mak new file mode 100644 index 0000000..32de084 --- /dev/null +++ b/src/core/win32.mak @@ -0,0 +1,125 @@ +# Makefile to build the D runtime library core components for Win32 +# Designed to work with DigitalMars make +# Targets: +# make +# Same as make all +# make lib +# Build the common library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=druntime-core.lib +LIB_MASK=druntime-core*.lib + +CP=xcopy /y +RM=del /f +MD=mkdir + +ADD_CFLAGS= +ADD_DFLAGS= + +CFLAGS=-mn -6 -r $(ADD_CFLAGS) +#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS) + +DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS) +#DFLAGS=-g -w -nofloat $(ADD_DFLAGS) + +TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS) +#TFLAGS=-g -w -nofloat $(ADD_DFLAGS) + +DOCFLAGS=-version=DDoc + +CC=dmc +LC=lib +DC=dmd + +INC_DEST=..\..\import +LIB_DEST=..\..\lib +DOC_DEST=..\..\doc + +.DEFAULT: .asm .c .cpp .d .html .obj + +.asm.obj: + $(CC) -c $< + +.c.obj: + $(CC) -c $(CFLAGS) $< -o$@ + +.cpp.obj: + $(CC) -c $(CFLAGS) $< -o$@ + +.d.obj: + $(DC) -c $(DFLAGS) -Hf$*.di $< -of$@ +# $(DC) -c $(DFLAGS) $< -of$@ + +.d.html: + $(DC) -c -o- $(DOCFLAGS) -Df$*.html $< + +targets : lib doc +all : lib doc +core : lib +lib : core.lib +doc : core.doc + +###################################################### + +OBJ_CORE= \ + bitmanip.obj \ + exception.obj \ + memory.obj \ + runtime.obj \ + thread.obj + +OBJ_STDC= \ + stdc.obj + +ALL_OBJS= \ + $(OBJ_CORE) \ + $(OBJ_STDC) + +###################################################### + +DOC_CORE= \ + bitmanip.html \ + exception.html \ + memory.html \ + runtime.html \ + thread.html + +ALL_DOCS= + +###################################################### + +core.lib : $(LIB_TARGET) + +$(LIB_TARGET) : $(ALL_OBJS) + $(RM) $@ + $(LC) -c -n $@ $(ALL_OBJS) + +core.doc : $(ALL_DOCS) + @echo Documentation generated. + +###################################################### + +### bitmanip + +bitmanip.obj : bitmanip.d + $(DC) -c $(DFLAGS) bitmanip.d -of$@ + +###################################################### + +clean : + $(RM) /s .\*.di + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + $(RM) $(LIB_MASK) + +install : + $(MD) $(INC_DEST) + $(CP) /s *.di $(INC_DEST)\. + $(MD) $(DOC_DEST) + $(CP) /s *.html $(DOC_DEST)\. + $(MD) $(LIB_DEST) + $(CP) $(LIB_MASK) $(LIB_DEST)\. diff --git a/src/dmd-posix.mak b/src/dmd-posix.mak new file mode 100644 index 0000000..da9cb9d --- /dev/null +++ b/src/dmd-posix.mak @@ -0,0 +1,75 @@ +# Makefile to build the composite D runtime library for Linux +# Designed to work with GNU make +# Targets: +# make +# Same as make all +# make lib +# Build the runtime library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=libdruntime-dmd.a +LIB_MASK=libdruntime-dmd*.a + +DIR_CC=../src/core +DIR_RT=../src/compiler/dmd +DIR_GC=../src/gc/basic + +CP=cp -f +RM=rm -f +MD=mkdir -p + +CC=gcc +LC=$(AR) -qsv +DC=dmd + +LIB_DEST=../lib + +ADD_CFLAGS=-m32 +ADD_DFLAGS= + +targets : lib doc +all : lib doc + +###################################################### + +ALL_OBJS= + +###################################################### + +ALL_DOCS= + +###################################################### + +lib : $(ALL_OBJS) + make -C $(DIR_CC) -fposix.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)" + make -C $(DIR_RT) -fposix.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)" + make -C $(DIR_GC) -fposix.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)" + find . -name "libphobos*.a" | xargs $(RM) + $(LC) $(LIB_TARGET) `find $(DIR_CC) -name "*.o" | xargs echo` + $(LC) $(LIB_TARGET) `find $(DIR_RT) -name "*.o" | xargs echo` + $(LC) $(LIB_TARGET) `find $(DIR_GC) -name "*.o" | xargs echo` + +doc : $(ALL_DOCS) + make -C $(DIR_CC) -fposix.mak doc DC=$(DC) + make -C $(DIR_RT) -fposix.mak doc DC=$(DC) + make -C $(DIR_GC) -fposix.mak doc DC=$(DC) + +###################################################### + +clean : + find . -name "*.di" | xargs $(RM) + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + make -C $(DIR_CC) -fposix.mak clean + make -C $(DIR_RT) -fposix.mak clean + make -C $(DIR_GC) -fposix.mak clean + $(RM) $(LIB_MASK) + +install : + make -C $(DIR_CC) -fposix.mak install + make -C $(DIR_RT) -fposix.mak install + make -C $(DIR_GC) -fposix.mak install + $(CP) $(LIB_MASK) $(LIB_DEST)/. diff --git a/src/dmd-win32.mak b/src/dmd-win32.mak new file mode 100644 index 0000000..3a637b8 --- /dev/null +++ b/src/dmd-win32.mak @@ -0,0 +1,101 @@ +# Makefile to build the composite D runtime library for Win32 +# Designed to work with DigitalMars make +# Targets: +# make +# Same as make all +# make lib +# Build the runtime library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=druntime-dmd.lib +LIB_MASK=druntime-dmd*.lib + +DIR_CC=core +DIR_RT=compiler\dmd +DIR_GC=gc\basic + +LIB_CC=$(DIR_CC)\druntime-core.lib +LIB_RT=$(DIR_RT)\druntime-rt-dmd.lib +LIB_GC=$(DIR_GC)\druntime-gc-basic.lib + +CP=xcopy /y +RM=del /f +MD=mkdir + +CC=dmc +LC=lib +DC=dmd + +LIB_DEST=..\lib + +ADD_CFLAGS= +ADD_DFLAGS= + +targets : lib doc +all : lib doc + +###################################################### + +ALL_OBJS= + +###################################################### + +ALL_DOCS= + +###################################################### + +lib : $(ALL_OBJS) + cd $(DIR_CC) + make -fwin32.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)" + cd .. + cd $(DIR_RT) + make -fwin32.mak lib + cd ..\.. + cd $(DIR_GC) + make -fwin32.mak lib DC=$(DC) ADD_DFLAGS="$(ADD_DFLAGS)" ADD_CFLAGS="$(ADD_CFLAGS)" + cd ..\.. + $(RM) $(LIB_TARGET) + $(LC) -c -n $(LIB_TARGET) $(LIB_CC) $(LIB_RT) $(LIB_GC) + +doc : $(ALL_DOCS) + cd $(DIR_CC) + make -fwin32.mak doc + cd .. + cd $(DIR_RT) + make -fwin32.mak doc + cd ..\.. + cd $(DIR_GC) + make -fwin32.mak doc + cd ..\.. + +###################################################### + +clean : + $(RM) /s *.di + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + cd $(DIR_CC) + make -fwin32.mak clean + cd .. + cd $(DIR_RT) + make -fwin32.mak clean + cd ..\.. + cd $(DIR_GC) + make -fwin32.mak clean + cd ..\.. + $(RM) $(LIB_MASK) + +install : + cd $(DIR_CC) + make -fwin32.mak install + cd .. + cd $(DIR_RT) + make -fwin32.mak install + cd ..\.. + cd $(DIR_GC) + make -fwin32.mak install + cd ..\.. + $(CP) $(LIB_MASK) $(LIB_DEST)\. diff --git a/src/dmd.conf b/src/dmd.conf new file mode 100644 index 0000000..198aed3 --- /dev/null +++ b/src/dmd.conf @@ -0,0 +1,2 @@ +[Environment] +DFLAGS=-version=Posix "-I%HOME%/../import" diff --git a/src/gc/basic/gc.d b/src/gc/basic/gc.d new file mode 100644 index 0000000..b078959 --- /dev/null +++ b/src/gc/basic/gc.d @@ -0,0 +1,186 @@ +/** + * This module contains the garbage collector front-end. + * + * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. + * All rights reserved. + * License: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + * Authors: Walter Bright, Sean Kelly + */ + +private import gcx; +private import gcstats; +private import stdc.stdlib; + +version=GCCLASS; + +version (GCCLASS) + alias GC gc_t; +else + alias GC* gc_t; + +gc_t _gc; + +extern (C) void thread_init(); + +extern (C) void gc_init() +{ + version (GCCLASS) + { void* p; + ClassInfo ci = GC.classinfo; + + p = malloc(ci.init.length); + (cast(byte*)p)[0 .. ci.init.length] = ci.init[]; + _gc = cast(GC)p; + } + else + { + _gc = cast(GC*) calloc(1, GC.sizeof); + } + _gc.initialize(); + // NOTE: The GC must initialize the thread library + // before its first collection. + thread_init(); +} + +extern (C) void gc_term() +{ + // NOTE: There may be daemons threads still running when this routine is + // called. If so, cleaning memory out from under then is a good + // way to make them crash horribly. This probably doesn't matter + // much since the app is supposed to be shutting down anyway, but + // I'm disabling cleanup for now until I can think about it some + // more. + // + // NOTE: Due to popular demand, this has been re-enabled. It still has + // the problems mentioned above though, so I guess we'll see. + _gc.fullCollectNoStack(); // not really a 'collect all' -- still scans + // static data area, roots, and ranges. + _gc.Dtor(); +} + +extern (C) void gc_enable() +{ + _gc.enable(); +} + +extern (C) void gc_disable() +{ + _gc.disable(); +} + +extern (C) void gc_collect() +{ + _gc.fullCollect(); +} + + +extern (C) void gc_minimize() +{ + _gc.minimize(); +} + +extern (C) uint gc_getAttr( void* p ) +{ + return _gc.getAttr( p ); +} + +extern (C) uint gc_setAttr( void* p, uint a ) +{ + return _gc.setAttr( p, a ); +} + +extern (C) uint gc_clrAttr( void* p, uint a ) +{ + return _gc.clrAttr( p, a ); +} + +extern (C) void* gc_malloc( size_t sz, uint ba = 0 ) +{ + return _gc.malloc( sz, ba ); +} + +extern (C) void* gc_calloc( size_t sz, uint ba = 0 ) +{ + return _gc.calloc( sz, ba ); +} + +extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 ) +{ + return _gc.realloc( p, sz, ba ); +} + +extern (C) size_t gc_extend( void* p, size_t mx, size_t sz ) +{ + return _gc.extend( p, mx, sz ); +} + +extern (C) size_t gc_reserve( size_t sz ) +{ + return _gc.reserve( sz ); +} + +extern (C) void gc_free( void* p ) +{ + _gc.free( p ); +} + +extern (C) void* gc_addrOf( void* p ) +{ + return _gc.addrOf( p ); +} + +extern (C) size_t gc_sizeOf( void* p ) +{ + return _gc.sizeOf( p ); +} + +extern (C) BlkInfo gc_query( void* p ) +{ + return _gc.query( p ); +} + +// NOTE: This routine is experimental. The stats or function name may change +// before it is made officially available. +extern (C) GCStats gc_stats() +{ + GCStats stats = void; + _gc.getStats( stats ); + return stats; +} + +extern (C) void gc_addRoot( void* p ) +{ + _gc.addRoot( p ); +} + +extern (C) void gc_addRange( void* p, size_t sz ) +{ + _gc.addRange( p, sz ); +} + +extern (C) void gc_removeRoot( void *p ) +{ + _gc.removeRoot( p ); +} + +extern (C) void gc_removeRange( void *p ) +{ + _gc.removeRange( p ); +} diff --git a/src/gc/basic/gcalloc.d b/src/gc/basic/gcalloc.d new file mode 100644 index 0000000..5c47f69 --- /dev/null +++ b/src/gc/basic/gcalloc.d @@ -0,0 +1,213 @@ +/** + * This module contains allocation functions for the garbage collector. + * + * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. + * All rights reserved. + * License: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + * Authors: Walter Bright, David Friedman, Sean Kelly + */ + + +version (Windows) +{ + private import sys.windows.windows; + + alias int pthread_t; + + pthread_t pthread_self() + { + return cast(pthread_t) GetCurrentThreadId(); + } + + //version = GC_Use_Alloc_Win32; +} +else version (Posix) +{ + private import stdc.posix.sys.mman; + private import stdc.stdlib; + + //version = GC_Use_Alloc_MMap; +} +else +{ + private import stdc.stdlib; + + //version = GC_Use_Alloc_Malloc; +} + +/+ +static if(is(typeof(VirtualAlloc))) + version = GC_Use_Alloc_Win32; +else static if (is(typeof(mmap))) + version = GC_Use_Alloc_MMap; +else static if (is(typeof(valloc))) + version = GC_Use_Alloc_Valloc; +else static if (is(typeof(malloc))) + version = GC_Use_Alloc_Malloc; +else static assert(false, "No supported allocation methods available."); ++/ + +static if (is(typeof(VirtualAlloc))) // version (GC_Use_Alloc_Win32) +{ + /** + * Map memory. + */ + void *os_mem_map(size_t nbytes) + { + return VirtualAlloc(null, nbytes, MEM_RESERVE, PAGE_READWRITE); + } + + + /** + * Commit memory. + * Returns: + * 0 success + * !=0 failure + */ + int os_mem_commit(void *base, size_t offset, size_t nbytes) + { void *p; + + p = VirtualAlloc(base + offset, nbytes, MEM_COMMIT, PAGE_READWRITE); + return cast(int)(p is null); + } + + + /** + * Decommit memory. + * Returns: + * 0 success + * !=0 failure + */ + int os_mem_decommit(void *base, size_t offset, size_t nbytes) + { + return cast(int)(VirtualFree(base + offset, nbytes, MEM_DECOMMIT) == 0); + } + + + /** + * Unmap memory allocated with os_mem_map(). + * Memory must have already been decommitted. + * Returns: + * 0 success + * !=0 failure + */ + int os_mem_unmap(void *base, size_t nbytes) + { + return cast(int)(VirtualFree(base, 0, MEM_RELEASE) == 0); + } +} +else static if (is(typeof(mmap))) // else version (GC_Use_Alloc_MMap) +{ + void *os_mem_map(size_t nbytes) + { void *p; + + p = mmap(null, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + return (p == MAP_FAILED) ? null : p; + } + + + int os_mem_commit(void *base, size_t offset, size_t nbytes) + { + return 0; + } + + + int os_mem_decommit(void *base, size_t offset, size_t nbytes) + { + return 0; + } + + + int os_mem_unmap(void *base, size_t nbytes) + { + return munmap(base, nbytes); + } +} +else static if (is(typeof(valloc))) // else version (GC_Use_Alloc_Valloc) +{ + void *os_mem_map(size_t nbytes) + { + return valloc(nbytes); + } + + + int os_mem_commit(void *base, size_t offset, size_t nbytes) + { + return 0; + } + + + int os_mem_decommit(void *base, size_t offset, size_t nbytes) + { + return 0; + } + + + int os_mem_unmap(void *base, size_t nbytes) + { + free(base); + return 0; + } +} +else static if (is(typeof(malloc))) // else version (GC_Use_Alloc_Malloc) +{ + // NOTE: This assumes malloc granularity is at least (void*).sizeof. If + // (req_size + PAGESIZE) is allocated, and the pointer is rounded up + // to PAGESIZE alignment, there will be space for a void* at the end + // after PAGESIZE bytes used by the GC. + + + private import gcx : PAGESIZE; + + + const size_t PAGE_MASK = PAGESIZE - 1; + + + void *os_mem_map(size_t nbytes) + { byte *p, q; + p = cast(byte *) malloc(nbytes + PAGESIZE); + q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK); + * cast(void**)(q + nbytes) = p; + return q; + } + + + int os_mem_commit(void *base, size_t offset, size_t nbytes) + { + return 0; + } + + + int os_mem_decommit(void *base, size_t offset, size_t nbytes) + { + return 0; + } + + + int os_mem_unmap(void *base, size_t nbytes) + { + free( *cast(void**)( cast(byte*) base + nbytes ) ); + return 0; + } +} +else +{ + static assert(false, "No supported allocation methods available."); +} diff --git a/src/gc/basic/gcbits.d b/src/gc/basic/gcbits.d new file mode 100644 index 0000000..a9f1683 --- /dev/null +++ b/src/gc/basic/gcbits.d @@ -0,0 +1,205 @@ +/** + * This module contains a specialized bitset implementation. + * + * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. + * All rights reserved. + * License: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + * Authors: Walter Bright, David Friedman, Sean Kelly + */ + + +private +{ + import bitmanip; + import stdc.string; + import stdc.stdlib; + extern (C) void onOutOfMemoryError(); +} + + +version (DigitalMars) +{ + version = bitops; +} +else version (GNU) +{ + // use the unoptimized version +} +else version (D_InlineAsm_X86) +{ + version = Asm86; +} + +struct GCBits +{ + const int BITS_PER_WORD = 32; + const int BITS_SHIFT = 5; + const int BITS_MASK = 31; + + uint* data = null; + size_t nwords = 0; // allocated words in data[] excluding sentinals + size_t nbits = 0; // number of bits in data[] excluding sentinals + + void Dtor() + { + if (data) + { + free(data); + data = null; + } + } + + invariant + { + if (data) + { + assert(nwords * data[0].sizeof * 8 >= nbits); + } + } + + void alloc(size_t nbits) + { + this.nbits = nbits; + nwords = (nbits + (BITS_PER_WORD - 1)) >> BITS_SHIFT; + data = cast(uint*)calloc(nwords + 2, uint.sizeof); + if (!data) + onOutOfMemoryError(); + } + + uint test(size_t i) + in + { + assert(i < nbits); + } + body + { + //return (cast(bit *)(data + 1))[i]; + return data[1 + (i >> BITS_SHIFT)] & (1 << (i & BITS_MASK)); + } + + void set(size_t i) + in + { + assert(i < nbits); + } + body + { + //(cast(bit *)(data + 1))[i] = 1; + data[1 + (i >> BITS_SHIFT)] |= (1 << (i & BITS_MASK)); + } + + void clear(size_t i) + in + { + assert(i < nbits); + } + body + { + //(cast(bit *)(data + 1))[i] = 0; + data[1 + (i >> BITS_SHIFT)] &= ~(1 << (i & BITS_MASK)); + } + + uint testClear(size_t i) + { + version (bitops) + { + return std.intrinsic.btr(data + 1, i); + } + else version (Asm86) + { + asm + { + naked ; + mov EAX,data[EAX] ; + mov ECX,i-4[ESP] ; + btr 4[EAX],ECX ; + sbb EAX,EAX ; + ret 4 ; + } + } + else + { uint result; + + //result = (cast(bit *)(data + 1))[i]; + //(cast(bit *)(data + 1))[i] = 0; + + uint* p = &data[1 + (i >> BITS_SHIFT)]; + uint mask = (1 << (i & BITS_MASK)); + result = *p & mask; + *p &= ~mask; + return result; + } + } + + void zero() + { + memset(data + 1, 0, nwords * uint.sizeof); + } + + void copy(GCBits *f) + in + { + assert(nwords == f.nwords); + } + body + { + memcpy(data + 1, f.data + 1, nwords * uint.sizeof); + } + + uint* base() + in + { + assert(data); + } + body + { + return data + 1; + } +} + +unittest +{ + GCBits b; + + b.alloc(786); + assert(b.test(123) == 0); + assert(b.testClear(123) == 0); + b.set(123); + assert(b.test(123) != 0); + assert(b.testClear(123) != 0); + assert(b.test(123) == 0); + + b.set(785); + b.set(0); + assert(b.test(785) != 0); + assert(b.test(0) != 0); + b.zero(); + assert(b.test(785) == 0); + assert(b.test(0) == 0); + + GCBits b2; + b2.alloc(786); + b2.set(38); + b.copy(&b2); + assert(b.test(38) != 0); + b2.Dtor(); + + b.Dtor(); +} diff --git a/src/gc/basic/gcstats.d b/src/gc/basic/gcstats.d new file mode 100644 index 0000000..18f21ab --- /dev/null +++ b/src/gc/basic/gcstats.d @@ -0,0 +1,38 @@ +/** + * This module contains garbage collector statistics functionality. + * + * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. + * All rights reserved. + * License: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + * Authors: Walter Bright, Sean Kelly + */ + + +/** + * + */ +struct GCStats +{ + size_t poolsize; // total size of pool + size_t usedsize; // bytes allocated + size_t freeblocks; // number of blocks marked FREE + size_t freelistsize; // total of memory on free lists + size_t pageblocks; // number of blocks marked PAGE +} diff --git a/src/gc/basic/gcx.d b/src/gc/basic/gcx.d new file mode 100644 index 0000000..0270dd5 --- /dev/null +++ b/src/gc/basic/gcx.d @@ -0,0 +1,2982 @@ +/** + * This module contains the garbage collector implementation. + * + * Copyright: Copyright (C) 2001-2007 Digital Mars, www.digitalmars.com. + * All rights reserved. + * License: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + * Authors: Walter Bright, David Friedman, Sean Kelly + */ + +// D Programming Language Garbage Collector implementation + +/************** Debugging ***************************/ + +//debug = PRINTF; // turn on printf's +//debug = COLLECT_PRINTF; // turn on printf's +//debug = THREADINVARIANT; // check thread integrity +//debug = LOGGING; // log allocations / frees +//debug = MEMSTOMP; // stomp on memory +//debug = SENTINEL; // add underrun/overrrun protection +//debug = PTRCHECK; // more pointer checking +//debug = PTRCHECK2; // thorough but slow pointer checking + +/*************** Configuration *********************/ + +version = STACKGROWSDOWN; // growing the stack means subtracting from the stack pointer + // (use for Intel X86 CPUs) + // else growing the stack means adding to the stack pointer +version = MULTI_THREADED; // produce multithreaded version + +/***************************************************/ + +private import gcbits; +private import gcstats; +private import gcalloc; + +private import cstdlib = stdc.stdlib : calloc, free, malloc, realloc; +private import stdc.string; + +debug private import stdc.stdio; + +version (GNU) +{ + // BUG: The following import will likely not work, since the gcc + // subdirectory is elsewhere. Instead, perhaps the functions + // could be declared directly or some other resolution could + // be found. + private import gcc.builtins; // for __builtin_unwind_init +} + + +private +{ + enum BlkAttr : uint + { + FINALIZE = 0b0000_0001, + NO_SCAN = 0b0000_0010, + NO_MOVE = 0b0000_0100, + ALL_BITS = 0b1111_1111 + } + + struct BlkInfo + { + void* base; + size_t size; + uint attr; + } + + extern (C) void* rt_stackBottom(); + extern (C) void* rt_stackTop(); + + extern (C) void rt_finalize( void* p, bool det = true ); + + alias void delegate( void*, void* ) scanFn; + + extern (C) void rt_scanStaticData( scanFn scan ); + + version (MULTI_THREADED) + { + extern (C) bool thread_needLock(); + extern (C) void thread_suspendAll(); + extern (C) void thread_resumeAll(); + + extern (C) void thread_scanAll( scanFn fn, void* curStackTop = null ); + } + + extern (C) void onOutOfMemoryError(); + + enum + { + OPFAIL = ~cast(size_t)0 + } +} + + +alias GC gc_t; + + +/* ======================= Leak Detector =========================== */ + + +debug (LOGGING) +{ + struct Log + { + void* p; + size_t size; + size_t line; + char* file; + void* parent; + + void print() + { + printf(" p = %x, size = %d, parent = %x ", p, size, parent); + if (file) + { + printf("%s(%u)", file, line); + } + printf("\n"); + } + } + + + struct LogArray + { + size_t dim; + size_t allocdim; + Log *data; + + void Dtor() + { + if (data) + cstdlib.free(data); + data = null; + } + + void reserve(size_t nentries) + { + assert(dim <= allocdim); + if (allocdim - dim < nentries) + { + allocdim = (dim + nentries) * 2; + assert(dim + nentries <= allocdim); + if (!data) + { + data = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof); + if (!data && allocdim) + onOutOfMemoryError(); + } + else + { Log *newdata; + + newdata = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof); + if (!newdata && allocdim) + onOutOfMemoryError(); + memcpy(newdata, data, dim * Log.sizeof); + cstdlib.free(data); + data = newdata; + } + } + } + + + void push(Log log) + { + reserve(1); + data[dim++] = log; + } + + void remove(size_t i) + { + memmove(data + i, data + i + 1, (dim - i) * Log.sizeof); + dim--; + } + + + size_t find(void *p) + { + for (size_t i = 0; i < dim; i++) + { + if (data[i].p == p) + return i; + } + return OPFAIL; // not found + } + + + void copy(LogArray *from) + { + reserve(from.dim - dim); + assert(from.dim <= allocdim); + memcpy(data, from.data, from.dim * Log.sizeof); + dim = from.dim; + } + } +} + + +/* ============================ GC =============================== */ + + +class GCLock { } // just a dummy so we can get a global lock + + +const uint GCVERSION = 1; // increment every time we change interface + // to GC. + +class GC +{ + // For passing to debug code + static size_t line; + static char* file; + + uint gcversion = GCVERSION; + + Gcx *gcx; // implementation + static ClassInfo gcLock; // global lock + + + void initialize() + { + gcLock = GCLock.classinfo; + gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof); + if (!gcx) + onOutOfMemoryError(); + gcx.initialize(); + setStackBottom(rt_stackBottom()); + } + + + void Dtor() + { + version (linux) + { + //debug(PRINTF) printf("Thread %x ", pthread_self()); + //debug(PRINTF) printf("GC.Dtor()\n"); + } + + if (gcx) + { + gcx.Dtor(); + cstdlib.free(gcx); + gcx = null; + } + } + + + invariant + { + if (gcx) + { + gcx.thread_Invariant(); + } + } + + + /** + * + */ + void enable() + { + if (!thread_needLock()) + { + assert(gcx.disabled > 0); + gcx.disabled--; + } + else synchronized (gcLock) + { + assert(gcx.disabled > 0); + gcx.disabled--; + } + } + + + /** + * + */ + void disable() + { + if (!thread_needLock()) + { + gcx.disabled++; + } + else synchronized (gcLock) + { + gcx.disabled++; + } + } + + + /** + * + */ + uint getAttr(void* p) + { + if (!p) + { + return 0; + } + + uint go() + { + Pool* pool = gcx.findPool(p); + uint oldb = 0; + + if (pool) + { + auto biti = cast(size_t)(p - pool.baseAddr) / 16; + + oldb = gcx.getBits(pool, biti); + } + return oldb; + } + + if (!thread_needLock()) + { + return go(); + } + else synchronized (gcLock) + { + return go(); + } + } + + + /** + * + */ + uint setAttr(void* p, uint mask) + { + if (!p) + { + return 0; + } + + uint go() + { + Pool* pool = gcx.findPool(p); + uint oldb = 0; + + if (pool) + { + auto biti = cast(size_t)(p - pool.baseAddr) / 16; + + oldb = gcx.getBits(pool, biti); + gcx.setBits(pool, biti, mask); + } + return oldb; + } + + if (!thread_needLock()) + { + return go(); + } + else synchronized (gcLock) + { + return go(); + } + } + + + /** + * + */ + uint clrAttr(void* p, uint mask) + { + if (!p) + { + return 0; + } + + uint go() + { + Pool* pool = gcx.findPool(p); + uint oldb = 0; + + if (pool) + { + auto biti = cast(size_t)(p - pool.baseAddr) / 16; + + oldb = gcx.getBits(pool, biti); + gcx.clrBits(pool, biti, mask); + } + return oldb; + } + + if (!thread_needLock()) + { + return go(); + } + else synchronized (gcLock) + { + return go(); + } + } + + + /** + * + */ + void *malloc(size_t size, uint bits = 0) + { + if (!size) + { + return null; + } + + if (!thread_needLock()) + { + return mallocNoSync(size, bits); + } + else synchronized (gcLock) + { + return mallocNoSync(size, bits); + } + } + + + // + // + // + private void *mallocNoSync(size_t size, uint bits = 0) + { + assert(size != 0); + + void *p = null; + Bins bin; + + //debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx); + assert(gcx); + //debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self()); + + size += SENTINEL_EXTRA; + + // Compute size bin + // Cache previous binsize lookup - Dave Fladebo. + static size_t lastsize = -1; + static Bins lastbin; + if (size == lastsize) + bin = lastbin; + else + { + bin = gcx.findBin(size); + lastsize = size; + lastbin = bin; + } + + if (bin < B_PAGE) + { + p = gcx.bucket[bin]; + if (p is null) + { + if (!gcx.allocPage(bin) && !gcx.disabled) // try to find a new page + { + if (!thread_needLock()) + { + /* Then we haven't locked it yet. Be sure + * and lock for a collection, since a finalizer + * may start a new thread. + */ + synchronized (gcLock) + { + gcx.fullcollectshell(); + } + } + else if (!gcx.fullcollectshell()) // collect to find a new page + { + //gcx.newPool(1); + } + } + if (!gcx.bucket[bin] && !gcx.allocPage(bin)) + { int result; + + gcx.newPool(1); // allocate new pool to find a new page + result = gcx.allocPage(bin); + if (!result) + onOutOfMemoryError(); + } + p = gcx.bucket[bin]; + } + + // Return next item from free list + gcx.bucket[bin] = (cast(List*)p).next; + if( !(bits & BlkAttr.NO_SCAN) ) + memset(p + size, 0, binsize[bin] - size); + //debug(PRINTF) printf("\tmalloc => %x\n", p); + debug (MEMSTOMP) memset(p, 0xF0, size); + } + else + { + p = gcx.bigAlloc(size); + if (!p) + onOutOfMemoryError(); + } + size -= SENTINEL_EXTRA; + p = sentinel_add(p); + sentinel_init(p, size); + gcx.log_malloc(p, size); + + if (bits) + { + Pool *pool = gcx.findPool(p); + assert(pool); + + gcx.setBits(pool, cast(size_t)(p - pool.baseAddr) / 16, bits); + } + return p; + } + + + /** + * + */ + void *calloc(size_t size, uint bits = 0) + { + if (!size) + { + return null; + } + + if (!thread_needLock()) + { + return callocNoSync(size, bits); + } + else synchronized (gcLock) + { + return callocNoSync(size, bits); + } + } + + + // + // + // + private void *callocNoSync(size_t size, uint bits = 0) + { + assert(size != 0); + + //debug(PRINTF) printf("calloc: %x len %d\n", p, len); + void *p = mallocNoSync(size, bits); + memset(p, 0, size); + return p; + } + + + /** + * + */ + void *realloc(void *p, size_t size, uint bits = 0) + { + if (!thread_needLock()) + { + return reallocNoSync(p, size, bits); + } + else synchronized (gcLock) + { + return reallocNoSync(p, size, bits); + } + } + + + // + // + // + private void *reallocNoSync(void *p, size_t size, uint bits = 0) + { + if (!size) + { if (p) + { freeNoSync(p); + p = null; + } + } + else if (!p) + { + p = mallocNoSync(size, bits); + } + else + { void *p2; + size_t psize; + + //debug(PRINTF) printf("GC::realloc(p = %x, size = %u)\n", p, size); + version (SENTINEL) + { + sentinel_Invariant(p); + psize = *sentinel_size(p); + if (psize != size) + { + if (psize) + { + Pool *pool = gcx.findPool(p); + + if (pool) + { + auto biti = cast(size_t)(p - pool.baseAddr) / 16; + + if (bits) + { + gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); + gcx.setBits(pool, biti, bits); + } + else + { + bits = gcx.getBits(pool, biti); + } + } + } + p2 = mallocNoSync(size, bits); + if (psize < size) + size = psize; + //debug(PRINTF) printf("\tcopying %d bytes\n",size); + memcpy(p2, p, size); + p = p2; + } + } + else + { + psize = gcx.findSize(p); // find allocated size + if (psize >= PAGESIZE && size >= PAGESIZE) + { + auto psz = psize / PAGESIZE; + auto newsz = (size + PAGESIZE - 1) / PAGESIZE; + if (newsz == psz) + return p; + + auto pool = gcx.findPool(p); + auto pagenum = (p - pool.baseAddr) / PAGESIZE; + + if (newsz < psz) + { // Shrink in place + synchronized (gcLock) + { + debug (MEMSTOMP) memset(p + size, 0xF2, psize - size); + pool.freePages(pagenum + newsz, psz - newsz); + } + return p; + } + else if (pagenum + newsz <= pool.npages) + { + // Attempt to expand in place + synchronized (gcLock) + { + for (size_t i = pagenum + psz; 1;) + { + if (i == pagenum + newsz) + { + debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize); + memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz); + return p; + } + if (i == pool.ncommitted) + { + auto u = pool.extendPages(pagenum + newsz - pool.ncommitted); + if (u == OPFAIL) + break; + i = pagenum + newsz; + continue; + } + if (pool.pagetable[i] != B_FREE) + break; + i++; + } + } + } + } + if (psize < size || // if new size is bigger + psize > size * 2) // or less than half + { + if (psize) + { + Pool *pool = gcx.findPool(p); + + if (pool) + { + auto biti = cast(size_t)(p - pool.baseAddr) / 16; + + if (bits) + { + gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); + gcx.setBits(pool, biti, bits); + } + else + { + bits = gcx.getBits(pool, biti); + } + } + } + p2 = mallocNoSync(size, bits); + if (psize < size) + size = psize; + //debug(PRINTF) printf("\tcopying %d bytes\n",size); + memcpy(p2, p, size); + p = p2; + } + } + } + return p; + } + + + /** + * Attempt to in-place enlarge the memory block pointed to by p by at least + * minbytes beyond its current capacity, up to a maximum of maxsize. This + * does not attempt to move the memory block (like realloc() does). + * + * Returns: + * 0 if could not extend p, + * total size of entire memory block if successful. + */ + size_t extend(void* p, size_t minsize, size_t maxsize) + { + if (!thread_needLock()) + { + return extendNoSync(p, minsize, maxsize); + } + else synchronized (gcLock) + { + return extendNoSync(p, minsize, maxsize); + } + } + + + // + // + // + private size_t extendNoSync(void* p, size_t minsize, size_t maxsize) + in + { + assert( minsize <= maxsize ); + } + body + { + //debug(PRINTF) printf("GC::extend(p = %x, minsize = %u, maxsize = %u)\n", p, minsize, maxsize); + version (SENTINEL) + { + return 0; + } + auto psize = gcx.findSize(p); // find allocated size + if (psize < PAGESIZE) + return 0; // cannot extend buckets + + auto psz = psize / PAGESIZE; + auto minsz = (minsize + PAGESIZE - 1) / PAGESIZE; + auto maxsz = (maxsize + PAGESIZE - 1) / PAGESIZE; + + auto pool = gcx.findPool(p); + auto pagenum = (p - pool.baseAddr) / PAGESIZE; + + size_t sz; + for (sz = 0; sz < maxsz; sz++) + { + auto i = pagenum + psz + sz; + if (i == pool.ncommitted) + break; + if (pool.pagetable[i] != B_FREE) + { if (sz < minsz) + return 0; + break; + } + } + if (sz >= minsz) + { + } + else if (pagenum + psz + sz == pool.ncommitted) + { + auto u = pool.extendPages(minsz - sz); + if (u == OPFAIL) + return 0; + sz = minsz; + } + else + return 0; + debug (MEMSTOMP) memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize); + memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz); + gcx.p_cache = null; + gcx.size_cache = 0; + return (psz + sz) * PAGESIZE; + } + + + /** + * + */ + size_t reserve(size_t size) + { + if (!size) + { + return 0; + } + + if (!thread_needLock()) + { + return reserveNoSync(size); + } + else synchronized (gcLock) + { + return reserveNoSync(size); + } + } + + + // + // + // + private size_t reserveNoSync(size_t size) + { + assert(size != 0); + assert(gcx); + + return gcx.reserve(size); + } + + + /** + * + */ + void free(void *p) + { + if (!p) + { + return; + } + + if (!thread_needLock()) + { + return freeNoSync(p); + } + else synchronized (gcLock) + { + return freeNoSync(p); + } + } + + + // + // + // + private void freeNoSync(void *p) + { + assert (p); + + Pool* pool; + size_t pagenum; + Bins bin; + size_t biti; + + // Find which page it is in + pool = gcx.findPool(p); + if (!pool) // if not one of ours + return; // ignore + sentinel_Invariant(p); + p = sentinel_sub(p); + pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE; + biti = cast(size_t)(p - pool.baseAddr) / 16; + gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); + + bin = cast(Bins)pool.pagetable[pagenum]; + if (bin == B_PAGE) // if large alloc + { size_t npages; + size_t n; + + // Free pages + npages = 1; + n = pagenum; + while (++n < pool.ncommitted && pool.pagetable[n] == B_PAGEPLUS) + npages++; + debug (MEMSTOMP) memset(p, 0xF2, npages * PAGESIZE); + pool.freePages(pagenum, npages); + } + else + { // Add to free list + List *list = cast(List*)p; + + debug (MEMSTOMP) memset(p, 0xF2, binsize[bin]); + + list.next = gcx.bucket[bin]; + gcx.bucket[bin] = list; + } + gcx.log_free(sentinel_add(p)); + } + + + /** + * Determine the base address of the block containing p. If p is not a gc + * allocated pointer, return null. + */ + void* addrOf(void *p) + { + if (!p) + { + return null; + } + + if (!thread_needLock()) + { + return addrOfNoSync(p); + } + else synchronized (gcLock) + { + return addrOfNoSync(p); + } + } + + + // + // + // + void* addrOfNoSync(void *p) + { + if (!p) + { + return null; + } + + return gcx.findBase(p); + } + + + /** + * Determine the allocated size of pointer p. If p is an interior pointer + * or not a gc allocated pointer, return 0. + */ + size_t sizeOf(void *p) + { + if (!p) + { + return 0; + } + + if (!thread_needLock()) + { + return sizeOfNoSync(p); + } + else synchronized (gcLock) + { + return sizeOfNoSync(p); + } + } + + + // + // + // + private size_t sizeOfNoSync(void *p) + { + assert (p); + + version (SENTINEL) + { + p = sentinel_sub(p); + size_t size = gcx.findSize(p); + + // Check for interior pointer + // This depends on: + // 1) size is a power of 2 for less than PAGESIZE values + // 2) base of memory pool is aligned on PAGESIZE boundary + if (cast(size_t)p & (size - 1) & (PAGESIZE - 1)) + size = 0; + return size ? size - SENTINEL_EXTRA : 0; + } + else + { + if (p == gcx.p_cache) + return gcx.size_cache; + + size_t size = gcx.findSize(p); + + // Check for interior pointer + // This depends on: + // 1) size is a power of 2 for less than PAGESIZE values + // 2) base of memory pool is aligned on PAGESIZE boundary + if (cast(size_t)p & (size - 1) & (PAGESIZE - 1)) + size = 0; + else + { + gcx.p_cache = p; + gcx.size_cache = size; + } + + return size; + } + } + + + /** + * Determine the base address of the block containing p. If p is not a gc + * allocated pointer, return null. + */ + BlkInfo query(void *p) + { + if (!p) + { + BlkInfo i; + return i; + } + + if (!thread_needLock()) + { + return queryNoSync(p); + } + else synchronized (gcLock) + { + return queryNoSync(p); + } + } + + + // + // + // + BlkInfo queryNoSync(void *p) + { + assert(p); + + return gcx.getInfo(p); + } + + + /** + * Verify that pointer p: + * 1) belongs to this memory pool + * 2) points to the start of an allocated piece of memory + * 3) is not on a free list + */ + void check(void *p) + { + if (!p) + { + return; + } + + if (!thread_needLock()) + { + checkNoSync(p); + } + else synchronized (gcLock) + { + checkNoSync(p); + } + } + + + // + // + // + private void checkNoSync(void *p) + { + assert(p); + + sentinel_Invariant(p); + debug (PTRCHECK) + { + Pool* pool; + size_t pagenum; + Bins bin; + size_t size; + + p = sentinel_sub(p); + pool = gcx.findPool(p); + assert(pool); + pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE; + bin = cast(Bins)pool.pagetable[pagenum]; + assert(bin <= B_PAGE); + size = binsize[bin]; + assert((cast(size_t)p & (size - 1)) == 0); + + debug (PTRCHECK2) + { + if (bin < B_PAGE) + { + // Check that p is not on a free list + List *list; + + for (list = gcx.bucket[bin]; list; list = list.next) + { + assert(cast(void*)list != p); + } + } + } + } + } + + + // + // + // + private void setStackBottom(void *p) + { + version (STACKGROWSDOWN) + { + //p = (void *)((uint *)p + 4); + if (p > gcx.stackBottom) + { + //debug(PRINTF) printf("setStackBottom(%x)\n", p); + gcx.stackBottom = p; + } + } + else + { + //p = (void *)((uint *)p - 4); + if (p < gcx.stackBottom) + { + //debug(PRINTF) printf("setStackBottom(%x)\n", p); + gcx.stackBottom = cast(char*)p; + } + } + } + + + /** + * add p to list of roots + */ + void addRoot(void *p) + { + if (!p) + { + return; + } + + if (!thread_needLock()) + { + gcx.addRoot(p); + } + else synchronized (gcLock) + { + gcx.addRoot(p); + } + } + + + /** + * remove p from list of roots + */ + void removeRoot(void *p) + { + if (!p) + { + return; + } + + if (!thread_needLock()) + { + gcx.removeRoot(p); + } + else synchronized (gcLock) + { + gcx.removeRoot(p); + } + } + + + /** + * add range to scan for roots + */ + void addRange(void *p, size_t sz) + { + if (!p || !sz) + { + return; + } + + //debug(PRINTF) printf("+GC.addRange(pbot = x%x, ptop = x%x)\n", pbot, ptop); + if (!thread_needLock()) + { + gcx.addRange(p, p + sz); + } + else synchronized (gcLock) + { + gcx.addRange(p, p + sz); + } + //debug(PRINTF) printf("-GC.addRange()\n"); + } + + + /** + * remove range + */ + void removeRange(void *p) + { + if (!p) + { + return; + } + + if (!thread_needLock()) + { + gcx.removeRange(p); + } + else synchronized (gcLock) + { + gcx.removeRange(p); + } + } + + + /** + * do full garbage collection + */ + void fullCollect() + { + debug(PRINTF) printf("GC.fullCollect()\n"); + + if (!thread_needLock()) + { + gcx.fullcollectshell(); + } + else synchronized (gcLock) + { + gcx.fullcollectshell(); + } + + version (none) + { + GCStats stats; + + getStats(stats); + debug(PRINTF) printf("poolsize = %x, usedsize = %x, freelistsize = %x\n", + stats.poolsize, stats.usedsize, stats.freelistsize); + } + + gcx.log_collect(); + } + + + /** + * do full garbage collection ignoring roots + */ + void fullCollectNoStack() + { + if (!thread_needLock()) + { + gcx.noStack++; + gcx.fullcollectshell(); + gcx.noStack--; + } + else synchronized (gcLock) + { + gcx.noStack++; + gcx.fullcollectshell(); + gcx.noStack--; + } + } + + + /** + * minimize free space usage + */ + void minimize() + { + if (!thread_needLock()) + { + gcx.minimize(); + } + else synchronized (gcLock) + { + gcx.minimize(); + } + } + + + /** + * Retrieve statistics about garbage collection. + * Useful for debugging and tuning. + */ + void getStats(out GCStats stats) + { + if (!thread_needLock()) + { + getStatsNoSync(stats); + } + else synchronized (gcLock) + { + getStatsNoSync(stats); + } + } + + + // + // + // + private void getStatsNoSync(out GCStats stats) + { + size_t psize = 0; + size_t usize = 0; + size_t flsize = 0; + + size_t n; + size_t bsize = 0; + + //debug(PRINTF) printf("getStats()\n"); + memset(&stats, 0, GCStats.sizeof); + + for (n = 0; n < gcx.npools; n++) + { Pool *pool = gcx.pooltable[n]; + + psize += pool.ncommitted * PAGESIZE; + for (size_t j = 0; j < pool.ncommitted; j++) + { + Bins bin = cast(Bins)pool.pagetable[j]; + if (bin == B_FREE) + stats.freeblocks++; + else if (bin == B_PAGE) + stats.pageblocks++; + else if (bin < B_PAGE) + bsize += PAGESIZE; + } + } + + for (n = 0; n < B_PAGE; n++) + { + //debug(PRINTF) printf("bin %d\n", n); + for (List *list = gcx.bucket[n]; list; list = list.next) + { + //debug(PRINTF) printf("\tlist %x\n", list); + flsize += binsize[n]; + } + } + + usize = bsize - flsize; + + stats.poolsize = psize; + stats.usedsize = bsize - flsize; + stats.freelistsize = flsize; + } +} + + +/* ============================ Gcx =============================== */ + +enum +{ PAGESIZE = 4096, + COMMITSIZE = (4096*16), + POOLSIZE = (4096*256), +} + + +enum +{ + B_16, + B_32, + B_64, + B_128, + B_256, + B_512, + B_1024, + B_2048, + B_PAGE, // start of large alloc + B_PAGEPLUS, // continuation of large alloc + B_FREE, // free page + B_UNCOMMITTED, // memory not committed for this page + B_MAX +} + + +alias ubyte Bins; + + +struct List +{ + List *next; +} + + +struct Range +{ + void *pbot; + void *ptop; +} + + +const uint binsize[B_MAX] = [ 16,32,64,128,256,512,1024,2048,4096 ]; +const uint notbinsize[B_MAX] = [ ~(16u-1),~(32u-1),~(64u-1),~(128u-1),~(256u-1), + ~(512u-1),~(1024u-1),~(2048u-1),~(4096u-1) ]; + +/* ============================ Gcx =============================== */ + + +struct Gcx +{ + debug (THREADINVARIANT) + { + pthread_t self; + void thread_Invariant() + { + if (self != pthread_self()) + printf("thread_Invariant(): gcx = %x, self = %x, pthread_self() = %x\n", this, self, pthread_self()); + assert(self == pthread_self()); + } + } + else + { + void thread_Invariant() { } + } + + void *p_cache; + size_t size_cache; + + size_t nroots; + size_t rootdim; + void **roots; + + size_t nranges; + size_t rangedim; + Range *ranges; + + uint noStack; // !=0 means don't scan stack + uint log; // turn on logging + uint anychanges; + void *stackBottom; + uint inited; + int disabled; // turn off collections if >0 + + byte *minAddr; // min(baseAddr) + byte *maxAddr; // max(topAddr) + + size_t npools; + Pool **pooltable; + + List *bucket[B_MAX]; // free list for each size + + + void initialize() + { int dummy; + + (cast(byte*)this)[0 .. Gcx.sizeof] = 0; + stackBottom = cast(char*)&dummy; + log_init(); + debug (THREADINVARIANT) + self = pthread_self(); + //printf("gcx = %p, self = %x\n", this, self); + inited = 1; + } + + + void Dtor() + { + inited = 0; + + for (size_t i = 0; i < npools; i++) + { Pool *pool = pooltable[i]; + + pool.Dtor(); + cstdlib.free(pool); + } + if (pooltable) + cstdlib.free(pooltable); + + if (roots) + cstdlib.free(roots); + + if (ranges) + cstdlib.free(ranges); + } + + + void Invariant() { } + + + invariant + { + if (inited) + { + //printf("Gcx.invariant(): this = %p\n", this); + size_t i; + + // Assure we're called on the right thread + debug (THREADINVARIANT) assert(self == pthread_self()); + + for (i = 0; i < npools; i++) + { Pool *pool = pooltable[i]; + + pool.Invariant(); + if (i == 0) + { + assert(minAddr == pool.baseAddr); + } + if (i + 1 < npools) + { + assert(pool.opCmp(pooltable[i + 1]) < 0); + } + else if (i + 1 == npools) + { + assert(maxAddr == pool.topAddr); + } + } + + if (roots) + { + assert(rootdim != 0); + assert(nroots <= rootdim); + } + + if (ranges) + { + assert(rangedim != 0); + assert(nranges <= rangedim); + + for (i = 0; i < nranges; i++) + { + assert(ranges[i].pbot); + assert(ranges[i].ptop); + assert(ranges[i].pbot <= ranges[i].ptop); + } + } + + for (i = 0; i < B_PAGE; i++) + { + for (List *list = bucket[i]; list; list = list.next) + { + } + } + } + } + + + /** + * + */ + void addRoot(void *p) + { + if (nroots == rootdim) + { + size_t newdim = rootdim * 2 + 16; + void** newroots; + + newroots = cast(void**)cstdlib.malloc(newdim * newroots[0].sizeof); + if (!newroots) + onOutOfMemoryError(); + if (roots) + { memcpy(newroots, roots, nroots * newroots[0].sizeof); + cstdlib.free(roots); + } + roots = newroots; + rootdim = newdim; + } + roots[nroots] = p; + nroots++; + } + + + /** + * + */ + void removeRoot(void *p) + { + for (size_t i = nroots; i--;) + { + if (roots[i] == p) + { + nroots--; + memmove(roots + i, roots + i + 1, (nroots - i) * roots[0].sizeof); + return; + } + } + assert(0); + } + + + /** + * + */ + void addRange(void *pbot, void *ptop) + { + debug(PRINTF) printf("Thread %x ", pthread_self()); + debug(PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this, pbot, ptop, nranges); + if (nranges == rangedim) + { + size_t newdim = rangedim * 2 + 16; + Range *newranges; + + newranges = cast(Range*)cstdlib.malloc(newdim * newranges[0].sizeof); + if (!newranges) + onOutOfMemoryError(); + if (ranges) + { memcpy(newranges, ranges, nranges * newranges[0].sizeof); + cstdlib.free(ranges); + } + ranges = newranges; + rangedim = newdim; + } + ranges[nranges].pbot = pbot; + ranges[nranges].ptop = ptop; + nranges++; + } + + + /** + * + */ + void removeRange(void *pbot) + { + debug(PRINTF) printf("Thread %x ", pthread_self()); + debug(PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this, pbot, nranges); + for (size_t i = nranges; i--;) + { + if (ranges[i].pbot == pbot) + { + nranges--; + memmove(ranges + i, ranges + i + 1, (nranges - i) * ranges[0].sizeof); + return; + } + } + debug(PRINTF) printf("Wrong thread\n"); + + // This is a fatal error, but ignore it. + // The problem is that we can get a Close() call on a thread + // other than the one the range was allocated on. + //assert(zero); + } + + + /** + * Find Pool that pointer is in. + * Return null if not in a Pool. + * Assume pooltable[] is sorted. + */ + Pool *findPool(void *p) + { + if (p >= minAddr && p < maxAddr) + { + if (npools == 1) + { + return pooltable[0]; + } + + for (size_t i = 0; i < npools; i++) + { Pool *pool; + + pool = pooltable[i]; + if (p < pool.topAddr) + { if (pool.baseAddr <= p) + return pool; + break; + } + } + } + return null; + } + + + /** + * Find base address of block containing pointer p. + * Returns null if not a gc'd pointer + */ + void* findBase(void *p) + { + Pool *pool; + + pool = findPool(p); + if (pool) + { + size_t offset = cast(size_t)(p - pool.baseAddr); + size_t pn = offset / PAGESIZE; + Bins bin = cast(Bins)pool.pagetable[pn]; + + // Adjust bit to be at start of allocated memory block + if (bin <= B_PAGE) + { + return pool.baseAddr + (offset & notbinsize[bin]); + } + else if (bin == B_PAGEPLUS) + { + do + { --pn, offset -= PAGESIZE; + } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); + + return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); + } + else + { + // we are in a B_FREE or B_UNCOMMITTED page + return null; + } + } + return null; + } + + + /** + * Find size of pointer p. + * Returns 0 if not a gc'd pointer + */ + size_t findSize(void *p) + { + Pool* pool; + size_t size = 0; + + pool = findPool(p); + if (pool) + { + size_t pagenum; + Bins bin; + + pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE; + bin = cast(Bins)pool.pagetable[pagenum]; + size = binsize[bin]; + if (bin == B_PAGE) + { size_t npages = pool.ncommitted; + ubyte* pt; + size_t i; + + pt = &pool.pagetable[0]; + for (i = pagenum + 1; i < npages; i++) + { + if (pt[i] != B_PAGEPLUS) + break; + } + size = (i - pagenum) * PAGESIZE; + } + } + return size; + } + + + /** + * + */ + BlkInfo getInfo(void* p) + { + Pool* pool; + BlkInfo info; + + pool = findPool(p); + if (pool) + { + size_t offset = cast(size_t)(p - pool.baseAddr); + size_t pn = offset / PAGESIZE; + Bins bin = cast(Bins)pool.pagetable[pn]; + + //////////////////////////////////////////////////////////////////// + // findAddr + //////////////////////////////////////////////////////////////////// + + if (bin <= B_PAGE) + { + info.base = pool.baseAddr + (offset & notbinsize[bin]); + } + else if (bin == B_PAGEPLUS) + { + do + { --pn, offset -= PAGESIZE; + } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); + + info.base = pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); + + // fix bin for use by size calc below + bin = cast(Bins)pool.pagetable[pn]; + } + + //////////////////////////////////////////////////////////////////// + // findSize + //////////////////////////////////////////////////////////////////// + + info.size = binsize[bin]; + if (bin == B_PAGE) + { size_t npages = pool.ncommitted; + ubyte* pt; + size_t i; + + pt = &pool.pagetable[0]; + for (i = pn + 1; i < npages; i++) + { + if (pt[i] != B_PAGEPLUS) + break; + } + info.size = (i - pn) * PAGESIZE; + } + + //////////////////////////////////////////////////////////////////// + // getBits + //////////////////////////////////////////////////////////////////// + + info.attr = getBits(pool, cast(size_t)(offset / 16)); + } + return info; + } + + + /** + * Compute bin for size. + */ + static Bins findBin(size_t size) + { Bins bin; + + if (size <= 256) + { + if (size <= 64) + { + if (size <= 16) + bin = B_16; + else if (size <= 32) + bin = B_32; + else + bin = B_64; + } + else + { + if (size <= 128) + bin = B_128; + else + bin = B_256; + } + } + else + { + if (size <= 1024) + { + if (size <= 512) + bin = B_512; + else + bin = B_1024; + } + else + { + if (size <= 2048) + bin = B_2048; + else + bin = B_PAGE; + } + } + return bin; + } + + + /** + * Allocate a new pool of at least size bytes. + * Sort it into pooltable[]. + * Mark all memory in the pool as B_FREE. + * Return the actual number of bytes reserved or 0 on error. + */ + size_t reserve(size_t size) + { + size_t npages = (size + PAGESIZE - 1) / PAGESIZE; + Pool* pool = newPool(npages); + + if (!pool || pool.extendPages(npages) == OPFAIL) + return 0; + return pool.ncommitted * PAGESIZE; + } + + + /** + * Minimizes physical memory usage by returning free pools to the OS. + */ + void minimize() + { + size_t n; + size_t pn; + Pool* pool; + size_t ncommitted; + + for (n = 0; n < npools; n++) + { + pool = pooltable[n]; + ncommitted = pool.ncommitted; + for (pn = 0; pn < ncommitted; pn++) + { + if (cast(Bins)pool.pagetable[pn] != B_FREE) + break; + } + if (pn < ncommitted) + { + n++; + continue; + } + pool.Dtor(); + cstdlib.free(pool); + memmove(pooltable + n, + pooltable + n + 1, + (--npools - n) * (Pool*).sizeof); + minAddr = pooltable[0].baseAddr; + maxAddr = pooltable[npools - 1].topAddr; + } + } + + + /** + * Allocate a chunk of memory that is larger than a page. + * Return null if out of memory. + */ + void *bigAlloc(size_t size) + { + Pool* pool; + size_t npages; + size_t n; + size_t pn; + size_t freedpages; + void* p; + int state; + + npages = (size + PAGESIZE - 1) / PAGESIZE; + + for (state = 0; ; ) + { + // This code could use some refinement when repeatedly + // allocating very large arrays. + + for (n = 0; n < npools; n++) + { + pool = pooltable[n]; + pn = pool.allocPages(npages); + if (pn != OPFAIL) + goto L1; + } + + // Failed + switch (state) + { + case 0: + if (disabled) + { state = 1; + continue; + } + // Try collecting + freedpages = fullcollectshell(); + if (freedpages >= npools * ((POOLSIZE / PAGESIZE) / 4)) + { state = 1; + continue; + } + // Release empty pools to prevent bloat + minimize(); + // Allocate new pool + pool = newPool(npages); + if (!pool) + { state = 2; + continue; + } + pn = pool.allocPages(npages); + assert(pn != OPFAIL); + goto L1; + case 1: + // Release empty pools to prevent bloat + minimize(); + // Allocate new pool + pool = newPool(npages); + if (!pool) + goto Lnomemory; + pn = pool.allocPages(npages); + assert(pn != OPFAIL); + goto L1; + case 2: + goto Lnomemory; + default: + assert(false); + } + } + + L1: + pool.pagetable[pn] = B_PAGE; + if (npages > 1) + memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1); + p = pool.baseAddr + pn * PAGESIZE; + memset(cast(char *)p + size, 0, npages * PAGESIZE - size); + debug (MEMSTOMP) memset(p, 0xF1, size); + //debug(PRINTF) printf("\tp = %x\n", p); + return p; + + Lnomemory: + return null; // let mallocNoSync handle the error + } + + + /** + * Allocate a new pool with at least npages in it. + * Sort it into pooltable[]. + * Return null if failed. + */ + Pool *newPool(size_t npages) + { + Pool* pool; + Pool** newpooltable; + size_t newnpools; + size_t i; + + //debug(PRINTF) printf("************Gcx::newPool(npages = %d)****************\n", npages); + + // Round up to COMMITSIZE pages + npages = (npages + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1); + + // Minimum of POOLSIZE + if (npages < POOLSIZE/PAGESIZE) + npages = POOLSIZE/PAGESIZE; + else if (npages > POOLSIZE/PAGESIZE) + { // Give us 150% of requested size, so there's room to extend + auto n = npages + (npages >> 1); + if (n < size_t.max/PAGESIZE) + npages = n; + } + + // Allocate successively larger pools up to 8 megs + if (npools) + { size_t n; + + n = npools; + if (n > 8) + n = 8; // cap pool size at 8 megs + n *= (POOLSIZE / PAGESIZE); + if (npages < n) + npages = n; + } + + pool = cast(Pool *)cstdlib.calloc(1, Pool.sizeof); + if (pool) + { + pool.initialize(npages); + if (!pool.baseAddr) + goto Lerr; + + newnpools = npools + 1; + newpooltable = cast(Pool **)cstdlib.realloc(pooltable, newnpools * (Pool *).sizeof); + if (!newpooltable) + goto Lerr; + + // Sort pool into newpooltable[] + for (i = 0; i < npools; i++) + { + if (pool.opCmp(newpooltable[i]) < 0) + break; + } + memmove(newpooltable + i + 1, newpooltable + i, (npools - i) * (Pool *).sizeof); + newpooltable[i] = pool; + + pooltable = newpooltable; + npools = newnpools; + + minAddr = pooltable[0].baseAddr; + maxAddr = pooltable[npools - 1].topAddr; + } + return pool; + + Lerr: + pool.Dtor(); + cstdlib.free(pool); + return null; + } + + + /** + * Allocate a page of bin's. + * Returns: + * 0 failed + */ + int allocPage(Bins bin) + { + Pool* pool; + size_t n; + size_t pn; + byte* p; + byte* ptop; + + //debug(PRINTF) printf("Gcx::allocPage(bin = %d)\n", bin); + for (n = 0; n < npools; n++) + { + pool = pooltable[n]; + pn = pool.allocPages(1); + if (pn != OPFAIL) + goto L1; + } + return 0; // failed + + L1: + pool.pagetable[pn] = cast(ubyte)bin; + + // Convert page to free list + size_t size = binsize[bin]; + List **b = &bucket[bin]; + + p = pool.baseAddr + pn * PAGESIZE; + ptop = p + PAGESIZE; + for (; p < ptop; p += size) + { + (cast(List *)p).next = *b; + *b = cast(List *)p; + } + return 1; + } + + + /** + * Search a range of memory values and mark any pointers into the GC pool. + */ + void mark(void *pbot, void *ptop) + { + void **p1 = cast(void **)pbot; + void **p2 = cast(void **)ptop; + size_t pcache = 0; + uint changes = 0; + + //printf("marking range: %p -> %p\n", pbot, ptop); + for (; p1 < p2; p1++) + { + Pool *pool; + byte *p = cast(byte *)(*p1); + + //if (log) debug(PRINTF) printf("\tmark %x\n", p); + if (p >= minAddr && p < maxAddr) + { + if ((cast(size_t)p & ~(PAGESIZE-1)) == pcache) + continue; + + pool = findPool(p); + if (pool) + { + size_t offset = cast(size_t)(p - pool.baseAddr); + size_t biti; + size_t pn = offset / PAGESIZE; + Bins bin = cast(Bins)pool.pagetable[pn]; + + //debug(PRINTF) printf("\t\tfound pool %x, base=%x, pn = %d, bin = %d, biti = x%x\n", pool, pool.baseAddr, pn, bin, biti); + + // Adjust bit to be at start of allocated memory block + if (bin <= B_PAGE) + { + biti = (offset & notbinsize[bin]) >> 4; + //debug(PRINTF) printf("\t\tbiti = x%x\n", biti); + } + else if (bin == B_PAGEPLUS) + { + do + { --pn; + } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); + biti = pn * (PAGESIZE / 16); + } + else + { + // Don't mark bits in B_FREE or B_UNCOMMITTED pages + continue; + } + + if (bin >= B_PAGE) // Cache B_PAGE and B_PAGEPLUS lookups + pcache = cast(size_t)p & ~(PAGESIZE-1); + + //debug(PRINTF) printf("\t\tmark(x%x) = %d\n", biti, pool.mark.test(biti)); + if (!pool.mark.test(biti)) + { + //if (log) debug(PRINTF) printf("\t\tmarking %x\n", p); + pool.mark.set(biti); + if (!pool.noscan.test(biti)) + { + pool.scan.set(biti); + changes = 1; + } + log_parent(sentinel_add(pool.baseAddr + biti * 16), sentinel_add(pbot)); + } + } + } + } + anychanges |= changes; + } + + + /** + * Return number of full pages free'd. + */ + size_t fullcollectshell() + { + // The purpose of the 'shell' is to ensure all the registers + // get put on the stack so they'll be scanned + void *sp; + size_t result; + version (GNU) + { + __builtin_unwind_init(); + sp = & sp; + } + else + { + asm + { + pushad ; + mov sp[EBP],ESP ; + } + } + result = fullcollect(sp); + version (GNU) + { + // nothing to do + } + else + { + asm + { + popad ; + } + } + return result; + } + + + /** + * + */ + size_t fullcollect(void *stackTop) + { + size_t n; + Pool* pool; + + debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n"); + + thread_suspendAll(); + + p_cache = null; + size_cache = 0; + + anychanges = 0; + for (n = 0; n < npools; n++) + { + pool = pooltable[n]; + pool.mark.zero(); + pool.scan.zero(); + pool.freebits.zero(); + } + + // Mark each free entry, so it doesn't get scanned + for (n = 0; n < B_PAGE; n++) + { + for (List *list = bucket[n]; list; list = list.next) + { + pool = findPool(list); + assert(pool); + pool.freebits.set(cast(size_t)(cast(byte*)list - pool.baseAddr) / 16); + } + } + + for (n = 0; n < npools; n++) + { + pool = pooltable[n]; + pool.mark.copy(&pool.freebits); + } + + rt_scanStaticData( &mark ); + + version (MULTI_THREADED) + { + if (!noStack) + { + // Scan stacks and registers for each paused thread + thread_scanAll( &mark, stackTop ); + } + } + else + { + if (!noStack) + { + // Scan stack for main thread + debug(PRINTF) printf(" scan stack bot = %x, top = %x\n", stackTop, stackBottom); + version (STACKGROWSDOWN) + mark(stackTop, stackBottom); + else + mark(stackBottom, stackTop); + } + } + + // Scan roots[] + debug(COLLECT_PRINTF) printf("scan roots[]\n"); + mark(roots, roots + nroots); + + // Scan ranges[] + debug(COLLECT_PRINTF) printf("scan ranges[]\n"); + //log++; + for (n = 0; n < nranges; n++) + { + debug(COLLECT_PRINTF) printf("\t%x .. %x\n", ranges[n].pbot, ranges[n].ptop); + mark(ranges[n].pbot, ranges[n].ptop); + } + //log--; + + debug(COLLECT_PRINTF) printf("\tscan heap\n"); + while (anychanges) + { + anychanges = 0; + for (n = 0; n < npools; n++) + { + uint *bbase; + uint *b; + uint *btop; + + pool = pooltable[n]; + + bbase = pool.scan.base(); + btop = bbase + pool.scan.nwords; + for (b = bbase; b < btop;) + { Bins bin; + size_t pn; + size_t u; + size_t bitm; + byte* o; + + bitm = *b; + if (!bitm) + { b++; + continue; + } + *b = 0; + + o = pool.baseAddr + (b - bbase) * 32 * 16; + if (!(bitm & 0xFFFF)) + { + bitm >>= 16; + o += 16 * 16; + } + for (; bitm; o += 16, bitm >>= 1) + { + if (!(bitm & 1)) + continue; + + pn = cast(size_t)(o - pool.baseAddr) / PAGESIZE; + bin = cast(Bins)pool.pagetable[pn]; + if (bin < B_PAGE) + { + mark(o, o + binsize[bin]); + } + else if (bin == B_PAGE || bin == B_PAGEPLUS) + { + if (bin == B_PAGEPLUS) + { + while (pool.pagetable[pn - 1] != B_PAGE) + pn--; + } + u = 1; + while (pn + u < pool.ncommitted && pool.pagetable[pn + u] == B_PAGEPLUS) + u++; + mark(o, o + u * PAGESIZE); + } + } + } + } + } + + thread_resumeAll(); + + // Free up everything not marked + debug(COLLECT_PRINTF) printf("\tfree'ing\n"); + size_t freedpages = 0; + size_t freed = 0; + for (n = 0; n < npools; n++) + { size_t pn; + size_t ncommitted; + uint* bbase; + + pool = pooltable[n]; + bbase = pool.mark.base(); + ncommitted = pool.ncommitted; + for (pn = 0; pn < ncommitted; pn++, bbase += PAGESIZE / (32 * 16)) + { + Bins bin = cast(Bins)pool.pagetable[pn]; + + if (bin < B_PAGE) + { byte* p; + byte* ptop; + size_t biti; + size_t bitstride; + auto size = binsize[bin]; + + p = pool.baseAddr + pn * PAGESIZE; + ptop = p + PAGESIZE; + biti = pn * (PAGESIZE/16); + bitstride = size / 16; + + version(none) // BUG: doesn't work because freebits() must also be cleared + { + // If free'd entire page + if (bbase[0] == 0 && bbase[1] == 0 && bbase[2] == 0 && bbase[3] == 0 && + bbase[4] == 0 && bbase[5] == 0 && bbase[6] == 0 && bbase[7] == 0) + { + for (; p < ptop; p += size, biti += bitstride) + { + if (pool.finals.nbits && pool.finals.testClear(biti)) + rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/); + gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); + + List *list = cast(List *)p; + //debug(PRINTF) printf("\tcollecting %x\n", list); + log_free(sentinel_add(list)); + + debug (MEMSTOMP) memset(p, 0xF3, size); + } + pool.pagetable[pn] = B_FREE; + freed += PAGESIZE; + //debug(PRINTF) printf("freeing entire page %d\n", pn); + continue; + } + } + for (; p < ptop; p += size, biti += bitstride) + { + if (!pool.mark.test(biti)) + { + sentinel_Invariant(sentinel_add(p)); + + pool.freebits.set(biti); + if (pool.finals.nbits && pool.finals.testClear(biti)) + rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/); + clrBits(pool, biti, BlkAttr.ALL_BITS); + + List *list = cast(List *)p; + debug(PRINTF) printf("\tcollecting %x\n", list); + log_free(sentinel_add(list)); + + debug (MEMSTOMP) memset(p, 0xF3, size); + + freed += size; + } + } + } + else if (bin == B_PAGE) + { size_t biti = pn * (PAGESIZE / 16); + + if (!pool.mark.test(biti)) + { byte *p = pool.baseAddr + pn * PAGESIZE; + + sentinel_Invariant(sentinel_add(p)); + if (pool.finals.nbits && pool.finals.testClear(biti)) + rt_finalize(sentinel_add(p), false/*noStack > 0*/); + clrBits(pool, biti, BlkAttr.ALL_BITS); + + debug(COLLECT_PRINTF) printf("\tcollecting big %x\n", p); + log_free(sentinel_add(p)); + pool.pagetable[pn] = B_FREE; + freedpages++; + debug (MEMSTOMP) memset(p, 0xF3, PAGESIZE); + while (pn + 1 < ncommitted && pool.pagetable[pn + 1] == B_PAGEPLUS) + { + pn++; + pool.pagetable[pn] = B_FREE; + freedpages++; + + debug (MEMSTOMP) + { p += PAGESIZE; + memset(p, 0xF3, PAGESIZE); + } + } + } + } + } + } + + // Zero buckets + bucket[] = null; + + // Free complete pages, rebuild free list + debug(COLLECT_PRINTF) printf("\tfree complete pages\n"); + size_t recoveredpages = 0; + for (n = 0; n < npools; n++) + { size_t pn; + size_t ncommitted; + + pool = pooltable[n]; + ncommitted = pool.ncommitted; + for (pn = 0; pn < ncommitted; pn++) + { + Bins bin = cast(Bins)pool.pagetable[pn]; + size_t biti; + size_t u; + + if (bin < B_PAGE) + { + size_t size = binsize[bin]; + size_t bitstride = size / 16; + size_t bitbase = pn * (PAGESIZE / 16); + size_t bittop = bitbase + (PAGESIZE / 16); + byte* p; + + biti = bitbase; + for (biti = bitbase; biti < bittop; biti += bitstride) + { if (!pool.freebits.test(biti)) + goto Lnotfree; + } + pool.pagetable[pn] = B_FREE; + recoveredpages++; + continue; + + Lnotfree: + p = pool.baseAddr + pn * PAGESIZE; + for (u = 0; u < PAGESIZE; u += size) + { biti = bitbase + u / 16; + if (pool.freebits.test(biti)) + { List *list; + + list = cast(List *)(p + u); + if (list.next != bucket[bin]) // avoid unnecessary writes + list.next = bucket[bin]; + bucket[bin] = list; + } + } + } + } + } + + debug(COLLECT_PRINTF) printf("recovered pages = %d\n", recoveredpages); + debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedpages, npools); + + return freedpages + recoveredpages; + } + + + /** + * + */ + uint getBits(Pool* pool, size_t biti) + in + { + assert( pool ); + } + body + { + uint bits; + + if (pool.finals.nbits && + pool.finals.test(biti)) + bits |= BlkAttr.FINALIZE; + if (pool.noscan.test(biti)) + bits |= BlkAttr.NO_SCAN; +// if (pool.nomove.nbits && +// pool.nomove.test(biti)) +// bits |= BlkAttr.NO_MOVE; + return bits; + } + + + /** + * + */ + void setBits(Pool* pool, size_t biti, uint mask) + in + { + assert( pool ); + } + body + { + if (mask & BlkAttr.FINALIZE) + { + if (!pool.finals.nbits) + pool.finals.alloc(pool.mark.nbits); + pool.finals.set(biti); + } + if (mask & BlkAttr.NO_SCAN) + { + pool.noscan.set(biti); + } +// if (mask & BlkAttr.NO_MOVE) +// { +// if (!pool.nomove.nbits) +// pool.nomove.alloc(pool.mark.nbits); +// pool.nomove.set(biti); +// } + } + + + /** + * + */ + void clrBits(Pool* pool, size_t biti, uint mask) + in + { + assert( pool ); + } + body + { + if (mask & BlkAttr.FINALIZE && pool.finals.nbits) + pool.finals.clear(biti); + if (mask & BlkAttr.NO_SCAN) + pool.noscan.clear(biti); +// if (mask & BlkAttr.NO_MOVE && pool.nomove.nbits) +// pool.nomove.clear(biti); + } + + + /***** Leak Detector ******/ + + + debug (LOGGING) + { + LogArray current; + LogArray prev; + + + void log_init() + { + //debug(PRINTF) printf("+log_init()\n"); + current.reserve(1000); + prev.reserve(1000); + //debug(PRINTF) printf("-log_init()\n"); + } + + + void log_malloc(void *p, size_t size) + { + //debug(PRINTF) printf("+log_malloc(p = %x, size = %d)\n", p, size); + Log log; + + log.p = p; + log.size = size; + log.line = GC.line; + log.file = GC.file; + log.parent = null; + + GC.line = 0; + GC.file = null; + + current.push(log); + //debug(PRINTF) printf("-log_malloc()\n"); + } + + + void log_free(void *p) + { + //debug(PRINTF) printf("+log_free(%x)\n", p); + size_t i; + + i = current.find(p); + if (i == OPFAIL) + { + debug(PRINTF) printf("free'ing unallocated memory %x\n", p); + } + else + current.remove(i); + //debug(PRINTF) printf("-log_free()\n"); + } + + + void log_collect() + { + //debug(PRINTF) printf("+log_collect()\n"); + // Print everything in current that is not in prev + + debug(PRINTF) printf("New pointers this cycle: --------------------------------\n"); + size_t used = 0; + for (size_t i = 0; i < current.dim; i++) + { + size_t j; + + j = prev.find(current.data[i].p); + if (j == OPFAIL) + current.data[i].print(); + else + used++; + } + + debug(PRINTF) printf("All roots this cycle: --------------------------------\n"); + for (size_t i = 0; i < current.dim; i++) + { + void *p; + size_t j; + + p = current.data[i].p; + if (!findPool(current.data[i].parent)) + { + j = prev.find(current.data[i].p); + if (j == OPFAIL) + debug(PRINTF) printf("N"); + else + debug(PRINTF) printf(" ");; + current.data[i].print(); + } + } + + debug(PRINTF) printf("Used = %d-------------------------------------------------\n", used); + prev.copy(¤t); + + debug(PRINTF) printf("-log_collect()\n"); + } + + + void log_parent(void *p, void *parent) + { + //debug(PRINTF) printf("+log_parent()\n"); + size_t i; + + i = current.find(p); + if (i == OPFAIL) + { + debug(PRINTF) printf("parent'ing unallocated memory %x, parent = %x\n", p, parent); + Pool *pool; + pool = findPool(p); + assert(pool); + size_t offset = cast(size_t)(p - pool.baseAddr); + size_t biti; + size_t pn = offset / PAGESIZE; + Bins bin = cast(Bins)pool.pagetable[pn]; + biti = (offset & notbinsize[bin]); + debug(PRINTF) printf("\tbin = %d, offset = x%x, biti = x%x\n", bin, offset, biti); + } + else + { + current.data[i].parent = parent; + } + //debug(PRINTF) printf("-log_parent()\n"); + } + + } + else + { + void log_init() { } + void log_malloc(void *p, size_t size) { } + void log_free(void *p) { } + void log_collect() { } + void log_parent(void *p, void *parent) { } + } +} + + +/* ============================ Pool =============================== */ + + +struct Pool +{ + byte* baseAddr; + byte* topAddr; + GCBits mark; // entries already scanned, or should not be scanned + GCBits scan; // entries that need to be scanned + GCBits freebits; // entries that are on the free list + GCBits finals; // entries that need finalizer run on them + GCBits noscan; // entries that should not be scanned + + size_t npages; + size_t ncommitted; // ncommitted <= npages + ubyte* pagetable; + + + void initialize(size_t npages) + { + size_t poolsize; + + //debug(PRINTF) printf("Pool::Pool(%u)\n", npages); + poolsize = npages * PAGESIZE; + assert(poolsize >= POOLSIZE); + baseAddr = cast(byte *)os_mem_map(poolsize); + + // Some of the code depends on page alignment of memory pools + assert((cast(size_t)baseAddr & (PAGESIZE - 1)) == 0); + + if (!baseAddr) + { + //debug(PRINTF) printf("GC fail: poolsize = x%x, errno = %d\n", poolsize, errno); + //debug(PRINTF) printf("message = '%s'\n", sys_errlist[errno]); + + npages = 0; + poolsize = 0; + } + //assert(baseAddr); + topAddr = baseAddr + poolsize; + + mark.alloc(cast(size_t)poolsize / 16); + scan.alloc(cast(size_t)poolsize / 16); + freebits.alloc(cast(size_t)poolsize / 16); + noscan.alloc(cast(size_t)poolsize / 16); + + pagetable = cast(ubyte*)cstdlib.malloc(npages); + if (!pagetable) + onOutOfMemoryError(); + memset(pagetable, B_UNCOMMITTED, npages); + + this.npages = npages; + ncommitted = 0; + } + + + void Dtor() + { + if (baseAddr) + { + int result; + + if (ncommitted) + { + result = os_mem_decommit(baseAddr, 0, ncommitted * PAGESIZE); + assert(result == 0); + ncommitted = 0; + } + + if (npages) + { + result = os_mem_unmap(baseAddr, npages * PAGESIZE); + assert(result == 0); + npages = 0; + } + + baseAddr = null; + topAddr = null; + } + if (pagetable) + cstdlib.free(pagetable); + + mark.Dtor(); + scan.Dtor(); + freebits.Dtor(); + finals.Dtor(); + noscan.Dtor(); + } + + + void Invariant() { } + + + invariant + { + //mark.Invariant(); + //scan.Invariant(); + //freebits.Invariant(); + //finals.Invariant(); + //noscan.Invariant(); + + if (baseAddr) + { + //if (baseAddr + npages * PAGESIZE != topAddr) + //printf("baseAddr = %p, npages = %d, topAddr = %p\n", baseAddr, npages, topAddr); + assert(baseAddr + npages * PAGESIZE == topAddr); + assert(ncommitted <= npages); + } + + for (size_t i = 0; i < npages; i++) + { Bins bin = cast(Bins)pagetable[i]; + + assert(bin < B_MAX); + } + } + + + /** + * Allocate n pages from Pool. + * Returns OPFAIL on failure. + */ + size_t allocPages(size_t n) + { + size_t i; + size_t n2; + + //debug(PRINTF) printf("Pool::allocPages(n = %d)\n", n); + n2 = n; + for (i = 0; i < ncommitted; i++) + { + if (pagetable[i] == B_FREE) + { + if (--n2 == 0) + { //debug(PRINTF) printf("\texisting pn = %d\n", i - n + 1); + return i - n + 1; + } + } + else + n2 = n; + } + return extendPages(n); + } + + /** + * Extend Pool by n pages. + * Returns OPFAIL on failure. + */ + size_t extendPages(size_t n) + { + //debug(PRINTF) printf("Pool::extendPages(n = %d)\n", n); + if (ncommitted + n <= npages) + { + size_t tocommit; + + tocommit = (n + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1); + if (ncommitted + tocommit > npages) + tocommit = npages - ncommitted; + //debug(PRINTF) printf("\tlooking to commit %d more pages\n", tocommit); + //fflush(stdout); + if (os_mem_commit(baseAddr, ncommitted * PAGESIZE, tocommit * PAGESIZE) == 0) + { + memset(pagetable + ncommitted, B_FREE, tocommit); + auto i = ncommitted; + ncommitted += tocommit; + + while (i && pagetable[i - 1] == B_FREE) + i--; + + return i; + } + //debug(PRINTF) printf("\tfailed to commit %d pages\n", tocommit); + } + + return OPFAIL; + } + + + /** + * Free npages pages starting with pagenum. + */ + void freePages(size_t pagenum, size_t npages) + { + memset(&pagetable[pagenum], B_FREE, npages); + } + + + /** + * Used for sorting pooltable[] + */ + int opCmp(Pool *p2) + { + if (baseAddr < p2.baseAddr) + return -1; + else + return cast(int)(baseAddr > p2.baseAddr); + } +} + + +/* ============================ SENTINEL =============================== */ + + +version (SENTINEL) +{ + const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL; // 32 or 64 bits + const ubyte SENTINEL_POST = 0xF5; // 8 bits + const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1; + + + size_t* sentinel_size(void *p) { return &(cast(size_t *)p)[-2]; } + size_t* sentinel_pre(void *p) { return &(cast(size_t *)p)[-1]; } + ubyte* sentinel_post(void *p) { return &(cast(ubyte *)p)[*sentinel_size(p)]; } + + + void sentinel_init(void *p, size_t size) + { + *sentinel_size(p) = size; + *sentinel_pre(p) = SENTINEL_PRE; + *sentinel_post(p) = SENTINEL_POST; + } + + + void sentinel_Invariant(void *p) + { + assert(*sentinel_pre(p) == SENTINEL_PRE); + assert(*sentinel_post(p) == SENTINEL_POST); + } + + + void *sentinel_add(void *p) + { + return p + 2 * size_t.sizeof; + } + + + void *sentinel_sub(void *p) + { + return p - 2 * size_t.sizeof; + } +} +else +{ + const uint SENTINEL_EXTRA = 0; + + + void sentinel_init(void *p, size_t size) + { + } + + + void sentinel_Invariant(void *p) + { + } + + + void *sentinel_add(void *p) + { + return p; + } + + + void *sentinel_sub(void *p) + { + return p; + } +} diff --git a/src/gc/basic/posix.mak b/src/gc/basic/posix.mak new file mode 100644 index 0000000..432deb3 --- /dev/null +++ b/src/gc/basic/posix.mak @@ -0,0 +1,100 @@ +# Makefile to build the garbage collector D library for Posix +# Designed to work with GNU make +# Targets: +# make +# Same as make all +# make lib +# Build the garbage collector library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=libdruntime-gc-basic.a +LIB_MASK=libdruntime-gc-basic*.a + +CP=cp -f +RM=rm -f +MD=mkdir -p + +ADD_CFLAGS= +ADD_DFLAGS= + +CFLAGS=-O $(ADD_CFLAGS) +#CFLAGS=-g $(ADD_CFLAGS) + +DFLAGS=-release -O -inline -w -nofloat -version=Posix $(ADD_DFLAGS) +#DFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS) + +TFLAGS=-O -inline -w -nofloat -version=Posix $(ADD_DFLAGS) +#TFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS) + +DOCFLAGS=-version=DDoc -version=Posix + +CC=gcc +LC=$(AR) -qsv +DC=dmd + +LIB_DEST=../../../lib + +.SUFFIXES: .s .S .c .cpp .d .html .o + +.s.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.S.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.c.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.cpp.o: + g++ -c $(CFLAGS) $< -o$@ + +.d.o: + $(DC) -c $(DFLAGS) $< -of$@ + +.d.html: + $(DC) -c -o- $(DOCFLAGS) -Df$*.html $< +# $(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $< + +targets : lib doc +all : lib doc +lib : basic.lib +doc : basic.doc + +###################################################### + +ALL_OBJS= \ + gc.o \ + gcalloc.o \ + gcbits.o \ + gcstats.o \ + gcx.o + +###################################################### + +ALL_DOCS= + +###################################################### + +basic.lib : $(LIB_TARGET) + +$(LIB_TARGET) : $(ALL_OBJS) + $(RM) $@ + $(LC) $@ $(ALL_OBJS) + +basic.doc : $(ALL_DOCS) + echo No documentation available. + +###################################################### + +clean : + find . -name "*.di" | xargs $(RM) + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + $(RM) $(LIB_MASK) + +install : + $(MD) $(LIB_DEST) + $(CP) $(LIB_MASK) $(LIB_DEST)/. diff --git a/src/gc/basic/win32.mak b/src/gc/basic/win32.mak new file mode 100644 index 0000000..dd6b72f --- /dev/null +++ b/src/gc/basic/win32.mak @@ -0,0 +1,97 @@ +# Makefile to build the garbage collector D library for Win32 +# Designed to work with DigitalMars make +# Targets: +# make +# Same as make all +# make lib +# Build the garbage collector library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=druntime-gc-basic.lib +LIB_MASK=druntime-gc-basic*.lib + +CP=xcopy /y +RM=del /f +MD=mkdir + +ADD_CFLAGS= +ADD_DFLAGS= + +CFLAGS=-mn -6 -r $(ADD_CFLAGS) +#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS) + +DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS) +#DFLAGS=-g -w -nofloat $(ADD_DFLAGS) + +TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS) +#TFLAGS=-g -w -nofloat $(ADD_DFLAGS) + +DOCFLAGS=-version=DDoc + +CC=dmc +LC=lib +DC=dmd + +LIB_DEST=..\..\..\lib + +.DEFAULT: .asm .c .cpp .d .html .obj + +.asm.obj: + $(CC) -c $< + +.c.obj: + $(CC) -c $(CFLAGS) $< -o$@ + +.cpp.obj: + $(CC) -c $(CFLAGS) $< -o$@ + +.d.obj: + $(DC) -c $(DFLAGS) $< -of$@ + +.d.html: + $(DC) -c -o- $(DOCFLAGS) -Df$*.html $< +# $(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $< + +targets : lib doc +all : lib doc +lib : basic.lib +doc : basic.doc + +###################################################### + +ALL_OBJS= \ + gc.obj \ + gcalloc.obj \ + gcbits.obj \ + gcstats.obj \ + gcx.obj + +###################################################### + +ALL_DOCS= + +###################################################### + +basic.lib : $(LIB_TARGET) + +$(LIB_TARGET) : $(ALL_OBJS) + $(RM) $@ + $(LC) -c -n $@ $(ALL_OBJS) + +basic.doc : $(ALL_DOCS) + @echo No documentation available. + +###################################################### + +clean : + $(RM) /s *.di + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + $(RM) $(LIB_MASK) + +install : + $(MD) $(LIB_DEST) + $(CP) $(LIB_MASK) $(LIB_DEST)\. diff --git a/src/gc/stub/gc.d b/src/gc/stub/gc.d new file mode 100644 index 0000000..29e2686 --- /dev/null +++ b/src/gc/stub/gc.d @@ -0,0 +1,166 @@ +/** + * This module contains a minimal garbage collector implementation according to + * published requirements. This library is mostly intended to serve as an + * example, but it is usable in applications which do not rely on a garbage + * collector to clean up memory (ie. when dynamic array resizing is not used, + * and all memory allocated with 'new' is freed deterministically with + * 'delete'). + * + * Please note that block attribute data must be tracked, or at a minimum, the + * FINALIZE bit must be tracked for any allocated memory block because calling + * rt_finalize on a non-object block can result in an access violation. In the + * allocator below, this tracking is done via a leading uint bitmask. A real + * allocator may do better to store this data separately, similar to the basic + * GC. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + */ + +private import stdc.stdlib; + +private +{ + enum BlkAttr : uint + { + FINALIZE = 0b0000_0001, + NO_SCAN = 0b0000_0010, + NO_MOVE = 0b0000_0100, + ALL_BITS = 0b1111_1111 + } + + struct BlkInfo + { + void* base; + size_t size; + uint attr; + } + + extern (C) void thread_init(); + extern (C) void onOutOfMemoryError(); +} + +extern (C) void gc_init() +{ + // NOTE: The GC must initialize the thread library before its first + // collection, and always before returning from gc_init(). + thread_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 ) +{ + return 0; +} + +extern (C) uint gc_setAttr( void* p, uint a ) +{ + return 0; +} + +extern (C) uint gc_clrAttr( void* p, uint a ) +{ + return 0; +} + +extern (C) void* gc_malloc( size_t sz, uint ba = 0 ) +{ + void* p = malloc( sz ); + + if( sz && p is null ) + onOutOfMemoryError(); + return p; +} + +extern (C) void* gc_calloc( size_t sz, uint ba = 0 ) +{ + void* p = calloc( 1, sz ); + + if( sz && p is null ) + onOutOfMemoryError(); + return p; +} + +extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 ) +{ + p = realloc( p, sz ); + + if( sz && p is null ) + onOutOfMemoryError(); + return p; +} + +extern (C) size_t gc_extend( void* p, size_t mx, size_t sz ) +{ + return 0; +} + +extern (C) size_t gc_reserve( size_t sz ) +{ + return 0; +} + +extern (C) void gc_free( void* p ) +{ + free( p ); +} + +extern (C) void* gc_addrOf( void* p ) +{ + return null; +} + +extern (C) size_t gc_sizeOf( void* p ) +{ + return 0; +} + +extern (C) BlkInfo gc_query( void* p ) +{ + return BlkInfo.init; +} + +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 ) +{ + +} diff --git a/src/gc/stub/posix.mak b/src/gc/stub/posix.mak new file mode 100644 index 0000000..038233e --- /dev/null +++ b/src/gc/stub/posix.mak @@ -0,0 +1,98 @@ +# Makefile to build the garbage collector D library for Posix +# Designed to work with GNU make +# Targets: +# make +# Same as make all +# make lib +# Build the garbage collector library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=druntime-gc-stub.a +LIB_MASK=druntime-gc-stub*.a + +CP=cp -f +RM=rm -f +MD=mkdir -p + +ADD_CFLAGS= +ADD_DFLAGS= + +CFLAGS=-O -m32 $(ADD_CFLAGS) +#CFLAGS=-g -m32 $(ADD_CFLAGS) + +### warnings disabled because gcx has issues ### + +DFLAGS=-release -O -inline -version=Posix $(ADD_DFLAGS) +#DFLAGS=-g -version=Posix $(ADD_DFLAGS) + +TFLAGS=-O -inline -version=Posix $(ADD_DFLAGS) +#TFLAGS=-g -version=Posix $(ADD_DFLAGS) + +DOCFLAGS=-version=DDoc -version=Posix + +CC=gcc +LC=$(AR) -qsv +DC=dmd + +LIB_DEST=.. + +.SUFFIXES: .s .S .c .cpp .d .html .o + +.s.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.S.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.c.o: + $(CC) -c $(CFLAGS) $< -o$@ + +.cpp.o: + g++ -c $(CFLAGS) $< -o$@ + +.d.o: + $(DC) -c $(DFLAGS) $< -of$@ + +.d.html: + $(DC) -c -o- $(DOCFLAGS) -Df$*.html $< +# $(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $< + +targets : lib doc +all : lib doc +lib : stub.lib +doc : stub.doc + +###################################################### + +ALL_OBJS= \ + gc.o + +###################################################### + +ALL_DOCS= + +###################################################### + +stub.lib : $(LIB_TARGET) + +$(LIB_TARGET) : $(ALL_OBJS) + $(RM) $@ + $(LC) $@ $(ALL_OBJS) + +stub.doc : $(ALL_DOCS) + echo No documentation available. + +###################################################### + +clean : + find . -name "*.di" | xargs $(RM) + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + $(RM) $(LIB_MASK) + +install : + $(MD) $(LIB_DEST) + $(CP) $(LIB_MASK) $(LIB_DEST)/. diff --git a/src/gc/stub/win32.mak b/src/gc/stub/win32.mak new file mode 100644 index 0000000..9fc4e1a --- /dev/null +++ b/src/gc/stub/win32.mak @@ -0,0 +1,95 @@ +# Makefile to build the garbage collector D library for Win32 +# Designed to work with DigitalMars make +# Targets: +# make +# Same as make all +# make lib +# Build the garbage collector library +# make doc +# Generate documentation +# make clean +# Delete unneeded files created by build process + +LIB_TARGET=tango-gc-stub.lib +LIB_MASK=tango-gc-stub*.lib + +CP=xcopy /y +RM=del /f +MD=mkdir + +ADD_CFLAGS= +ADD_DFLAGS= + +CFLAGS=-mn -6 -r $(ADD_CFLAGS) +#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS) + +### warnings disabled because gcx has issues ### + +DFLAGS=-release -O -inline $(ADD_DFLAGS) +#DFLAGS=-g -release $(ADD_DFLAGS) + +TFLAGS=-O -inline $(ADD_DFLAGS) +#TFLAGS=-g $(ADD_DFLAGS) + +DOCFLAGS=-version=DDoc + +CC=dmc +LC=lib +DC=dmd + +LIB_DEST=.. + +.DEFAULT: .asm .c .cpp .d .html .obj + +.asm.obj: + $(CC) -c $< + +.c.obj: + $(CC) -c $(CFLAGS) $< -o$@ + +.cpp.obj: + $(CC) -c $(CFLAGS) $< -o$@ + +.d.obj: + $(DC) -c $(DFLAGS) $< -of$@ + +.d.html: + $(DC) -c -o- $(DOCFLAGS) -Df$*.html $< +# $(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $< + +targets : lib doc +all : lib doc +lib : stub.lib +doc : stub.doc + +###################################################### + +ALL_OBJS= \ + gc.obj + +###################################################### + +ALL_DOCS= + +###################################################### + +stub.lib : $(LIB_TARGET) + +$(LIB_TARGET) : $(ALL_OBJS) + $(RM) $@ + $(LC) -c -n $@ $(ALL_OBJS) + +stub.doc : $(ALL_DOCS) + @echo No documentation available. + +###################################################### + +clean : + $(RM) /s *.di + $(RM) $(ALL_OBJS) + $(RM) $(ALL_DOCS) + $(RM) $(LIB_MASK) + +install : + $(MD) $(LIB_DEST) + $(CP) $(LIB_MASK) $(LIB_DEST)\. diff --git a/src/sc.ini b/src/sc.ini new file mode 100644 index 0000000..caca7eb --- /dev/null +++ b/src/sc.ini @@ -0,0 +1,7 @@ +[Version] +version=7.51 Build 020 + +[Environment] +LIB=%@P%\..\lib;\dm\lib +DFLAGS="-I%HOME%\..\import" +LINKCMD=%@P%\..\..\dm\bin\link.exe -- 2.43.0