diff --git a/src/core/cpuid.d b/src/core/cpuid.d index d8ebcaed04..918b28d495 100644 --- a/src/core/cpuid.d +++ b/src/core/cpuid.d @@ -845,7 +845,7 @@ bool hasCPUID() return true; else version(LDC) { size_t flags; - asm { + asm @nogc nothrow { pushf; pop EAX; mov flags, EAX; diff --git a/src/ldc/eh/common.d b/src/ldc/eh/common.d index 722ce7e39d..15981594af 100644 --- a/src/ldc/eh/common.d +++ b/src/ldc/eh/common.d @@ -30,7 +30,7 @@ extern(C) void fatalerror(in char* format, ...) // Reading DWARF data // ------------------------ -version (Win64) {} else +version (CRuntime_Microsoft) {} else { extern(C) { @@ -195,15 +195,15 @@ ubyte* get_encoded_value(ubyte* addr, ref size_t res, ubyte encoding, void* cont res += cast(size_t)old_addr; break; case _DW_EH_Format.DW_EH_PE_funcrel: - version(Win64) fatalerror("Not yet implemented."); else + version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else res += cast(size_t)_Unwind_GetRegionStart(context); break; case _DW_EH_Format.DW_EH_PE_textrel: - version(Win64) fatalerror("Not yet implemented."); else + version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else res += cast(size_t)_Unwind_GetTextRelBase(context); break; case _DW_EH_Format.DW_EH_PE_datarel: - version(Win64) fatalerror("Not yet implemented."); else + version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else res += cast(size_t)_Unwind_GetDataRelBase(context); break; default: @@ -231,7 +231,7 @@ ptrdiff_t get_base_of_encoded_value(ubyte encoding, void* context) case DW_EH_PE_aligned: return 0; - version(Win64) {} else + version(CRuntime_Microsoft) {} else { case DW_EH_PE_textrel: return _Unwind_GetTextRelBase (context); diff --git a/src/ldc/eh/win32.d b/src/ldc/eh/win32.d new file mode 100644 index 0000000000..d68c2a2064 --- /dev/null +++ b/src/ldc/eh/win32.d @@ -0,0 +1,232 @@ +/** + * This module implements the runtime-part of LDC exceptions + * on Windows win32. + */ +module ldc.eh.win32; + +version(CRuntime_Microsoft): +version(Win32): + +import ldc.eh.common; +import core.sys.windows.windows; +import core.exception : onOutOfMemoryError; +import core.stdc.stdlib : malloc; +import core.stdc.string : memcpy; + +// pointers are image relative for Win64 versions +version(Win64) + alias ImgPtr(T) = uint; // offset into image +else + alias ImgPtr(T) = T; + +alias PMFN = ImgPtr!(void function(void*)); + +struct TypeDescriptor(int N) +{ + version(_RTTI) + const void * pVFTable; // Field overloaded by RTTI + else + uint hash; // Hash value computed from type's decorated name + + void * spare; // reserved, possible for RTTI + char[N+1] name; // variable size, zero terminated +} + +struct PMD +{ + int mdisp; // Offset of intended data within base + int pdisp; // Displacement to virtual base pointer + int vdisp; // Index within vbTable to offset of base +} + +struct CatchableType +{ + uint properties; // Catchable Type properties (Bit field) + ImgPtr!(TypeDescriptor!1*) pType; // Pointer to TypeDescriptor + PMD thisDisplacement; // Pointer to instance of catch type within thrown object. + int sizeOrOffset; // Size of simple-type object or offset into buffer of 'this' pointer for catch object + PMFN copyFunction; // Copy constructor or CC-closure +} + +enum CT_IsSimpleType = 0x00000001; // type is a simple type (includes pointers) +enum CT_ByReferenceOnly = 0x00000002; // type must be caught by reference +enum CT_HasVirtualBase = 0x00000004; // type is a class with virtual bases +enum CT_IsWinRTHandle = 0x00000008; // type is a winrt handle +enum CT_IsStdBadAlloc = 0x00000010; // type is a a std::bad_alloc + +struct CatchableTypeArray +{ + int nCatchableTypes; + ImgPtr!(CatchableType*)[2] arrayOfCatchableTypes; +} + +struct _ThrowInfo +{ + uint attributes; // Throw Info attributes (Bit field) + PMFN pmfnUnwind; // Destructor to call when exception has been handled or aborted. + PMFN pForwardCompat; // pointer to Forward compatibility frame handler + ImgPtr!(CatchableTypeArray*) pCatchableTypeArray; // pointer to CatchableTypeArray +} + +enum TI_IsConst = 0x00000001; // thrown object has const qualifier +enum TI_IsVolatile = 0x00000002; // thrown object has volatile qualifier +enum TI_IsUnaligned = 0x00000004; // thrown object has unaligned qualifier +enum TI_IsPure = 0x00000008; // object thrown from a pure module +enum TI_IsWinRT = 0x00000010; // object thrown is a WinRT Exception + +extern(Windows) void RaiseException(DWORD dwExceptionCode, + DWORD dwExceptionFlags, + DWORD nNumberOfArguments, + ULONG_PTR* lpArguments); + +__gshared TypeDescriptor!16 tdObject = { 0, null, "_D6object6Object\0" }; +__gshared TypeDescriptor!20 tdThrowable = { 0, null, "_D6object9Throwable\0" }; +__gshared TypeDescriptor!12 tdException = { 0, null, "_D9Exception\0" }; +version(none) { +__gshared CatchableType ctThrowable = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdThrowable, { 0, -1, 0 }, 4, null }; +__gshared CatchableType ctException = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdException, { 0, -1, 0 }, 4, null }; +__gshared CatchableTypeArray ctArray = { 2, [ &ctThrowable, &ctException ] }; +__gshared _ThrowInfo objectThrowInfo = { 0, null, null, &ctArray }; +} + +enum int STATUS_MSC_EXCEPTION = 0xe0000000 | ('m' << 16) | ('s' << 8) | ('c' << 0); + +enum EXCEPTION_NONCONTINUABLE = 0x01; +enum EXCEPTION_UNWINDING = 0x02; + +enum EH_MAGIC_NUMBER1 = 0x19930520; + +extern(C) void _d_throw_exception(Object e) +{ + if (e is null) + fatalerror("Cannot throw null exception"); + auto ti = typeid(e); + if (ti is null) + fatalerror("Cannot throw corrupt exception object with null classinfo"); + + ULONG_PTR[3] ExceptionInformation; + ExceptionInformation[0] = EH_MAGIC_NUMBER1; + ExceptionInformation[1] = cast(ULONG_PTR) cast(void*) &e; + ExceptionInformation[2] = cast(ULONG_PTR) getThrowInfo(ti); + + RaiseException(STATUS_MSC_EXCEPTION, EXCEPTION_NONCONTINUABLE, 3, ExceptionInformation.ptr); +} + +import rt.util.container.hashtab; +import core.sync.mutex; + +__gshared HashTab!(TypeInfo_Class, _ThrowInfo) throwInfoHashtab; +__gshared HashTab!(TypeInfo_Class, CatchableType) catchableHashtab; +__gshared Mutex throwInfoMutex; + +// create and cache throwinfo for ti +_ThrowInfo* getThrowInfo(TypeInfo_Class ti) +{ + throwInfoMutex.lock(); + if (auto p = ti in throwInfoHashtab) + { + throwInfoMutex.unlock(); + return p; + } + + size_t classes = 0; + for (TypeInfo_Class tic = ti; tic; tic = tic.base) + classes++; + + size_t sz = int.sizeof + classes * ImgPtr!(CatchableType*).sizeof; + auto cta = cast(CatchableTypeArray*) malloc(sz); + if (!cta) + onOutOfMemoryError(); + cta.nCatchableTypes = classes; + + size_t c = 0; + for (TypeInfo_Class tic = ti; tic; tic = tic.base) + cta.arrayOfCatchableTypes.ptr[c++] = getCatchableType(tic); + + _ThrowInfo tinf = { 0, null, null, cta }; + throwInfoHashtab[ti] = tinf; + auto pti = ti in throwInfoHashtab; + throwInfoMutex.unlock(); + return pti; +} + +CatchableType* getCatchableType(TypeInfo_Class ti) +{ + if (auto p = ti in catchableHashtab) + return p; + + static size_t mangledNameLength(string s) + { + size_t len = 2 + s.length; // "_D" + identifier + 1 digit per dot + for (size_t q = 0; q < s.length; ) + { + size_t p = q; + while (p < s.length && s.ptr[p] != '.') + p++; + for (size_t r = p - q; r >= 10; r /= 10) // add digits for length >= 10 + len++; + q = p + 1; + } + return len; + } + + static void mangleName(string s, char* buf) + { + *buf++ = '_'; + *buf++ = 'D'; + for (size_t q = 0; q < s.length; ) + { + size_t p = q; + while (p < s.length && s.ptr[p] != '.') + p++; + size_t digits = 10; + size_t len = p - q; + for ( ; len >= digits; digits *= 10) {} + for (digits /= 10; digits > 1; digits /= 10) + { + size_t dig = len / digits; + *buf++ = cast(char)('0' + dig); + len -= dig * digits; + } + *buf++ = cast(char)('0' + len); + memcpy(buf, s.ptr + q, p - q); + buf += p - q; + q = p + 1; + } + *buf = 0; + } + + size_t mangledLength = mangledNameLength(ti.name) + 1; + size_t sz = TypeDescriptor!1.sizeof + mangledLength; + auto td = cast(TypeDescriptor!1*) malloc(sz); + if (!td) + onOutOfMemoryError(); + + td.hash = 0; + td.spare = null; + mangleName(ti.name, td.name.ptr); + + CatchableType ct = { CT_IsSimpleType, td, { 0, -1, 0 }, 4, null }; + catchableHashtab[ti] = ct; + return ti in catchableHashtab; +} + +void msvc_eh_init() +{ + throwInfoMutex = new Mutex; + + // Exception has a special mangling that's not reflected in the name + + CatchableType ctObject = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdObject, { 0, -1, 0 }, 4, null }; + catchableHashtab[typeid(Object)] = ctObject; + CatchableType ctThrowable = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdThrowable, { 0, -1, 0 }, 4, null }; + catchableHashtab[typeid(Throwable)] = ctThrowable; + CatchableType ctException = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdException, { 0, -1, 0 }, 4, null }; + catchableHashtab[typeid(Exception)] = ctException; +} + +shared static this() +{ + // should be called from rt_init + msvc_eh_init(); +} diff --git a/src/rt/sections_ldc.d b/src/rt/sections_ldc.d index 93ee88cfb4..1dd3d6009c 100644 --- a/src/rt/sections_ldc.d +++ b/src/rt/sections_ldc.d @@ -96,7 +96,7 @@ private Section(SEG_DATA, SECT_COMMON) ]; } - else version (Win64) + else version (CRuntime_Microsoft) { extern extern (C) __gshared { @@ -371,7 +371,7 @@ void initSections() } _dyld_register_func_for_add_image(&scanSections); } - else version (Win64) + else version (CRuntime_Microsoft) { pushRange(_data_start__, _data_end__); if (_bss_start__ != null) diff --git a/src/rt/stdio_msvc.c b/src/rt/stdio_msvc.c index a81042643f..4ba82be225 100644 --- a/src/rt/stdio_msvc.c +++ b/src/rt/stdio_msvc.c @@ -36,9 +36,20 @@ int _set_output_format(int format); // VS2013- //extern const char* __acrt_iob_func; extern const char* _nullfunc = 0; -#pragma comment(linker, "/alternatename:__acrt_iob_func=_nullfunc") -#pragma comment(linker, "/alternatename:__iob_func=_nullfunc") -#pragma comment(linker, "/alternatename:_set_output_format=_nullfunc") +#if defined _M_IX86 + #define C_PREFIX "_" +#elif defined _M_X64 || defined _M_ARM || defined _M_ARM64 + #define C_PREFIX "" +#else + #error Unsupported architecture +#endif + +#define DECLARE_ALTERNATE_NAME(name, alternate_name) \ + __pragma(comment(linker, "/alternatename:" C_PREFIX #name "=" C_PREFIX #alternate_name)) + +DECLARE_ALTERNATE_NAME (__acrt_iob_func, _nullfunc); +DECLARE_ALTERNATE_NAME (__iob_func, _nullfunc); +DECLARE_ALTERNATE_NAME (_set_output_format, _nullfunc); void init_msvc() { @@ -65,25 +76,25 @@ void init_msvc() // VS2015+ provides C99-conformant (v)snprintf functions, so weakly // link to legacy _(v)snprintf (not C99-conformant!) for VS2013- only -#pragma comment(linker, "/alternatename:snprintf=_snprintf") -#pragma comment(linker, "/alternatename:vsnprintf=_vsnprintf") +DECLARE_ALTERNATE_NAME (snprintf, _snprintf); +DECLARE_ALTERNATE_NAME (vsnprintf, _vsnprintf); // VS2013- implements these functions as macros, VS2015+ provides symbols -#pragma comment(linker, "/alternatename:_fputc_nolock=_msvc_fputc_nolock") -#pragma comment(linker, "/alternatename:_fgetc_nolock=_msvc_fgetc_nolock") -#pragma comment(linker, "/alternatename:rewind=_msvc_rewind") -#pragma comment(linker, "/alternatename:clearerr=_msvc_clearerr") -#pragma comment(linker, "/alternatename:feof=_msvc_feof") -#pragma comment(linker, "/alternatename:ferror=_msvc_ferror") -#pragma comment(linker, "/alternatename:fileno=_msvc_fileno") +DECLARE_ALTERNATE_NAME (_fputc_nolock, _msvc_fputc_nolock); +DECLARE_ALTERNATE_NAME (_fgetc_nolock, _msvc_fgetc_nolock); +DECLARE_ALTERNATE_NAME (rewind, _msvc_rewind); +DECLARE_ALTERNATE_NAME (clearerr, _msvc_clearerr); +DECLARE_ALTERNATE_NAME (feof, _msvc_feof); +DECLARE_ALTERNATE_NAME (ferror, _msvc_ferror); +DECLARE_ALTERNATE_NAME (fileno, _msvc_fileno); // VS2013- helper functions int _filbuf(FILE* fp); int _flsbuf(int c, FILE* fp); -#pragma comment(linker, "/alternatename:_filbuf=_nullfunc") -#pragma comment(linker, "/alternatename:_flsbuf=_nullfunc") +DECLARE_ALTERNATE_NAME(_filbuf, _nullfunc); +DECLARE_ALTERNATE_NAME(_flsbuf, _nullfunc); int _msvc_fputc_nolock(int c, FILE* fp) {