// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // =========================================================================== // File: palclr.h // // Various macros and constants that are necessary to make the CLR portable. // // =========================================================================== #if !defined(FEATURE_PAL) #ifndef __PALCLR_H__ #define __PALCLR_H__ // This macro is used to standardize the wide character string literals between UNIX and Windows. // Unix L"" is UTF32, and on windows it's UTF16. Because of built-in assumptions on the size // of string literals, it's important to match behaviour between Unix and Windows. Unix will be defined // as u"" (char16_t) #ifdef PLATFORM_UNIX #define W(str) u##str #else // PLATFORM_UNIX #define W(str) L##str #endif // PLATFORM_UNIX #include #if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE) #define _DEBUG_IMPL 1 #endif // // CPP_ASSERT() can be used within a class definition, to perform a // compile-time assertion involving private names within the class. // // MS compiler doesn't allow redefinition of the typedef within a template. // gcc doesn't allow redefinition of the typedef within a class, though // it does at file scope. #define CPP_ASSERT(n, e) typedef char __C_ASSERT__##n[(e) ? 1 : -1]; // PORTABILITY_ASSERT and PORTABILITY_WARNING macros are meant to be used to // mark places in the code that needs attention for portability. The usual // usage pattern is: // // int get_scratch_register() { // #if defined(_TARGET_X86_) // return eax; // #elif defined(_TARGET_AMD64_) // return rax; // #elif defined(_TARGET_ARM_) // return r0; // #else // PORTABILITY_ASSERT("scratch register"); // return 0; // #endif // } // // PORTABILITY_ASSERT is meant to be used inside functions/methods. It can // introduce compile-time and/or run-time errors. // PORTABILITY_WARNING is meant to be used outside functions/methods. It can // introduce compile-time errors or warnings only. // // People starting new ports will first define these to just cause run-time // errors. Once they fix all the places that need attention for portability, // they can define PORTABILITY_ASSERT and PORTABILITY_WARNING to cause // compile-time errors to make sure that they haven't missed anything. // // If it is reasonably possible all codepaths containing PORTABILITY_ASSERT // should be compilable (e.g. functions should return NULL or something if // they are expected to return a value). // // The message in these two macros should not contain any keywords like TODO // or NYI. It should be just the brief description of the problem. #if defined(_TARGET_X86_) // Finished ports - compile-time errors #define PORTABILITY_WARNING(message) NEED_TO_PORT_THIS_ONE(NEED_TO_PORT_THIS_ONE) #define PORTABILITY_ASSERT(message) NEED_TO_PORT_THIS_ONE(NEED_TO_PORT_THIS_ONE) #else // Ports in progress - run-time asserts only #define PORTABILITY_WARNING(message) #define PORTABILITY_ASSERT(message) _ASSERTE(false && message) #endif #define DIRECTORY_SEPARATOR_CHAR_A '\\' #define DIRECTORY_SEPARATOR_STR_A "\\" #define DIRECTORY_SEPARATOR_CHAR_W W('\\') #define DIRECTORY_SEPARATOR_STR_W W("\\") #define PATH_SEPARATOR_CHAR_W W(';') #define PATH_SEPARATOR_STR_W W(";") #define VOLUME_SEPARATOR_CHAR_W W(':') // PAL Macros // Not all compilers support fully anonymous aggregate types, so the // PAL provides names for those types. To allow existing definitions of // those types to continue to work, we provide macros that should be // used to reference fields within those types. #ifndef DECIMAL_SCALE #define DECIMAL_SCALE(dec) ((dec).scale) #endif #ifndef DECIMAL_SIGN #define DECIMAL_SIGN(dec) ((dec).sign) #endif #ifndef DECIMAL_SIGNSCALE #define DECIMAL_SIGNSCALE(dec) ((dec).signscale) #endif #ifndef DECIMAL_LO32 #define DECIMAL_LO32(dec) ((dec).Lo32) #endif #ifndef DECIMAL_MID32 #define DECIMAL_MID32(dec) ((dec).Mid32) #endif #ifndef DECIMAL_HI32 #define DECIMAL_HI32(dec) ((dec).Hi32) #endif #ifndef DECIMAL_LO64_GET #define DECIMAL_LO64_GET(dec) ((dec).Lo64) #endif #ifndef DECIMAL_LO64_SET #define DECIMAL_LO64_SET(dec,value) {(dec).Lo64 = value; } #endif #ifndef IMAGE_RELOC_FIELD #define IMAGE_RELOC_FIELD(img, f) ((img).f) #endif #ifndef IMAGE_IMPORT_DESC_FIELD #define IMAGE_IMPORT_DESC_FIELD(img, f) ((img).f) #endif //Remove these "unanonymous" unions from newer builds for now. Confirm that they were never needed when we //bring back Rotor. #define IMAGE_RDE_ID(img) ((img)->Id) #ifndef IMAGE_RDE_ID #define IMAGE_RDE_ID(img) ((img)->Id) #endif #define IMAGE_RDE_NAME(img) ((img)->Name) #ifndef IMAGE_RDE_NAME #define IMAGE_RDE_NAME(img) ((img)->Name) #endif #define IMAGE_RDE_OFFSET(img) ((img)->OffsetToData) #ifndef IMAGE_RDE_OFFSET #define IMAGE_RDE_OFFSET(img) ((img)->OffsetToData) #endif #ifndef IMAGE_RDE_NAME_FIELD #define IMAGE_RDE_NAME_FIELD(img, f) ((img)->f) #endif #define IMAGE_RDE_OFFSET_FIELD(img, f) ((img)->f) #ifndef IMAGE_RDE_OFFSET_FIELD #define IMAGE_RDE_OFFSET_FIELD(img, f) ((img)->f) #endif #ifndef IMAGE_FE64_FIELD #define IMAGE_FE64_FIELD(img, f) ((img).f) #endif #ifndef IMPORT_OBJ_HEADER_FIELD #define IMPORT_OBJ_HEADER_FIELD(obj, f) ((obj).f) #endif #ifndef IMAGE_COR20_HEADER_FIELD #define IMAGE_COR20_HEADER_FIELD(obj, f) ((obj).f) #endif // PAL Numbers // Used to ensure cross-compiler compatibility when declaring large // integer constants. 64-bit integer constants should be wrapped in the // declarations listed here. // // Each of the #defines here is wrapped to avoid conflicts with rotor_pal.h. #if defined(_MSC_VER) // MSVC's way of declaring large integer constants // If you define these in one step, without the _HELPER macros, you // get extra whitespace when composing these with other concatenating macros. #ifndef I64 #define I64_HELPER(x) x ## i64 #define I64(x) I64_HELPER(x) #endif #ifndef UI64 #define UI64_HELPER(x) x ## ui64 #define UI64(x) UI64_HELPER(x) #endif #else // GCC's way of declaring large integer constants // If you define these in one step, without the _HELPER macros, you // get extra whitespace when composing these with other concatenating macros. #ifndef I64 #define I64_HELPER(x) x ## LL #define I64(x) I64_HELPER(x) #endif #ifndef UI64 #define UI64_HELPER(x) x ## ULL #define UI64(x) UI64_HELPER(x) #endif #endif // PAL SEH // Macros for portable exception handling. The Win32 SEH is emulated using // these macros and setjmp/longjmp on Unix // // Usage notes: // // - The filter has to be a function taking two parameters: // LONG MyFilter(PEXCEPTION_POINTERS *pExceptionInfo, PVOID pv) // // - It is not possible to directly use the local variables in the filter. // All the local information that the filter has to need to know about should // be passed through pv parameter // // - Do not use goto to jump out of the PAL_TRY block // (jumping out of the try block is not a good idea even on Win32, because of // it causes stack unwind) // // - It is not possible to directly use the local variables in the try block. // All the local information that the filter has to need to know about should // be passed through pv parameter // // // Simple examples: // // struct Param { ... local variables used in try block and filter ... } param; // PAL_TRY(Param *, pParam, ¶m) { // read as: Param *pParam = ¶m; // .... // } PAL_FINALLY { // .... // } // PAL_ENDTRY // // // struct Param { ... local variables used in try block and filter ... } param; // PAL_TRY(Param *, pParam, ¶m) { // .... // } PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { // .... // } // PAL_ENDTRY // // // LONG MyFilter(PEXCEPTION_POINTERS *pExceptionInfo, PVOID pv) // { // ... // } // PAL_TRY(void *, unused, NULL) { // .... // } PAL_EXCEPT_FILTER(MyFilter) { // .... // } // PAL_ENDTRY // // // Complex example: // // struct MyParams // { // ... // } params; // // PAL_TRY(MyParams *, pMyParamsOuter, ¶ms) { // PAL_TRY(MyParams *, pMyParamsInnter, pMyParamsOuter) { // ... // if (error) goto Done; // ... // Done: ; // } PAL_EXCEPT_FILTER(OtherFilter) { // ... // } // PAL_ENDTRY // } // PAL_FINALLY { // } // PAL_ENDTRY // #include "staticcontract.h" #define HardwareExceptionHolder // Note: PAL_SEH_RESTORE_GUARD_PAGE is only ever defined in clrex.h, so we only restore guard pages automatically // when these macros are used from within the VM. #define PAL_SEH_RESTORE_GUARD_PAGE #define PAL_TRY_NAKED \ { \ bool __exHandled; __exHandled = false; \ DWORD __exCode; __exCode = 0; \ SCAN_EHMARKER(); \ __try \ { \ SCAN_EHMARKER_TRY(); #define PAL_EXCEPT_NAKED(Disposition) \ } \ __except(__exCode = GetExceptionCode(), Disposition) \ { \ __exHandled = true; \ SCAN_EHMARKER_CATCH(); \ PAL_SEH_RESTORE_GUARD_PAGE #define PAL_EXCEPT_FILTER_NAKED(pfnFilter, param) \ } \ __except(__exCode = GetExceptionCode(), \ pfnFilter(GetExceptionInformation(), param)) \ { \ __exHandled = true; \ SCAN_EHMARKER_CATCH(); \ PAL_SEH_RESTORE_GUARD_PAGE #define PAL_FINALLY_NAKED \ } \ __finally \ { \ #define PAL_ENDTRY_NAKED \ } \ PAL_ENDTRY_NAKED_DBG \ } \ #if defined(_DEBUG) && !defined(DACCESS_COMPILE) // // In debug mode, compile the try body as a method of a local class. // This way, the compiler will check that the body is not directly // accessing any local variables and arguments. // #define PAL_TRY(__ParamType, __paramDef, __paramRef) \ { \ __ParamType __param = __paramRef; \ __ParamType __paramToPassToFilter = __paramRef; \ class __Body \ { \ public: \ static void Run(__ParamType __paramDef) \ { \ PAL_TRY_HANDLER_DBG_BEGIN // PAL_TRY implementation that abstracts usage of COMPILER_INSTANCE*, which is used by // JIT64. On Windows, we dont need to do anything special as we dont have nested classes/methods // as on PAL. #define PAL_TRY_CI(__ParamType, __paramDef, __paramRef) \ { \ struct __HandlerData { \ __ParamType __param; \ COMPILER_INSTANCE *__ciPtr; \ }; \ __HandlerData handlerData; \ handlerData.__param = __paramRef; \ handlerData.__ciPtr = ciPtr; \ __HandlerData* __param = &handlerData; \ __ParamType __paramToPassToFilter = __paramRef; \ class __Body \ { \ public: \ static void Run(__HandlerData* __pHandlerData) \ { \ PAL_TRY_HANDLER_DBG_BEGIN \ COMPILER_INSTANCE *ciPtr = __pHandlerData->__ciPtr; \ __ParamType __paramDef = __pHandlerData->__param; #define PAL_TRY_FOR_DLLMAIN(__ParamType, __paramDef, __paramRef, __reason) \ { \ __ParamType __param = __paramRef; \ __ParamType __paramToPassToFilter = __paramRef; \ class __Body \ { \ public: \ static void Run(__ParamType __paramDef) \ { \ PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(__reason) #define PAL_EXCEPT(Disposition) \ PAL_TRY_HANDLER_DBG_END \ } \ }; \ PAL_TRY_NAKED \ __Body::Run(__param); \ PAL_EXCEPT_NAKED(Disposition) #define PAL_EXCEPT_FILTER(pfnFilter) \ PAL_TRY_HANDLER_DBG_END \ } \ }; \ PAL_TRY_NAKED \ __Body::Run(__param); \ PAL_EXCEPT_FILTER_NAKED(pfnFilter, __paramToPassToFilter) #define PAL_FINALLY \ PAL_TRY_HANDLER_DBG_END \ } \ }; \ PAL_TRY_NAKED \ __Body::Run(__param); \ PAL_FINALLY_NAKED #define PAL_ENDTRY \ PAL_ENDTRY_NAKED \ } #else // _DEBUG #define PAL_TRY(__ParamType, __paramDef, __paramRef) \ { \ __ParamType __param = __paramRef; \ __ParamType __paramDef = __param; \ PAL_TRY_NAKED \ PAL_TRY_HANDLER_DBG_BEGIN // PAL_TRY implementation that abstracts usage of COMPILER_INSTANCE*, which is used by // JIT64. On Windows, we dont need to do anything special as we dont have nested classes/methods // as on PAL. #define PAL_TRY_CI(__ParamType, __paramDef, __paramRef) PAL_TRY(__ParamType, __paramDef, __paramRef) #define PAL_TRY_FOR_DLLMAIN(__ParamType, __paramDef, __paramRef, __reason) \ { \ __ParamType __param = __paramRef; \ __ParamType __paramDef; __paramDef = __param; \ PAL_TRY_NAKED \ PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(__reason) #define PAL_EXCEPT(Disposition) \ PAL_TRY_HANDLER_DBG_END \ PAL_EXCEPT_NAKED(Disposition) #define PAL_EXCEPT_FILTER(pfnFilter) \ PAL_TRY_HANDLER_DBG_END \ PAL_EXCEPT_FILTER_NAKED(pfnFilter, __param) #define PAL_FINALLY \ PAL_TRY_HANDLER_DBG_END \ PAL_FINALLY_NAKED #define PAL_ENDTRY \ PAL_ENDTRY_NAKED \ } #endif // _DEBUG // Executes the handler if the specified exception code matches // the one in the exception. Otherwise, returns EXCEPTION_CONTINUE_SEARCH. #define PAL_EXCEPT_IF_EXCEPTION_CODE(dwExceptionCode) PAL_EXCEPT((GetExceptionCode() == dwExceptionCode)?EXCEPTION_EXECUTE_HANDLER:EXCEPTION_CONTINUE_SEARCH) #define PAL_CPP_TRY try #define PAL_CPP_ENDTRY #define PAL_CPP_THROW(type, obj) do { SCAN_THROW_MARKER; throw obj; } while (false) #define PAL_CPP_RETHROW do { SCAN_THROW_MARKER; throw; } while (false) #define PAL_CPP_CATCH_DERIVED(type, obj) catch (type * obj) #define PAL_CPP_CATCH_ALL catch (...) #define PAL_CPP_CATCH_EXCEPTION_NOARG catch (Exception *) // SELECTANY macro is intended to prevent duplication of static const // arrays declared in .h files in binary modules. // The problem is that const variables have static internal linkage // in C++. That means that if a const variable is declared in a .h file // the compiler will emit it into every translation unit that uses that .h file. // That will cause duplication of the data when those translation units // are linked into a binary module. // SELECTANY declares a variable as extern to give it external linkage // and it provides __declspec(selectany) to instruct the linker to merge // duplicate external const static data copies into one. // #if defined(SOURCE_FORMATTING) #define SELECTANY extern #else #define SELECTANY extern __declspec(selectany) #endif #if defined(SOURCE_FORMATTING) #define __annotation(x) #endif #if defined(_DEBUG_IMPL) && !defined(JIT_BUILD) && !defined(JIT64_BUILD) && !defined(CROSS_COMPILE) && !defined(_TARGET_ARM_) // @ARMTODO: no contracts for speed #define PAL_TRY_HANDLER_DBG_BEGIN \ BOOL ___oldOkayToThrowValue = FALSE; \ SO_INFRASTRUCTURE_CODE(BOOL ___oldSOTolerantState = FALSE;) \ ClrDebugState *___pState = ::GetClrDebugState(); \ __try \ { \ ___oldOkayToThrowValue = ___pState->IsOkToThrow(); \ SO_INFRASTRUCTURE_CODE(___oldSOTolerantState = ___pState->IsSOTolerant();) \ ___pState->SetOkToThrow(); \ PAL_ENTER_THROWS_REGION; // Special version that avoids touching the debug state after doing work in a DllMain for process or thread detach. #define PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason) \ BOOL ___oldOkayToThrowValue = FALSE; \ SO_INFRASTRUCTURE_CODE(BOOL ___oldSOTolerantState = FALSE;) \ ClrDebugState *___pState = NULL; \ if (_reason != DLL_PROCESS_ATTACH) \ ___pState = CheckClrDebugState(); \ __try \ { \ if (___pState) \ { \ ___oldOkayToThrowValue = ___pState->IsOkToThrow(); \ SO_INFRASTRUCTURE_CODE(___oldSOTolerantState = ___pState->IsSOTolerant();) \ ___pState->SetOkToThrow(); \ } \ if ((_reason == DLL_PROCESS_DETACH) || (_reason == DLL_THREAD_DETACH)) \ { \ ___pState = NULL; \ } \ PAL_ENTER_THROWS_REGION; #define PAL_TRY_HANDLER_DBG_END \ PAL_LEAVE_THROWS_REGION \ } \ __finally \ { \ if (___pState != NULL) \ { \ _ASSERTE(___pState == CheckClrDebugState()); \ ___pState->SetOkToThrow( ___oldOkayToThrowValue ); \ SO_INFRASTRUCTURE_CODE(___pState->SetSOTolerance( ___oldSOTolerantState );) \ } \ } #define PAL_ENDTRY_NAKED_DBG \ if (__exHandled) \ { \ RESTORE_SO_TOLERANCE_STATE; \ } \ #else #define PAL_TRY_HANDLER_DBG_BEGIN ANNOTATION_TRY_BEGIN; #define PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason) ANNOTATION_TRY_BEGIN; #define PAL_TRY_HANDLER_DBG_END ANNOTATION_TRY_END; #define PAL_ENDTRY_NAKED_DBG #endif // defined(ENABLE_CONTRACTS_IMPL) && !defined(JIT64_BUILD) #if !BIGENDIAN // For little-endian machines, do nothing #define VAL16(x) x #define VAL32(x) x #define VAL64(x) x #define SwapString(x) #define SwapStringLength(x, y) #define SwapGuid(x) #endif // !BIGENDIAN #ifdef _MSC_VER // Get Unaligned values from a potentially unaligned object #define GET_UNALIGNED_16(_pObject) (*(UINT16 UNALIGNED *)(_pObject)) #define GET_UNALIGNED_32(_pObject) (*(UINT32 UNALIGNED *)(_pObject)) #define GET_UNALIGNED_64(_pObject) (*(UINT64 UNALIGNED *)(_pObject)) // Set Value on an potentially unaligned object #define SET_UNALIGNED_16(_pObject, _Value) (*(UNALIGNED UINT16 *)(_pObject)) = (UINT16)(_Value) #define SET_UNALIGNED_32(_pObject, _Value) (*(UNALIGNED UINT32 *)(_pObject)) = (UINT32)(_Value) #define SET_UNALIGNED_64(_pObject, _Value) (*(UNALIGNED UINT64 *)(_pObject)) = (UINT64)(_Value) // Get Unaligned values from a potentially unaligned object and swap the value #define GET_UNALIGNED_VAL16(_pObject) VAL16(GET_UNALIGNED_16(_pObject)) #define GET_UNALIGNED_VAL32(_pObject) VAL32(GET_UNALIGNED_32(_pObject)) #define GET_UNALIGNED_VAL64(_pObject) VAL64(GET_UNALIGNED_64(_pObject)) // Set a swap Value on an potentially unaligned object #define SET_UNALIGNED_VAL16(_pObject, _Value) SET_UNALIGNED_16(_pObject, VAL16((UINT16)_Value)) #define SET_UNALIGNED_VAL32(_pObject, _Value) SET_UNALIGNED_32(_pObject, VAL32((UINT32)_Value)) #define SET_UNALIGNED_VAL64(_pObject, _Value) SET_UNALIGNED_64(_pObject, VAL64((UINT64)_Value)) #endif #ifdef _WIN64 #define VALPTR(x) VAL64(x) #define GET_UNALIGNED_PTR(x) GET_UNALIGNED_64(x) #define GET_UNALIGNED_VALPTR(x) GET_UNALIGNED_VAL64(x) #define SET_UNALIGNED_PTR(p,x) SET_UNALIGNED_64(p,x) #define SET_UNALIGNED_VALPTR(p,x) SET_UNALIGNED_VAL64(p,x) #else #define VALPTR(x) VAL32(x) #define GET_UNALIGNED_PTR(x) GET_UNALIGNED_32(x) #define GET_UNALIGNED_VALPTR(x) GET_UNALIGNED_VAL32(x) #define SET_UNALIGNED_PTR(p,x) SET_UNALIGNED_32(p,x) #define SET_UNALIGNED_VALPTR(p,x) SET_UNALIGNED_VAL32(p,x) #endif #define MAKEDLLNAME_W(name) name W(".dll") #define MAKEDLLNAME_A(name) name ".dll" #ifdef UNICODE #define MAKEDLLNAME(x) MAKEDLLNAME_W(x) #else #define MAKEDLLNAME(x) MAKEDLLNAME_A(x) #endif #if !defined(MAX_LONGPATH) #define MAX_LONGPATH 260 /* max. length of full pathname */ #endif #if !defined(MAX_PATH_FNAME) #define MAX_PATH_FNAME MAX_PATH /* max. length of full pathname */ #endif #define __clr_reserved __reserved #endif // __PALCLR_H__ #include "palclr_win.h" #endif // !defined(FEATURE_PAL)