mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
949 lines
31 KiB
Diff
949 lines
31 KiB
Diff
Index: tango/core/rt/compiler/ldc/ldc/intrinsics.di
|
|
===================================================================
|
|
--- tango/core/rt/compiler/ldc/ldc/intrinsics.di (revision 5576)
|
|
+++ tango/core/rt/compiler/ldc/ldc/intrinsics.di (working copy)
|
|
@@ -101,8 +101,16 @@
|
|
// Note that, unlike the standard libc function, the llvm.memcpy.* intrinsics do
|
|
// not return a value, and takes an extra alignment argument.
|
|
|
|
-pragma(intrinsic, "llvm.memcpy.i#")
|
|
- void llvm_memcpy(T)(void* dst, void* src, T len, uint alignment);
|
|
+version(LDC_LLVMPre28)
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memcpy.i#")
|
|
+ void llvm_memcpy(T)(void* dst, void* src, T len, uint alignment);
|
|
+}
|
|
+else
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memcpy.p0i8.p0i8.i#")
|
|
+ void llvm_memcpy(T)(void* dst, void* src, T len, uint alignment, bool volatile_);
|
|
+}
|
|
|
|
deprecated {
|
|
alias llvm_memcpy!(uint) llvm_memcpy_i32;
|
|
@@ -116,8 +124,16 @@
|
|
// Note that, unlike the standard libc function, the llvm.memmove.* intrinsics
|
|
// do not return a value, and takes an extra alignment argument.
|
|
|
|
-pragma(intrinsic, "llvm.memmove.i#")
|
|
- void llvm_memmove(T)(void* dst, void* src, T len, uint alignment);
|
|
+version(LDC_LLVMPre28)
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memmove.i#")
|
|
+ void llvm_memmove(T)(void* dst, void* src, T len, uint alignment);
|
|
+}
|
|
+else
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memmove.p0i8.p0i8.i#")
|
|
+ void llvm_memmove(T)(void* dst, void* src, T len, uint alignment, bool volatile_);
|
|
+}
|
|
|
|
deprecated {
|
|
alias llvm_memmove!(uint) llvm_memmove_i32;
|
|
@@ -130,8 +146,16 @@
|
|
// Note that, unlike the standard libc function, the llvm.memset intrinsic does
|
|
// not return a value, and takes an extra alignment argument.
|
|
|
|
-pragma(intrinsic, "llvm.memset.i#")
|
|
- void llvm_memset(T)(void* dst, ubyte val, T len, uint alignment);
|
|
+version(LDC_LLVMPre28)
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memset.i#")
|
|
+ void llvm_memset(T)(void* dst, ubyte val, T len, uint alignment);
|
|
+}
|
|
+else
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memset.p0i8.i#")
|
|
+ void llvm_memset(T)(void* dst, ubyte val, T len, uint alignment, bool volatile_);
|
|
+}
|
|
|
|
deprecated {
|
|
alias llvm_memset!(uint) llvm_memset_i32;
|
|
Index: tango/core/rt/compiler/ldc/rt/lifetime.d
|
|
===================================================================
|
|
--- tango/core/rt/compiler/ldc/rt/lifetime.d (revision 5576)
|
|
+++ tango/core/rt/compiler/ldc/rt/lifetime.d (working copy)
|
|
@@ -241,7 +241,7 @@
|
|
}
|
|
|
|
/**
|
|
- * As _d_newarrayT, but
|
|
+ * As _d_newarrayT, but
|
|
* for when the array has a non-zero initializer.
|
|
*/
|
|
extern (C) void* _d_newarrayiT(TypeInfo ti, size_t length)
|
|
@@ -359,7 +359,7 @@
|
|
|
|
|
|
/**
|
|
- * As _d_newarraymT, but
|
|
+ * As _d_newarraymT, but
|
|
* for when the array has a non-zero initializer.
|
|
*/
|
|
extern (C) void* _d_newarraymiT(TypeInfo ti, int ndims, size_t* dims)
|
|
@@ -483,7 +483,7 @@
|
|
// if (p)
|
|
// {
|
|
// This assert on array consistency may fail with casts or in unions.
|
|
-// This function still does something sensible even if plength && !pdata.
|
|
+// This function still does something sensible even if plength && !pdata.
|
|
// assert(!plength || pdata);
|
|
|
|
if (pdata)
|
|
@@ -505,9 +505,9 @@
|
|
}
|
|
}
|
|
|
|
-/**
|
|
- *
|
|
- */
|
|
+/**
|
|
+ *
|
|
+ */
|
|
extern (C) void _d_callinterfacefinalizer(void *p)
|
|
{
|
|
if (p)
|
|
@@ -544,9 +544,9 @@
|
|
|
|
if (p) // not necessary if called from gc
|
|
{
|
|
- if (det)
|
|
- (cast(Object)p).dispose();
|
|
-
|
|
+ if (det)
|
|
+ (cast(Object)p).dispose();
|
|
+
|
|
ClassInfo** pc = cast(ClassInfo**)p;
|
|
|
|
if (*pc)
|
|
@@ -593,7 +593,7 @@
|
|
{
|
|
assert(ti);
|
|
// This assert on array consistency may fail with casts or in unions.
|
|
-// This function still does something sensible even if plength && !pdata.
|
|
+// This function still does something sensible even if plength && !pdata.
|
|
// assert(!plength || pdata);
|
|
}
|
|
body
|
|
@@ -651,7 +651,6 @@
|
|
return newdata;
|
|
}
|
|
|
|
-
|
|
/**
|
|
* Resize arrays for non-zero initializers.
|
|
* p pointer to array lvalue to be updated
|
|
@@ -664,7 +663,7 @@
|
|
in
|
|
{
|
|
// This assert on array consistency may fail with casts or in unions.
|
|
-// This function still does something sensible even if plength && !pdata.
|
|
+// This function still does something sensible even if plength && !pdata.
|
|
// assert(!plength || pdata);
|
|
}
|
|
body
|
|
@@ -786,6 +785,7 @@
|
|
return *cast(long*)px;
|
|
}
|
|
|
|
++/
|
|
|
|
/**
|
|
*
|
|
@@ -824,8 +824,8 @@
|
|
const size_t b=0; // flatness factor, how fast the extra space decreases with array size
|
|
const size_t a=100; // allocate at most a% of the requested size as extra space (rounding will change this)
|
|
const size_t minBits=1; // minimum bit size
|
|
-
|
|
|
|
+
|
|
static size_t log2plusB(size_t c)
|
|
{
|
|
// could use the bsr bit op
|
|
@@ -847,12 +847,12 @@
|
|
return newcap;
|
|
}
|
|
|
|
-
|
|
/**
|
|
- *
|
|
+ * Appends a single element to an array.
|
|
*/
|
|
-extern (C) byte[] _d_arrayappendcT(TypeInfo ti, ref byte[] x, ...)
|
|
+extern (C) byte[] _d_arrayappendcT(TypeInfo ti, void* array, void* element)
|
|
{
|
|
+ auto x = cast(byte[]*)array;
|
|
auto sizeelem = ti.next.tsize(); // array element size
|
|
auto info = gc_query(x.ptr);
|
|
auto length = x.length;
|
|
@@ -879,18 +879,19 @@
|
|
assert(newcap >= newlength * sizeelem);
|
|
newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
|
|
memcpy(newdata, x.ptr, length * sizeelem);
|
|
- (cast(void**)(&x))[1] = newdata;
|
|
+ (cast(void**)x)[1] = newdata;
|
|
}
|
|
L1:
|
|
- byte *argp = cast(byte *)(&ti + 2);
|
|
+ byte *argp = cast(byte *)element;
|
|
|
|
- *cast(size_t *)&x = newlength;
|
|
+ *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;
|
|
+ return *x;
|
|
}
|
|
|
|
+/+
|
|
|
|
/**
|
|
* Append dchar to char[]
|
|
@@ -1128,7 +1129,6 @@
|
|
return result;
|
|
}
|
|
|
|
-
|
|
/**
|
|
*
|
|
*/
|
|
Index: tango/core/rt/compiler/ldc/rt/arrayInit.d
|
|
===================================================================
|
|
--- tango/core/rt/compiler/ldc/rt/arrayInit.d (revision 5576)
|
|
+++ tango/core/rt/compiler/ldc/rt/arrayInit.d (working copy)
|
|
@@ -114,7 +114,10 @@
|
|
auto p = a;
|
|
auto end = a + na*nv;
|
|
while (p !is end) {
|
|
- llvm_memcpy(p,v,nv,0);
|
|
+ version(LDC_LLVMPre28)
|
|
+ llvm_memcpy(p,v,nv,0);
|
|
+ else
|
|
+ llvm_memcpy(p,v,nv,1, false);
|
|
p += nv;
|
|
}
|
|
}
|
|
@@ -164,7 +167,12 @@
|
|
if (dstlen != srclen)
|
|
throw new Exception("lengths don't match for array copy");
|
|
else if (dst+dstlen <= src || src+srclen <= dst)
|
|
- llvm_memcpy(dst, src, dstlen, 0);
|
|
+ {
|
|
+ version(LDC_LLVMPre28)
|
|
+ llvm_memcpy(dst, src, dstlen, 0);
|
|
+ else
|
|
+ llvm_memcpy(dst, src, dstlen, 1, false);
|
|
+ }
|
|
else
|
|
throw new Exception("overlapping array copy");
|
|
}
|
|
Index: tango/core/rt/compiler/ldc/rt/eh.d
|
|
===================================================================
|
|
--- tango/core/rt/compiler/ldc/rt/eh.d (revision 5576)
|
|
+++ tango/core/rt/compiler/ldc/rt/eh.d (working copy)
|
|
@@ -1,38 +1,34 @@
|
|
/**
|
|
* This module contains functions and structures required for
|
|
- * exception handling.
|
|
+ * dwarf exception handling with llvm
|
|
*/
|
|
module rt.eh;
|
|
|
|
-import ldc.cstdarg;
|
|
-import rt.compiler.util.console;
|
|
+//debug = EH_personality;
|
|
|
|
-// debug = EH_personality;
|
|
-
|
|
// current EH implementation works on x86
|
|
// if it has a working unwind runtime
|
|
version(X86) {
|
|
version(linux) version=X86_UNWIND;
|
|
version(darwin) version=X86_UNWIND;
|
|
version(solaris) version=X86_UNWIND;
|
|
- version(freebsd) version=X86_UNWIND;
|
|
}
|
|
version(X86_64) {
|
|
version(linux) version=X86_UNWIND;
|
|
version(darwin) version=X86_UNWIND;
|
|
version(solaris) version=X86_UNWIND;
|
|
- version(freebsd) version=X86_UNWIND;
|
|
}
|
|
|
|
//version = HP_LIBUNWIND;
|
|
|
|
private extern(C) void abort();
|
|
private extern(C) int printf(char*, ...);
|
|
-private extern(C) int vprintf(char*, va_list va);
|
|
+//private extern(C) int vprintf(char*, va_list va);
|
|
|
|
// D runtime functions
|
|
extern(C) {
|
|
- int _d_isbaseof(ClassInfo oc, ClassInfo c);
|
|
+// int _d_isbaseof(ClassInfo oc, ClassInfo c);
|
|
+ Object _d_dynamic_cast(Object o, ClassInfo c);
|
|
}
|
|
|
|
// libunwind headers
|
|
@@ -74,16 +70,19 @@
|
|
// interface to HP's libunwind from http://www.nongnu.org/libunwind/
|
|
version(HP_LIBUNWIND)
|
|
{
|
|
+ // Haven't checked whether and how it has _Unwind_Get{Text,Data}RelBase
|
|
+ pragma (msg, "HP_LIBUNWIND interface is out of date and untested");
|
|
+
|
|
void __libunwind_Unwind_Resume(_Unwind_Exception *);
|
|
_Unwind_Reason_Code __libunwind_Unwind_RaiseException(_Unwind_Exception *);
|
|
ptrdiff_t __libunwind_Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr
|
|
context);
|
|
- ptrdiff_t __libunwind_Unwind_GetIP(_Unwind_Context_Ptr context);
|
|
+ size_t __libunwind_Unwind_GetIP(_Unwind_Context_Ptr context);
|
|
ptrdiff_t __libunwind_Unwind_SetIP(_Unwind_Context_Ptr context,
|
|
ptrdiff_t new_value);
|
|
ptrdiff_t __libunwind_Unwind_SetGR(_Unwind_Context_Ptr context, int index,
|
|
ptrdiff_t new_value);
|
|
- ptrdiff_t __libunwind_Unwind_GetRegionStart(_Unwind_Context_Ptr context);
|
|
+ size_t __libunwind_Unwind_GetRegionStart(_Unwind_Context_Ptr context);
|
|
|
|
alias __libunwind_Unwind_Resume _Unwind_Resume;
|
|
alias __libunwind_Unwind_RaiseException _Unwind_RaiseException;
|
|
@@ -94,27 +93,30 @@
|
|
alias __libunwind_Unwind_SetGR _Unwind_SetGR;
|
|
alias __libunwind_Unwind_GetRegionStart _Unwind_GetRegionStart;
|
|
}
|
|
-else version(X86_UNWIND)
|
|
+else version(X86_UNWIND)
|
|
{
|
|
void _Unwind_Resume(_Unwind_Exception*);
|
|
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*);
|
|
ptrdiff_t _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context);
|
|
- ptrdiff_t _Unwind_GetIP(_Unwind_Context_Ptr context);
|
|
+ size_t _Unwind_GetIP(_Unwind_Context_Ptr context);
|
|
ptrdiff_t _Unwind_SetIP(_Unwind_Context_Ptr context, ptrdiff_t new_value);
|
|
ptrdiff_t _Unwind_SetGR(_Unwind_Context_Ptr context, int index,
|
|
ptrdiff_t new_value);
|
|
- ptrdiff_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
|
|
+ size_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
|
|
+
|
|
+ size_t _Unwind_GetTextRelBase(_Unwind_Context_Ptr);
|
|
+ size_t _Unwind_GetDataRelBase(_Unwind_Context_Ptr);
|
|
}
|
|
else
|
|
{
|
|
// runtime calls these directly
|
|
void _Unwind_Resume(_Unwind_Exception*)
|
|
{
|
|
- console("_Unwind_Resume is not implemented on this platform.\n");
|
|
+ printf("_Unwind_Resume is not implemented on this platform.\n");
|
|
}
|
|
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*)
|
|
{
|
|
- console("_Unwind_RaiseException is not implemented on this platform.\n");
|
|
+ printf("_Unwind_RaiseException is not implemented on this platform.\n");
|
|
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
|
|
}
|
|
}
|
|
@@ -122,14 +124,161 @@
|
|
}
|
|
|
|
// error and exit
|
|
-extern(C) private void fatalerror(char[] format)
|
|
+extern(C) private void fatalerror(char* format, ...)
|
|
{
|
|
- printf("Fatal error in EH code: %.*s\n", format.length, format.ptr);
|
|
+// va_list args;
|
|
+// va_start(args, format);
|
|
+ printf("Fatal error in EH code: ");
|
|
+// vprintf(format, args);
|
|
+ printf("\n");
|
|
abort();
|
|
}
|
|
|
|
|
|
-// helpers for reading certain DWARF data
|
|
+// DWARF EH encoding enum
|
|
+// See e.g. http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/dwarfext.html
|
|
+private enum : ubyte {
|
|
+ DW_EH_PE_omit = 0xff, // value is not present
|
|
+
|
|
+ // value format
|
|
+ DW_EH_PE_absptr = 0x00, // literal pointer
|
|
+ DW_EH_PE_uleb128 = 0x01,
|
|
+ DW_EH_PE_udata2 = 0x02, // unsigned 2-byte
|
|
+ DW_EH_PE_udata4 = 0x03,
|
|
+ DW_EH_PE_udata8 = 0x04,
|
|
+ DW_EH_PE_sleb128 = 0x09,
|
|
+ DW_EH_PE_sdata2 = 0x0a,
|
|
+ DW_EH_PE_sdata4 = 0x0b,
|
|
+ DW_EH_PE_sdata8 = 0x0c,
|
|
+
|
|
+ // value meaning
|
|
+ DW_EH_PE_pcrel = 0x10, // relative to program counter
|
|
+ DW_EH_PE_textrel = 0x20, // relative to .text
|
|
+ DW_EH_PE_datarel = 0x30, // relative to .got or .eh_frame_hdr
|
|
+ DW_EH_PE_funcrel = 0x40, // relative to beginning of function
|
|
+ DW_EH_PE_aligned = 0x50, // is an aligned void*
|
|
+
|
|
+ // value is a pointer to the actual value
|
|
+ // this is a mask on top of one of the above
|
|
+ DW_EH_PE_indirect = 0x80
|
|
+}
|
|
+
|
|
+// Helpers for reading DWARF data
|
|
+
|
|
+// Given an encoding and a context, return the base to which the encoding is
|
|
+// relative
|
|
+private size_t base_of_encoded(_Unwind_Context_Ptr context, ubyte encoding)
|
|
+{
|
|
+ if (encoding == DW_EH_PE_omit)
|
|
+ return 0;
|
|
+
|
|
+ switch (encoding & 0x70) // ignore DW_EH_PE_indirect
|
|
+ {
|
|
+ case DW_EH_PE_absptr, DW_EH_PE_pcrel, DW_EH_PE_aligned:
|
|
+ return 0;
|
|
+
|
|
+ case DW_EH_PE_textrel: return _Unwind_GetTextRelBase(context);
|
|
+ case DW_EH_PE_datarel: return _Unwind_GetDataRelBase(context);
|
|
+ case DW_EH_PE_funcrel: return _Unwind_GetRegionStart(context);
|
|
+
|
|
+ default: fatalerror("Unrecognized base for DWARF value");
|
|
+ }
|
|
+}
|
|
+
|
|
+// Only defined for fixed-size encodings
|
|
+private size_t size_of_encoded(ubyte encoding)
|
|
+{
|
|
+ if (encoding == DW_EH_PE_omit)
|
|
+ return 0;
|
|
+
|
|
+ switch (encoding & 0x07) // ignore leb128
|
|
+ {
|
|
+ case DW_EH_PE_absptr: return (void*).sizeof;
|
|
+ case DW_EH_PE_udata2: return 2;
|
|
+ case DW_EH_PE_udata4: return 4;
|
|
+ case DW_EH_PE_udata8: return 8;
|
|
+
|
|
+ default: fatalerror("Unrecognized fixed-size DWARF value encoding");
|
|
+ }
|
|
+}
|
|
+
|
|
+// Actual value readers below: read a value from the given ubyte* into the
|
|
+// output parameter and return the pointer incremented past the value.
|
|
+
|
|
+// Like read_encoded_with_base but gets the base from the given context
|
|
+private ubyte* read_encoded(_Unwind_Context_Ptr context, ubyte encoding, ubyte* p, out size_t val)
|
|
+{
|
|
+ return read_encoded_with_base(encoding, base_of_encoded(context, encoding), p, val);
|
|
+}
|
|
+
|
|
+private ubyte* read_encoded_with_base(ubyte encoding, size_t base, ubyte* p, out size_t val)
|
|
+{
|
|
+ if (encoding == DW_EH_PE_aligned)
|
|
+ {
|
|
+ auto a = cast(size_t)p;
|
|
+ a = (a + (void*).sizeof - 1) & -(void*).sizeof;
|
|
+ val = *cast(size_t*)a;
|
|
+ return cast(ubyte*)(a + (void*).sizeof);
|
|
+ }
|
|
+
|
|
+ union U
|
|
+ {
|
|
+ size_t ptr;
|
|
+ ushort udata2;
|
|
+ uint udata4;
|
|
+ ulong udata8;
|
|
+ short sdata2;
|
|
+ int sdata4;
|
|
+ long sdata8;
|
|
+ }
|
|
+
|
|
+ auto u = cast(U*)p;
|
|
+
|
|
+ size_t result;
|
|
+
|
|
+ switch (encoding & 0x0f)
|
|
+ {
|
|
+ case DW_EH_PE_absptr:
|
|
+ result = u.ptr;
|
|
+ p += (void*).sizeof;
|
|
+ break;
|
|
+
|
|
+ case DW_EH_PE_uleb128:
|
|
+ {
|
|
+ p = get_uleb128(p, result);
|
|
+ break;
|
|
+ }
|
|
+ case DW_EH_PE_sleb128:
|
|
+ {
|
|
+ ptrdiff_t sleb128;
|
|
+ p = get_sleb128(p, sleb128);
|
|
+ result = cast(size_t)sleb128;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case DW_EH_PE_udata2: result = cast(size_t)u.udata2; p += 2; break;
|
|
+ case DW_EH_PE_udata4: result = cast(size_t)u.udata4; p += 4; break;
|
|
+ case DW_EH_PE_udata8: result = cast(size_t)u.udata8; p += 8; break;
|
|
+ case DW_EH_PE_sdata2: result = cast(size_t)u.sdata2; p += 2; break;
|
|
+ case DW_EH_PE_sdata4: result = cast(size_t)u.sdata4; p += 4; break;
|
|
+ case DW_EH_PE_sdata8: result = cast(size_t)u.sdata8; p += 8; break;
|
|
+
|
|
+ default: fatalerror("Unrecognized DWARF value encoding format");
|
|
+ }
|
|
+ if (result)
|
|
+ {
|
|
+ if ((encoding & 0x70) == DW_EH_PE_pcrel)
|
|
+ result += cast(size_t)u;
|
|
+ else
|
|
+ result += base;
|
|
+
|
|
+ if (encoding & DW_EH_PE_indirect)
|
|
+ result = *cast(size_t*)result;
|
|
+ }
|
|
+ val = result;
|
|
+ return p;
|
|
+}
|
|
+
|
|
private ubyte* get_uleb128(ubyte* addr, ref size_t res)
|
|
{
|
|
res = 0;
|
|
@@ -137,7 +286,7 @@
|
|
|
|
// read as long as high bit is set
|
|
while(*addr & 0x80) {
|
|
- res |= (*addr & 0x7f) << bitsize;
|
|
+ res |= (*addr & 0x7fU) << bitsize;
|
|
bitsize += 7;
|
|
addr += 1;
|
|
if(bitsize >= size_t.sizeof*8)
|
|
@@ -153,12 +302,12 @@
|
|
|
|
private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res)
|
|
{
|
|
- res = 0;
|
|
+ size_t tres = 0;
|
|
size_t bitsize = 0;
|
|
|
|
// read as long as high bit is set
|
|
while(*addr & 0x80) {
|
|
- res |= (*addr & 0x7f) << bitsize;
|
|
+ tres |= (*addr & 0x7fU) << bitsize;
|
|
bitsize += 7;
|
|
addr += 1;
|
|
if(bitsize >= size_t.sizeof*8)
|
|
@@ -167,12 +316,14 @@
|
|
// read last
|
|
if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
|
|
fatalerror("tried to read sleb128 that exceeded size of size_t");
|
|
- res |= (*addr) << bitsize;
|
|
+ tres |= (*addr) << bitsize;
|
|
|
|
// take care of sign
|
|
- if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40))
|
|
- res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1);
|
|
+ if(bitsize < size_t.sizeof*8 && (*addr & 0x40U) != 0)
|
|
+ tres |= cast(size_t)(-1) ^ ((1 << (bitsize+7)) - 1);
|
|
|
|
+ res = cast(ptrdiff_t)tres;
|
|
+
|
|
return addr + 1;
|
|
}
|
|
|
|
@@ -190,8 +341,7 @@
|
|
|
|
// the 8-byte string identifying the type of exception
|
|
// the first 4 are for vendor, the second 4 for language
|
|
-//TODO: This may be the wrong way around
|
|
-const char[8] _d_exception_class = "LLDCD1\0\0";
|
|
+const char[8] _d_exception_class = "LDC_D_10";
|
|
|
|
|
|
//
|
|
@@ -201,118 +351,174 @@
|
|
version(X86_UNWIND)
|
|
{
|
|
|
|
+// Various stuff we need
|
|
+struct Region
|
|
+{
|
|
+ ubyte* callsite_table;
|
|
+ ubyte* action_table;
|
|
+
|
|
+ // Note: classinfo_table points past the end of the table
|
|
+ ubyte* classinfo_table;
|
|
+
|
|
+ size_t start;
|
|
+ size_t lpStart_base; // landing pad base
|
|
+
|
|
+ ubyte ttypeEnc;
|
|
+ size_t ttype_base; // typeinfo base
|
|
+
|
|
+ ubyte callSiteEnc;
|
|
+}
|
|
+
|
|
// the personality routine gets called by the unwind handler and is responsible for
|
|
// reading the EH tables and deciding what to do
|
|
extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context)
|
|
{
|
|
+ debug(EH_personality) printf("Entering personality routine, context=%p\n", context);
|
|
// check ver: the C++ Itanium ABI only allows ver == 1
|
|
if(ver != 1)
|
|
+ {
|
|
+ debug(EH_personality) printf("eh version mismatch\n");
|
|
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
|
|
+ }
|
|
|
|
// check exceptionClass
|
|
//TODO: Treat foreign exceptions with more respect
|
|
- if((cast(char*)&exception_class)[0..8] != _d_exception_class)
|
|
+ auto wanted_ec = *cast(ulong*)_d_exception_class.ptr;
|
|
+ if(exception_class != wanted_ec)
|
|
+ {
|
|
+ debug(EH_personality) printf("exception class mismatch %p vs %p\n", exception_class, wanted_ec);
|
|
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
|
|
+ }
|
|
|
|
// find call site table, action table and classinfo table
|
|
// Note: callsite and action tables do not contain static-length
|
|
// data and will be parsed as needed
|
|
- // Note: classinfo_table points past the end of the table
|
|
- ubyte* callsite_table;
|
|
- ubyte* action_table;
|
|
- ClassInfo* classinfo_table;
|
|
- _d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table);
|
|
- if (!callsite_table)
|
|
+
|
|
+ Region region;
|
|
+
|
|
+ _d_getLanguageSpecificTables(context, region);
|
|
+
|
|
+ // workaround. this should not happen
|
|
+ if (!region.callsite_table)
|
|
+ {
|
|
+ debug(EH_personality) printf("callsite_table is null\n");
|
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
|
+ }
|
|
|
|
+ debug(EH_personality) printf("yay, checking\n");
|
|
+ debug(EH_personality) printf("region.start = %p\n", region.start);
|
|
+
|
|
/*
|
|
find landing pad and action table index belonging to ip by walking
|
|
the callsite_table
|
|
*/
|
|
- ubyte* callsite_walker = callsite_table;
|
|
+ ubyte* callsite_walker = region.callsite_table;
|
|
+ debug(EH_personality) printf("callsite table at: %p\n", region.callsite_table);
|
|
+ debug(EH_personality) printf("action table at: %p\n", region.action_table);
|
|
+ debug(EH_personality) printf("rtti table at %p\n", region.classinfo_table);
|
|
|
|
// get the instruction pointer
|
|
// will be used to find the right entry in the callsite_table
|
|
// -1 because it will point past the last instruction
|
|
- ptrdiff_t ip = _Unwind_GetIP(context) - 1;
|
|
+ debug(EH_personality) printf("check1\n");
|
|
+ size_t ip = _Unwind_GetIP(context) - 1;
|
|
+ debug(EH_personality) printf("check2\n");
|
|
|
|
- // address block_start is relative to
|
|
- ptrdiff_t region_start = _Unwind_GetRegionStart(context);
|
|
-
|
|
// table entries
|
|
- uint block_start_offset, block_size;
|
|
- ptrdiff_t landing_pad;
|
|
+ size_t landing_pad;
|
|
size_t action_offset;
|
|
|
|
while(true) {
|
|
// if we've gone through the list and found nothing...
|
|
- if(callsite_walker >= action_table)
|
|
+ if(callsite_walker >= region.action_table)
|
|
+ {
|
|
+ debug(EH_personality) printf("found nothing\n");
|
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
|
+ }
|
|
|
|
- block_start_offset = *cast(uint*)callsite_walker;
|
|
- block_size = *(cast(uint*)callsite_walker + 1);
|
|
- landing_pad = *(cast(uint*)callsite_walker + 2);
|
|
- if(landing_pad)
|
|
- landing_pad += region_start;
|
|
- callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset);
|
|
+ size_t block_start, block_size;
|
|
|
|
- debug(EH_personality_verbose) printf("ip=%llx %d %d %llx\n", ip, block_start_offset, block_size, landing_pad);
|
|
+ callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, block_start);
|
|
+ callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, block_size);
|
|
+ callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, landing_pad);
|
|
+ callsite_walker = get_uleb128(callsite_walker, action_offset);
|
|
|
|
+ debug(EH_personality) printf("*block start offset = %p\n", block_start);
|
|
+ debug(EH_personality) printf(" block size = %p\n", block_size);
|
|
+ debug(EH_personality) printf(" landing pad = %p\n", landing_pad);
|
|
+ debug(EH_personality) printf(" ip=%p %p %p %p\n", ip, block_start, block_size, landing_pad);
|
|
+
|
|
// since the list is sorted, as soon as we're past the ip
|
|
// there's no handler to be found
|
|
- if(ip < region_start + block_start_offset)
|
|
+ if(ip < region.start + block_start)
|
|
+ {
|
|
+ debug(EH_personality) printf("found nothing2\n");
|
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
|
+ }
|
|
|
|
+ if(landing_pad)
|
|
+ landing_pad += region.lpStart_base;
|
|
+
|
|
// if we've found our block, exit
|
|
- if(ip < region_start + block_start_offset + block_size)
|
|
+ if(ip < region.start + block_start + block_size)
|
|
break;
|
|
}
|
|
|
|
- debug(EH_personality) printf("Found correct landing pad and actionOffset %d\n", action_offset);
|
|
+ debug(EH_personality) printf("Found correct landing pad %p and actionOffset %p\n", landing_pad, action_offset);
|
|
|
|
// now we need the exception's classinfo to find a handler
|
|
// the exception_info is actually a member of a larger _d_exception struct
|
|
// the runtime allocated. get that now
|
|
- _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof);
|
|
+ _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - size_t.sizeof); //_d_exception.unwind_info.offsetof);
|
|
|
|
// if there's no action offset and no landing pad, continue unwinding
|
|
if(!action_offset && !landing_pad)
|
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
|
|
|
// if there's no action offset but a landing pad, this is a cleanup handler
|
|
- else if(!action_offset && landing_pad)
|
|
- return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
|
|
+ else if(!action_offset && landing_pad != 0)
|
|
+ {
|
|
+ debug(EH_personality) printf("installing finally context\n");
|
|
+ return _d_eh_install_finally_context(actions, cast(ptrdiff_t)landing_pad, exception_struct, context);
|
|
+ }
|
|
|
|
/*
|
|
walk action table chain, comparing classinfos using _d_isbaseof
|
|
*/
|
|
- ubyte* action_walker = action_table + action_offset - 1;
|
|
+ ubyte* action_walker = region.action_table + action_offset - 1;
|
|
|
|
- ptrdiff_t ti_offset, next_action_offset;
|
|
while(true) {
|
|
+ ptrdiff_t ti_offset, next_action_offset;
|
|
+
|
|
action_walker = get_sleb128(action_walker, ti_offset);
|
|
// it is intentional that we not modify action_walker here
|
|
// next_action_offset is from current action_walker position
|
|
get_sleb128(action_walker, next_action_offset);
|
|
|
|
// negative are 'filters' which we don't use
|
|
- if(!(ti_offset >= 0))
|
|
+ if(ti_offset < 0)
|
|
fatalerror("Filter actions are unsupported");
|
|
|
|
// zero means cleanup, which we require to be the last action
|
|
if(ti_offset == 0) {
|
|
- if(!(next_action_offset == 0))
|
|
+ if(next_action_offset != 0)
|
|
fatalerror("Cleanup action must be last in chain");
|
|
- return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
|
|
+ return _d_eh_install_finally_context(actions, cast(ptrdiff_t)landing_pad, exception_struct, context);
|
|
}
|
|
|
|
// get classinfo for action and check if the one in the
|
|
// exception structure is a base
|
|
- ClassInfo catch_ci = *(classinfo_table - ti_offset);
|
|
- debug(EH_personality) printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr);
|
|
- if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci))
|
|
- return _d_eh_install_catch_context(actions, ti_offset, landing_pad, exception_struct, context);
|
|
+ size_t typeinfo;
|
|
+ auto filter = cast(size_t)ti_offset * size_of_encoded(region.ttypeEnc);
|
|
+ read_encoded_with_base(region.ttypeEnc, region.ttype_base, region.classinfo_table - filter, typeinfo);
|
|
|
|
+ debug(EH_personality)
|
|
+ printf("classinfo at %zx (enc %zx (size %zx) base %zx ptr %zx)\n", typeinfo, region.ttypeEnc, size_of_encoded(region.ttypeEnc), region.ttype_base, region.classinfo_table - filter);
|
|
+
|
|
+ auto catch_ci = *cast(ClassInfo*)&typeinfo;
|
|
+ if(_d_dynamic_cast(exception_struct.exception_object, catch_ci) !is null)
|
|
+ return _d_eh_install_catch_context(actions, ti_offset, cast(ptrdiff_t)landing_pad, exception_struct, context);
|
|
+
|
|
// we've walked through all actions and found nothing...
|
|
if(next_action_offset == 0)
|
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
|
@@ -356,6 +562,7 @@
|
|
}
|
|
|
|
fatalerror("reached unreachable");
|
|
+
|
|
return _Unwind_Reason_Code.FATAL_PHASE2_ERROR;
|
|
}
|
|
|
|
@@ -370,56 +577,78 @@
|
|
_Unwind_SetGR(context, eh_exception_regno, cast(ptrdiff_t)exception_struct);
|
|
_Unwind_SetGR(context, eh_selector_regno, 0);
|
|
_Unwind_SetIP(context, landing_pad);
|
|
+
|
|
return _Unwind_Reason_Code.INSTALL_CONTEXT;
|
|
}
|
|
|
|
-private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci)
|
|
+private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, out Region region)
|
|
{
|
|
- ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
|
|
+ auto data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
|
|
+
|
|
+ // workaround. this should not be 0...
|
|
if (!data)
|
|
{
|
|
- callsite = null;
|
|
- action = null;
|
|
- ci = null;
|
|
- return;
|
|
+ //printf("language specific data is null\n");
|
|
+ return;
|
|
}
|
|
|
|
- //TODO: Do proper DWARF reading here
|
|
- if(*data++ != 0xff)
|
|
- fatalerror("DWARF header has unexpected format 1");
|
|
+ region.start = _Unwind_GetRegionStart(context);
|
|
|
|
- if(*data++ != 0x00)
|
|
- fatalerror("DWARF header has unexpected format 2");
|
|
- size_t cioffset;
|
|
- data = get_uleb128(data, cioffset);
|
|
- ci = cast(ClassInfo*)(data + cioffset);
|
|
+ // Read the C++-style LSDA: this is implementation-defined by GCC but LLVM
|
|
+ // outputs the same kind of table
|
|
|
|
- if(*data++ != 0x03)
|
|
- fatalerror("DWARF header has unexpected format 3");
|
|
- size_t callsitelength;
|
|
- data = get_uleb128(data, callsitelength);
|
|
- action = data + callsitelength;
|
|
+ // Get @LPStart: landing pad offsets are relative to it
|
|
+ auto lpStartEnc = *data++;
|
|
+ if (lpStartEnc == DW_EH_PE_omit)
|
|
+ region.lpStart_base = region.start;
|
|
+ else
|
|
+ data = read_encoded(context, lpStartEnc, data, region.lpStart_base);
|
|
|
|
- callsite = data;
|
|
+ // Get @TType: the offset to the handler and typeinfo
|
|
+ region.ttypeEnc = *data++;
|
|
+ if (region.ttypeEnc == DW_EH_PE_omit)
|
|
+ // Not sure about this one...
|
|
+ fatalerror("@TType must not be omitted from DWARF header");
|
|
+
|
|
+ size_t ciOffset;
|
|
+ data = get_uleb128(data, ciOffset);
|
|
+ region.classinfo_table = data + ciOffset;
|
|
+
|
|
+ region.ttype_base = base_of_encoded(context, region.ttypeEnc);
|
|
+
|
|
+ // Get encoding and length of the call site table, which precedes the action
|
|
+ // table.
|
|
+ region.callSiteEnc = *data++;
|
|
+ if (region.callSiteEnc == DW_EH_PE_omit)
|
|
+ fatalerror("Call site table encoding must not be omitted from DWARF header");
|
|
+
|
|
+ size_t callSiteLength;
|
|
+ region.callsite_table = get_uleb128(data, callSiteLength);
|
|
+ region.action_table = region.callsite_table + callSiteLength;
|
|
}
|
|
|
|
} // end of x86 Linux specific implementation
|
|
|
|
-
|
|
-extern(C) void _d_throw_exception(Object e)
|
|
+// called to throw object
|
|
+extern(C)
|
|
+void _d_throw_exception(Object e)
|
|
{
|
|
+ //printf("throwing %p, rtti = %p\n", e, **cast(ClassRTTI***)e);
|
|
if (e !is null)
|
|
{
|
|
_d_exception* exc_struct = new _d_exception;
|
|
exc_struct.unwind_info.exception_class = *cast(ulong*)_d_exception_class.ptr;
|
|
exc_struct.exception_object = e;
|
|
_Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info);
|
|
- console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
|
|
+ printf("Error: returned %d from raise exception.\n", ret);
|
|
+ //console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
|
|
}
|
|
abort();
|
|
}
|
|
|
|
-extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct)
|
|
+// called to resume unwinding
|
|
+extern(C)
|
|
+void _d_eh_resume_unwind(void* exception_struct)
|
|
{
|
|
- _Unwind_Resume(&exception_struct.unwind_info);
|
|
+ _Unwind_Resume(&(cast(_d_exception*)exception_struct).unwind_info);
|
|
}
|
|
Index: tango/core/vendor/ldc/intrinsics.di
|
|
===================================================================
|
|
--- tango/core/vendor/ldc/intrinsics.di (revision 5576)
|
|
+++ tango/core/vendor/ldc/intrinsics.di (working copy)
|
|
@@ -101,8 +101,16 @@
|
|
// Note that, unlike the standard libc function, the llvm.memcpy.* intrinsics do
|
|
// not return a value, and takes an extra alignment argument.
|
|
|
|
-pragma(intrinsic, "llvm.memcpy.i#")
|
|
- void llvm_memcpy(T)(void* dst, void* src, T len, uint alignment);
|
|
+version(LDC_LLVMPre28)
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memcpy.i#")
|
|
+ void llvm_memcpy(T)(void* dst, void* src, T len, uint alignment);
|
|
+}
|
|
+else
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memcpy.p0i8.p0i8.i#")
|
|
+ void llvm_memcpy(T)(void* dst, void* src, T len, uint alignment, bool volatile_);
|
|
+}
|
|
|
|
deprecated {
|
|
alias llvm_memcpy!(uint) llvm_memcpy_i32;
|
|
@@ -116,8 +124,16 @@
|
|
// Note that, unlike the standard libc function, the llvm.memmove.* intrinsics
|
|
// do not return a value, and takes an extra alignment argument.
|
|
|
|
-pragma(intrinsic, "llvm.memmove.i#")
|
|
- void llvm_memmove(T)(void* dst, void* src, T len, uint alignment);
|
|
+version(LDC_LLVMPre28)
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memmove.i#")
|
|
+ void llvm_memmove(T)(void* dst, void* src, T len, uint alignment);
|
|
+}
|
|
+else
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memmove.p0i8.p0i8.i#")
|
|
+ void llvm_memmove(T)(void* dst, void* src, T len, uint alignment, bool volatile_);
|
|
+}
|
|
|
|
deprecated {
|
|
alias llvm_memmove!(uint) llvm_memmove_i32;
|
|
@@ -130,8 +146,16 @@
|
|
// Note that, unlike the standard libc function, the llvm.memset intrinsic does
|
|
// not return a value, and takes an extra alignment argument.
|
|
|
|
-pragma(intrinsic, "llvm.memset.i#")
|
|
- void llvm_memset(T)(void* dst, ubyte val, T len, uint alignment);
|
|
+version(LDC_LLVMPre28)
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memset.i#")
|
|
+ void llvm_memset(T)(void* dst, ubyte val, T len, uint alignment);
|
|
+}
|
|
+else
|
|
+{
|
|
+ pragma(intrinsic, "llvm.memset.p0i8.i#")
|
|
+ void llvm_memset(T)(void* dst, ubyte val, T len, uint alignment, bool volatile_);
|
|
+}
|
|
|
|
deprecated {
|
|
alias llvm_memset!(uint) llvm_memset_i32;
|