diff options
42 files changed, 300 insertions, 1559 deletions
diff --git a/.gitignore b/.gitignore index 83808394eb..e69eb76426 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ bld/ [Bb]in/ [Oo]bj/ msbuild.log +binaries # Roslyn stuff *.sln.ide @@ -254,3 +255,7 @@ TestWrappers_x64_release Vagrantfile .vagrant +# CMake files +CMakeFiles/ +cmake_install.cmake +CMakeCache.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 87072d8174..25c302991d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,12 @@ if(CMAKE_SYSTEM_NAME STREQUAL Darwin) set(CMAKE_ASM_COMPILE_OBJECT "${CMAKE_C_COMPILER} <FLAGS> <DEFINES> -o <OBJECT> -c <SOURCE>") endif(CMAKE_SYSTEM_NAME STREQUAL Darwin) +if(WIN32) + enable_language(ASM_MASM) +else() + enable_language(ASM) +endif(WIN32) + # Build a list of compiler definitions by putting -D in front of each define. function(get_compile_definitions DefinitionName) # Get the current list of definitions diff --git a/Documentation/dotnet-standards.md b/Documentation/dotnet-standards.md new file mode 100644 index 0000000000..0942c538de --- /dev/null +++ b/Documentation/dotnet-standards.md @@ -0,0 +1,52 @@ +.NET Standards +============== + +There was a very early realization by the founders of .NET that they were creating a new programming technology that had broad applicability across operating systems and CPU types and that advanced the state of the art of late 1990s (when the .NET project started at Microsoft) programming language implementation techniques. This led to considering and then pursuing standardization as an important pillar of establishing .NET in the industry. + +The key addition to the state of the art was support for multiple programming languages with a single language runtime, hence the name _Common Language Runtime_. There were many other smaller additions, such as value types, a simple exception model and attributes. Generics and language integrated query were later added to that list. + +Looking back, standardization was quite effective, leading to .NET having a strong presence on iOS and Android, with the Unity and Xamarin offerings, both of which use the Mono runtime. The same may end up being true for .NET on Linux. + +The various .NET standards have been made meaningful by the collaboration of multiple companies and industry experts that have served on the working groups that have defined the standards. In addition (and most importantly), the .NET standards have been implemented by multiple commercial (ex: Unity IL2CPP, .NET Native) and open source (ex: Mono) implementors. The presence of multiple implementations proves the point of standardization. + +ECMA 334 - C# +============= + +The C# language was standardized as [ECMA 334](http://www.ecma-international.org/publications/standards/Ecma-334.htm) in 2002 and approved as [ISO/IEC 23270](http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=42926) in 2003. + +**ECMA 334 Resources** + +- [ECMA 334 Standard Overview](http://www.ecma-international.org/publications/standards/Ecma-334.htm) +- [ECMA 334 Standard (PDF)](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-334.pdf) + +ECMA 335 - CLI +============== + +[Common Language Infrastructure](http://en.wikipedia.org/wiki/Common_Language_Infrastructure) - the formalized basis of .NET -- was standardized as [ECMA 335](http://www.ecma-international.org/publications/standards/Ecma-335.htm) in 2001 and approved as [ISO/IEC 23271](http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=58046) in 2003. The standards have been since updated, to reflect changes in .NET, such as generics. + +**ECMA 335 Resources** + +- [ECMA 335 Standard Overview](http://www.ecma-international.org/publications/standards/Ecma-335.htm) +- [ECMA 335 Standard (PDF)](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf) +- [Wikipedia entry on CLI](http://en.wikipedia.org/wiki/Common_Language_Infrastructure) + +**ECMA 335 Partitions with added Microsoft Specific Implementation Notes** + +- [Partition I: Concepts and Architecture](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20I.pdf) +- [Partition II: Meta Data Definition and Semantics](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20II.pdf) +- [Partition III: CIL Instruction Set](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20III.pdf) +- [Partition IV: Profiles and Libraries](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20IV.pdf) +- [Partition V: Debug Interchange Format](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20V.pdf) +- [Partition VI: Annexes](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20VI.pdf) + +Shared Source CLI (SSCLI) +========================= + +[Shared Source CLI](http://en.wikipedia.org/wiki/Shared_Source_Common_Language_Infrastructure) or "Rotor" was a working implementation for the ECMA-334 (C#) and ECMA-335 (Common Language Infrastructure, or CLI) standards. It was released under a shared source license in 2002, primarily to encourage academic research focused on .NET and to demonstrate viability of .NET on diverse platforms. It was last released in 2006, to align with the .NET Framework 2 release. It is no longer relevant, given that [CoreCLR](https://github.com/dotnet/coreclr) has been released as open source on GitHub. + +**SSCLI Resources** + +- [Wikipedia entry on SSCLI](http://en.wikipedia.org/wiki/Shared_Source_Common_Language_Infrastructure) +- [The Microsoft Shared Source CLI Implementation](https://msdn.microsoft.com/library/ms973879.aspx) +- [Shared Source Common Language Infrastructure 2.0 Release ](http://www.microsoft.com/en-us/download/details.aspx?id=4917) +- [Shared Source CLI 2.0 Infrastructure 2.0 Release - 3rd party provided on GitHub](https://github.com/gbarnett/shared-source-cli-2.0)
\ No newline at end of file diff --git a/Documentation/index.md b/Documentation/index.md index ae831b37ac..663ad4eb0c 100644 --- a/Documentation/index.md +++ b/Documentation/index.md @@ -1,9 +1,10 @@ Documents Index -=== +=============== This repo includes several documents that explain both high-level and low-level concepts about the .NET runtime. These are very useful for contributors, to get context that can be very difficult to acquire from just reading code. -# Book of the Runtime +Book of the Runtime +=================== - [Introduction to the Common Language Runtime](intro-to-clr.md) - [Mscorlib and Calling Into the Runtime](mscorlib.md) @@ -11,21 +12,20 @@ This repo includes several documents that explain both high-level and low-level - [Stack Walking](stackwalking.md) - [Book of the Runtime FAQ](botr-faq.md) -# Coding Guides +.NET Runtime Specs +================== - [CLR Coding Guide](clr-code-guide.md) +- [.NET Standards](dotnet-standards.md) -# Glossary +Decoder Rings +============= - [.NET Core Glossary](glossary.md) - [.NET Filename Encyclopedia](dotnet-filenames.md) -# Links to other sources +Links to other Sources +====================== - [MSDN Entry for the CLR](http://msdn.microsoft.com/en-us/library/8bs2ecf4(VS.71).aspx) -- [Wikipedia Entry for the CLR](http://en.wikipedia.org/wiki/Common_Language_Runtime) -- [ECMA Standard for the Common Language Infrastructure (CLI)](http://www.ecma-international.org/publications/standards/Ecma-335.htm) - - [Partition I Concepts and Architecture](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20I.pdf) - - [Partition II Meta Data Definition and Semantics](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20II.pdf) - - [Partition III CIL Instruction Set](http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20III.pdf) -- [.NET Framework Design Guidelines](http://msdn.microsoft.com/en-us/library/ms229042.aspx) +- [Wikipedia Entry for the CLR](http://en.wikipedia.org/wiki/Common_Language_Runtime)
\ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 95a56e1baa..95a9640e32 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,19 +10,16 @@ include_directories("classlibnative/bcltype") include_directories("classlibnative/cryptography") include_directories("classlibnative/inc") -if(WIN32) -enable_language(ASM_MASM) -else() -enable_language(ASM) -# This prevents inclusion of standard C compiler headers -add_compile_options(-nostdinc) +if(CLR_CMAKE_PLATFORM_UNIX) + # This prevents inclusion of standard C compiler headers + add_compile_options(-nostdinc) -if(NOT CLR_CMAKE_PLATFORM_DARWIN) - # This prevents inclusion of standard C++ compiler headers - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++") -endif(NOT CLR_CMAKE_PLATFORM_DARWIN) + if(NOT CLR_CMAKE_PLATFORM_DARWIN) + # This prevents inclusion of standard C++ compiler headers + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++") + endif(NOT CLR_CMAKE_PLATFORM_DARWIN) -endif(WIN32) +endif(CLR_CMAKE_PLATFORM_UNIX) add_subdirectory(utilcode) add_subdirectory(gcinfo) diff --git a/src/inc/debugreturn.h b/src/inc/debugreturn.h index 9eb204d92c..eadf827893 100644 --- a/src/inc/debugreturn.h +++ b/src/inc/debugreturn.h @@ -65,6 +65,7 @@ class __SafeToReturn { public: static int safe_to_return() {return 0;}; + static int used() {return 0;}; }; class __YouCannotUseAReturnStatementHere { @@ -76,9 +77,10 @@ private: // static int safe_to_return() {return 0;}; public: - // Some compilers warn if all member functions in a class are private. - // Rather than disable the warning, we'll work around it here. - static void dont_call_this() { _ASSERTE(!"Don't call this!"); } + // Some compilers warn if all member functions in a class are private + // or if a typedef is unused. Rather than disable the warning, we'll work + // around it here. + static int used() {return 0;}; }; typedef __SafeToReturn __ReturnOK; @@ -93,15 +95,15 @@ typedef __SafeToReturn __ReturnOK; // #define return if (0 && __ReturnOK::safe_to_return()) { } else return -#define DEBUG_ASSURE_NO_RETURN_BEGIN(arg) { typedef __YouCannotUseAReturnStatementHere __ReturnOK; -#define DEBUG_ASSURE_NO_RETURN_END(arg) } +#define DEBUG_ASSURE_NO_RETURN_BEGIN(arg) { typedef __YouCannotUseAReturnStatementHere __ReturnOK; if (0 && __ReturnOK::used()) { } else { +#define DEBUG_ASSURE_NO_RETURN_END(arg) } } // rotor_pal.h defaulted these to empty macros; this file redefines them #undef DEBUG_OK_TO_RETURN_BEGIN #undef DEBUG_OK_TO_RETURN_END -#define DEBUG_OK_TO_RETURN_BEGIN(arg) { typedef __SafeToReturn __ReturnOK; -#define DEBUG_OK_TO_RETURN_END(arg) } +#define DEBUG_OK_TO_RETURN_BEGIN(arg) { typedef __SafeToReturn __ReturnOK; if (0 && __ReturnOK::used()) { } else { +#define DEBUG_OK_TO_RETURN_END(arg) } } #else // !_DEBUG diff --git a/src/inc/staticcontract.h b/src/inc/staticcontract.h index 282a21f64e..5c7a33b8f7 100644 --- a/src/inc/staticcontract.h +++ b/src/inc/staticcontract.h @@ -244,6 +244,10 @@ namespace StaticContract STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_SO_TOLERANT; } + + static void used() + { + } }; struct ScanThrowMarkerTerminal @@ -252,6 +256,10 @@ namespace StaticContract { METHOD_CANNOT_BE_FOLDED_DEBUG; } + + static void used() + { + } }; struct ScanThrowMarkerIgnore @@ -260,6 +268,10 @@ namespace StaticContract { METHOD_CANNOT_BE_FOLDED_DEBUG; } + + static void used() + { + } }; } typedef StaticContract::ScanThrowMarkerStandard ScanThrowMarker; @@ -270,13 +282,13 @@ typedef StaticContract::ScanThrowMarkerStandard ScanThrowMarker; #define SCAN_THROW_MARKER do { ScanThrowMarker __throw_marker; } while (0) #define SCAN_IGNORE_THROW_MARKER \ - typedef StaticContract::ScanThrowMarkerIgnore ScanThrowMarker + typedef StaticContract::ScanThrowMarkerIgnore ScanThrowMarker; if (0) ScanThrowMarker::used(); // Terminal exceptions are asynchronous and cannot be included in THROWS contract // analysis. As such, this uses typedef to reassign the ScanThrowMarker to a // non-annotating struct so that SCAN does not see the block as throwing. #define STATIC_CONTRACT_THROWS_TERMINAL \ - typedef StaticContract::ScanThrowMarkerTerminal ScanThrowMarker; + typedef StaticContract::ScanThrowMarkerTerminal ScanThrowMarker; if (0) ScanThrowMarker::used(); #if defined(_DEBUG) && !defined(DACCESS_COMPILE) && defined(FEATURE_STACK_PROBE) && !defined(_TARGET_ARM_) // @ARMTODO extern void EnsureSOIntolerantOK(const char *szFunction, const char *szFile, int lineNum); diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index 22a4cf21c9..de924fc424 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -449,7 +449,7 @@ int PALAPI PAL_Initialize( int argc, - const char *argv[]); + const char * const argv[]); PALIMPORT DWORD @@ -4737,18 +4737,6 @@ SetUnhandledExceptionFilter( typedef EXCEPTION_DISPOSITION (PALAPI *PVECTORED_EXCEPTION_HANDLER)( struct _EXCEPTION_POINTERS *ExceptionPointers); -PALIMPORT -void -PALAPI -SetVectoredExceptionHandler( - IN PVECTORED_EXCEPTION_HANDLER lpHandler); - -PALIMPORT -void -PALAPI -SetVectoredContinueHandler( - IN PVECTORED_EXCEPTION_HANDLER lpHandler); - #endif // FEATURE_PAL_SXS // Define BitScanForward64 and BitScanForward @@ -5894,206 +5882,94 @@ typedef EXCEPTION_DISPOSITION (*PFN_PAL_EXCEPTION_FILTER)( PAL_DISPATCHER_CONTEXT *DispatcherContext, void *pvParam); -struct _Unwind_Exception *PAL_TryExcept( - PFN_PAL_BODY pfnBody, - PFN_PAL_EXCEPTION_FILTER pfnFilter, - void *pvParam, - BOOL *pfExecuteHandler); - -// -// Possible results from PAL_TryExcept: -// -// returned exception pfExecuteHandler means -// ------------------ ---------------- ---------------------------------------- -// NULL any No exception escaped from the try block. -// non-NULL FALSE An exception escaped from the try block, -// but the filter did not want to handle it. -// non-NULL TRUE An exception escaped from the try block, -// and the filter wanted to handle it. -// - -#define DEBUG_OK_TO_RETURN_BEGIN(arg) -#define DEBUG_OK_TO_RETURN_END(arg) - -#ifdef _PPC_ -// This function does not do anything. It is just here to be called by -// PAL_TRY, so we can avoid the body of PAL_TRY being translated by the -// compiler into a leaf function (i.e., one that does not set up its -// own frame), because on a hardware fault in a leaf function, we would -// get a stack that would not be unwindable. -PALIMPORT VOID PALAPI PAL_DummyCall(); -#define PAL_DUMMY_CALL PAL_DummyCall(); -#else -#define PAL_DUMMY_CALL -#endif - #ifdef __cplusplus -class PAL_CatchHolder -{ -public: - PAL_CatchHolder(_Unwind_Exception *exceptionObject) - { - __cxa_begin_catch(exceptionObject); - } - ~PAL_CatchHolder() - { - __cxa_end_catch(); - } -}; - -class PAL_ExceptionHolder +struct PAL_SEHException { -private: - _Unwind_Exception *m_exceptionObject; public: - PAL_ExceptionHolder(_Unwind_Exception *exceptionObject) - { - m_exceptionObject = exceptionObject; - } - - ~PAL_ExceptionHolder() - { - if (m_exceptionObject) - { - _Unwind_DeleteException(m_exceptionObject); - } - } - - void SuppressRelease() + // Note that the following two are actually embedded in this heap-allocated + // instance - in contrast to Win32, where the exception record would usually + // be allocated on the stack. This is needed because foreign cleanup handlers + // partially unwind the stack on the second pass. + EXCEPTION_POINTERS ExceptionPointers; + EXCEPTION_RECORD ExceptionRecord; + CONTEXT ContextRecord; + + PAL_SEHException(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContextRecord) { - m_exceptionObject = NULL; + ExceptionPointers.ExceptionRecord = &ExceptionRecord; + ExceptionPointers.ContextRecord = &ContextRecord; + ExceptionRecord = *pExceptionRecord; + ContextRecord = *pContextRecord; } }; -class PAL_NoHolder -{ -public: - void SuppressRelease() {} -}; #endif // __cplusplus +// Start of a try block for exceptions raised by RaiseException #define PAL_TRY(__ParamType, __paramDef, __paramRef) \ { \ - struct __HandlerData \ - { \ - __ParamType __param; \ - EXCEPTION_DISPOSITION __handlerDisposition; \ - __HandlerData(__ParamType param) : __param(param) {} \ + __ParamType __param = __paramRef; \ + auto tryBlock = [](__ParamType __paramDef) \ + { + +// Start of an exception handler. If an exception raised by the RaiseException +// occurs in the try block and the disposition is EXCEPTION_EXECUTE_HANDLER, +// the handler code is executed. If the disposition is EXCEPTION_CONTINUE_SEARCH, +// the exception is rethrown. The EXCEPTION_CONTINUE_EXECUTION disposition is +// not supported. +#define PAL_EXCEPT(dispositionExpression) \ }; \ - __HandlerData __handlerData(__paramRef); \ - class __Body \ + const bool isFinally = false; \ + auto finallyBlock = []() {}; \ + try \ { \ - public: \ - static void Run(void *__pvHandlerData) \ + tryBlock(__param); \ + } \ + catch (PAL_SEHException& ex) \ + { \ + EXCEPTION_DISPOSITION disposition = dispositionExpression; \ + _ASSERTE(disposition != EXCEPTION_CONTINUE_EXECUTION); \ + if (disposition == EXCEPTION_CONTINUE_SEARCH) \ { \ - __ParamType __paramDef = ((__HandlerData *)__pvHandlerData)->__param; \ - PAL_DUMMY_CALL; - -// On Windows 32bit, we dont invoke filters on the second pass. -// To ensure the same happens on the Mac, we check if we are -// in the first phase or not. If we are, we invoke the -// filter and save the disposition in a local static. -// -// However, if we are not in the first phase but in the second, -// and thus unwinding, then we return the disposition saved -// from the first pass back (similar to how CRT -// does it on x86). -#define PAL_EXCEPT(dispositionExpression) \ - } \ - static EXCEPTION_DISPOSITION Handler( \ - EXCEPTION_POINTERS *ExceptionPointers, \ - PAL_DISPATCHER_CONTEXT *DispatcherContext, \ - void *pvHandlerData) \ - { \ - DEBUG_OK_TO_RETURN_BEGIN(PAL_EXCEPT) \ - __HandlerData *pHandlerData = (__HandlerData *)pvHandlerData; \ - void *pvParam = NULL; \ - pvParam = pHandlerData->__param; \ - if (!(ExceptionPointers->ExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)) \ - pHandlerData->__handlerDisposition = (EXCEPTION_DISPOSITION) (dispositionExpression); \ - return pHandlerData->__handlerDisposition; \ - DEBUG_OK_TO_RETURN_END(PAL_EXCEPT) \ - } \ - }; \ - BOOL __fExecuteHandler; \ - _Unwind_Exception *__exception = \ - PAL_TryExcept(__Body::Run, __Body::Handler, &__handlerData, &__fExecuteHandler); \ - PAL_NoHolder __exceptionHolder; \ - if (__exception && __fExecuteHandler) \ - { \ - PAL_CatchHolder __catchHolder(__exception); \ - __exception = NULL; - -#define PAL_EXCEPT_FILTER(filter) PAL_EXCEPT(filter(ExceptionPointers, pvParam)) - -// 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(((ExceptionPointers->ExceptionRecord->ExceptionCode == dwExceptionCode)?EXCEPTION_EXECUTE_HANDLER:EXCEPTION_CONTINUE_SEARCH)) + throw; \ + } -#define PAL_FINALLY \ - } \ - static EXCEPTION_DISPOSITION Filter( \ - EXCEPTION_POINTERS *ExceptionPointers, \ - PAL_DISPATCHER_CONTEXT *DispatcherContext, \ - void *pvHandlerData) \ - { \ - DEBUG_OK_TO_RETURN_BEGIN(PAL_FINALLY) \ - return EXCEPTION_CONTINUE_SEARCH; \ - DEBUG_OK_TO_RETURN_END(PAL_FINALLY) \ - } \ - }; \ - BOOL __fExecuteHandler; \ - _Unwind_Exception *__exception = \ - PAL_TryExcept(__Body::Run, __Body::Filter, &__handlerData, &__fExecuteHandler); \ - PAL_ExceptionHolder __exceptionHolder(__exception); \ - { -#define PAL_ENDTRY \ - } \ - if (__exception) \ - { \ - __exceptionHolder.SuppressRelease(); \ - PAL_Leave(PAL_BoundaryBottom); \ - _Unwind_Resume(__exception); \ - } \ +// Start of an exception handler. It works the same way as the PAL_EXCEPT except +// that the disposition is obtained by calling the specified filter. +#define PAL_EXCEPT_FILTER(filter) PAL_EXCEPT(filter(&ex.ExceptionPointers, __param)) + +// Start of a finally block. The finally block is executed both when the try block +// finishes or when an exception is raised using the RaiseException in it. +#define PAL_FINALLY \ + }; \ + const bool isFinally = true; \ + auto finallyBlock = [&]() \ + { + +// End of an except or a finally block. +#define PAL_ENDTRY \ + }; \ + if (isFinally) \ + { \ + try \ + { \ + tryBlock(__param); \ + } \ + catch (...) \ + { \ + finallyBlock(); \ + throw; \ + } \ + finallyBlock(); \ + } \ } -#if _DEBUG -void PAL_CheckVirtualUnwind(); -#else // _DEBUG -#define PAL_CheckVirtualUnwind() -#endif // _DEBUG - - #endif // FEATURE_PAL_SXS -PALIMPORT -PAL_NORETURN -VOID -PALAPI -PAL_CppRethrow(); - -// Define PAL_CPP_THROW in terms of PAL_CPP_RETHROW, which does not throw -// using the C++ runtime, but our own implementation that will also call -// vectored handlers. -#define PAL_CPP_THROW(type,expr) \ - { \ - type __exn = expr; \ - PAL_Leave(PAL_BoundaryBottom); \ - PAL_CPP_TRY \ - { \ - throw __exn; \ - } \ - PAL_CPP_CATCH_ALL \ - { \ - PAL_CPP_RETHROW; \ - } \ - PAL_CPP_ENDTRY \ - } -#define PAL_CPP_RETHROW PAL_CppRethrow(); - +#define PAL_CPP_THROW(type, obj) { throw obj; } +#define PAL_CPP_RETHROW { throw; } #define PAL_CPP_TRY try { #define PAL_CPP_CATCH_EXCEPTION(ident) } catch (Exception *ident) { PAL_Reenter(PAL_BoundaryBottom); #define PAL_CPP_CATCH_EXCEPTION_NOARG } catch (Exception *) { PAL_Reenter(PAL_BoundaryBottom); diff --git a/src/pal/inc/pal_assert.h b/src/pal/inc/pal_assert.h index a1c4711381..d5a1d2d4a5 100644 --- a/src/pal/inc/pal_assert.h +++ b/src/pal/inc/pal_assert.h @@ -23,21 +23,13 @@ extern "C" { // C_ASSERT() can be used to perform many compile-time assertions: // type sizes, field offsets, etc. // -// An assertion failure results in error C2118: negative subscript. -// or -// size of array `__C_ASSERT__' is negative -// - -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#define C_ASSERT(e) static_assert(e, #e) // // 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]; +#define CPP_ASSERT(n, e) static_assert(e, #e) #endif // __cplusplus diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt index 3e4e9bbcc8..721bbba4a9 100644 --- a/src/pal/src/CMakeLists.txt +++ b/src/pal/src/CMakeLists.txt @@ -39,6 +39,7 @@ add_compile_options(-fPIC) set(SOURCES arch/i386/context.cpp + arch/i386/context2.S arch/i386/processor.cpp cruntime/file.cpp cruntime/filecrt.cpp diff --git a/src/pal/src/arch/i386/context.cpp b/src/pal/src/arch/i386/context.cpp index 518539fffc..cb1d045e7d 100644 --- a/src/pal/src/arch/i386/context.cpp +++ b/src/pal/src/arch/i386/context.cpp @@ -31,12 +31,8 @@ Abstract: SET_DEFAULT_DEBUG_CHANNEL(DEBUG); - -void CONTEXT_CaptureContext(LPCONTEXT lpContext) -{ - // TODO: this needs to be implemented. See context2.s - _ASSERT(FALSE); -} +// in context2.S +extern void CONTEXT_CaptureContext(LPCONTEXT lpContext); #ifdef _X86_ #define CONTEXT_ALL_FLOATING (CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS) diff --git a/src/pal/src/arch/i386/context2.s b/src/pal/src/arch/i386/context2.S index 535506cf00..6ec622a51b 100644 --- a/src/pal/src/arch/i386/context2.s +++ b/src/pal/src/arch/i386/context2.S @@ -8,6 +8,8 @@ // and is always apply to the current thread. // +#include "macros.inc" + #ifdef BIT64 #define CONTEXT_CONTROL 1 // SegSs, Rsp, SegCs, Rip, and EFlags @@ -76,8 +78,8 @@ // Incoming: // RDI: Context* // - .globl _CONTEXT_CaptureContext -_CONTEXT_CaptureContext: + .globl C_FUNC(CONTEXT_CaptureContext) +C_FUNC(CONTEXT_CaptureContext): testb $CONTEXT_INTEGER, CONTEXT_ContextFlags(%rdi) je 0f mov %rdi, CONTEXT_Rdi(%rdi) @@ -166,8 +168,8 @@ _CONTEXT_CaptureContext: #define CONTEXT_Xmm6 CONTEXT_Xmm5+16 #define CONTEXT_Xmm7 CONTEXT_Xmm6+16 - .globl _CONTEXT_CaptureContext -_CONTEXT_CaptureContext: + .globl C_FUNC(CONTEXT_CaptureContext) +C_FUNC(CONTEXT_CaptureContext): push %eax mov 8(%esp), %eax mov %edi, CONTEXT_Edi(%eax) diff --git a/src/pal/src/arch/i386/runfilter.s b/src/pal/src/arch/i386/runfilter.s deleted file mode 100644 index 1bf2f7438b..0000000000 --- a/src/pal/src/arch/i386/runfilter.s +++ /dev/null @@ -1,158 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// -// -// Implementation of the PAL_RunFilter primitive that allows -// to run a filter guarded by a personality routine that can -// deal with nested exceptions. -// - -#define ALIGN_UP(x) ((x + 15) & ~15) - -#ifdef BIT64 - -#define SIZEOF_ARG_REGISTERS 32 -#define FRAME_SIZE ALIGN_UP(SIZEOF_ARG_REGISTERS) - - .text - .globl _PAL_RunFilter -_PAL_RunFilter: -LFB7: - push %rbp -LCFI0: - mov %rsp, %rbp -LCFI1: - sub $FRAME_SIZE, %rsp - mov %rdi, (%rsp) // ExceptionPointers - mov %rsi, 8(%rsp) // DispatcherContext - mov %rdx, 16(%rsp) // pvParam - mov %rcx, 24(%rsp) // pfnFilter - - // Filters need to be passed ExceptionPointers and pvParam arguments, in that order. - // ExceptionPointers is already in the right register (RDI), so setup pvParam to be - // in RSI - mov %rdx, %rsi -LEHB0: - call *%rcx // Invoke the filter -LEHE0: - leave - ret -LFE7: - -#else // BIT64 - -#define SIZEOF_ARG_REGISTERS 12 -#define FRAME_SIZE ALIGN_UP(8 + SIZEOF_ARG_REGISTERS) - 8 - - .text - .globl _PAL_RunFilter -_PAL_RunFilter: -LFB7: - pushl %ebp -LCFI0: - movl %esp, %ebp -LCFI1: - subl $FRAME_SIZE, %esp - movl 8(%ebp), %eax // exception pointers - movl %eax, (%esp) - movl 12(%ebp), %eax // dispatcher context - movl %eax, 4(%esp) - movl 16(%ebp), %eax // param - movl %eax, 8(%esp) -LEHB0: - call *20(%ebp) // filter -LEHE0: - leave - ret -LFE7: - -#endif // BIT64 else - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -CIE_SEHFilterPersonality: - .long LECIE1-LSCIE1 -LSCIE1: - .long 0x0 - .byte 0x1 - .ascii "zPLR\0" - .byte 0x1 -#ifdef BIT64 - .byte 0x78 // data_align: -8 - .byte 16 // return address register: rip -#else // BIT64 - .byte 0x7c // data_align: -4 - .byte 0x8 // return address register: eip -#endif // BIT64 else - .byte 0x7 - .byte 0x9b -#ifdef BIT64 - .long _PAL_SEHFilterPersonalityRoutine+4@GOTPCREL -#else // BIT64 - .long L_PAL_SEHFilterPersonalityRoutine$non_lazy_ptr-. -#endif // BIT64 else - .byte 0x10 - .byte 0x10 - .byte 0xc // DW_CFA_def_cfa -#ifdef BIT64 - .byte 0x7 // operand1 = rsp - .byte 0x8 // operand2 = offset 8 - .byte 0x80 | 16 // DW_CFA_offset of return address register -#else // BIT64 - .byte 0x5 // operand1 = esp - .byte 0x4 // operand2 = offset 4 - .byte 0x80 | 8 // DW_CFA_offset of return address register -#endif // BIT64 else - .byte 0x1 // operand1 = 1 word - .align 2 -LECIE1: - - .globl _PAL_RunFilter.eh -_PAL_RunFilter.eh: -LSFDE1: - .set LLFDE1,LEFDE1-LASFDE1 - .set LFL7,LFE7-LFB7 - .long LLFDE1 -LASFDE1: - .long LASFDE1-CIE_SEHFilterPersonality -#ifdef BIT64 - .quad LFB7-. - .quad LFL7 - .byte 0x8 - .quad 0x0 -#else // BIT64 - .long LFB7-. - .long LFL7 - .byte 0x4 - .long 0x0 -#endif // BIT64 else - .byte 0x4 // DW_CFA_advance_loc4 - .long LCFI0-LFB7 - .byte 0xe // DW_CFA_def_cfa_offset -#ifdef BIT64 - .byte 0x10 - .byte 0x80 | 6 // DW_CFA_offset rbp -#else // BIT64 - .byte 0x8 - .byte 0x80 | 4 // DW_CFA_offset ebp -#endif // BIT64 else - .byte 0x2 - .byte 0x4 // DW_CFA_advance_loc4 - .long LCFI1-LCFI0 - .byte 0xd // DW_CFA_def_cfa_register -#ifdef BIT64 - .byte 6 // operand1 = rbp -#else // BIT64 - .byte 4 // operand1 = ebp -#endif // BIT64 - .align 2 -LEFDE1: - -#ifndef BIT64 - - .section __IMPORT,__pointers,non_lazy_symbol_pointers -L_PAL_SEHFilterPersonalityRoutine$non_lazy_ptr: - .indirect_symbol _PAL_SEHFilterPersonalityRoutine - .long 0 - -#endif // BIT64 diff --git a/src/pal/src/arch/i386/tryexcept.s b/src/pal/src/arch/i386/tryexcept.s deleted file mode 100644 index f0bea999ad..0000000000 --- a/src/pal/src/arch/i386/tryexcept.s +++ /dev/null @@ -1,207 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -// ==++== -// - -// ==--== -// -// Implementation of the PAL_TryExcept primitive for MSVC-style -// exception handling. -// - -#define ALIGN_UP(x) ((x + 15) & ~15) - -#ifdef BIT64 - -// GCC follows the AMD64 ABI calling convention which is considerably different from the Microsoft AMD64 calling convention. -// -// With MSVC, the first four arguments are passed in RCX, RDX, R8, R9 and the remaining on the stack. -// With GCC, the first six arguments are passed in RDI, RSI, RDX, RCX, R8, R9 and the remaining on the stack. - -// => Size of the total number of arguments PAL_TryExcept takes (32 bytes) + -// => 1 stack slot (8 bytes) to preserve "actions" flags when PAL_SEHPersonalityRoutine is invoked during unwind copies -// data to the stack location before fixing the context to invoke PAL_CallRunHandler + -// => 1 stack slot (8 bytes) to ensure stack is 16bytes aligned. -// -// Hence, the 48 bytes frame size. -#define SIZEOF_ARG_REGISTERS 48 -#define FRAME_SIZE ALIGN_UP(SIZEOF_ARG_REGISTERS) - - .text - .globl _PAL_TryExcept -_PAL_TryExcept: -LFB7: - push %rbp -LCFI0: - mov %rsp, %rbp -LCFI1: - sub $FRAME_SIZE, %rsp - mov %rdi, (%rsp) // Move the Body address to the stack - mov %rsi, 8(%rsp) // Move the Filter address to the stack - mov %rdx, 16(%rsp) // Move pvParam (i.e. HandlerData) to the stack - mov %rcx, 24(%rsp) // Move pfExecuteHandler value to the stack - mov %rdi, %r9 // Move the body address to r9 - mov %rdx, %rdi // Move the HandlerData argument to RDI - this will serve as the first (and only) argument passed to the __try block body below -LEHB0: - call *%r9 // ..and invoke the body of the __try block -LEHE0: - xor %rax, %rax // NULL, meaning "do not run handler" - jmp Lepilog - .globl _PAL_CallRunHandler -_PAL_CallRunHandler: - // Note: First two args (actions and exceptionObject) have already been - // setup by PAL_SEHPersonalityRoutine's cleanup phase handling. They are at - // RSP+32 and RSP+48 respectively. - // - // Prepare the arguments to be passed to PAL_RunHandler. - mov 32(%rsp), %rdi // actions - mov 40(%rsp), %rsi // exceptionObject - mov 8(%rsp), %rdx // filter - mov 16(%rsp), %rcx // param - mov 24(%rsp), %r8 // pfExecuteHandler - call _PAL_RunHandler -Lepilog: - leave - ret -LFE7: - -#else // BIT64 - -#define SIZEOF_ARG_REGISTERS 20 -#define FRAME_SIZE ALIGN_UP(8 + SIZEOF_ARG_REGISTERS) - 8 - - .text - .globl _PAL_TryExcept -_PAL_TryExcept: -LFB7: - pushl %ebp -LCFI0: - movl %esp, %ebp -LCFI1: - subl $FRAME_SIZE, %esp - movl 16(%ebp), %eax // param - movl %eax, (%esp) -LEHB0: - call *8(%ebp) // body -LEHE0: - xor %eax, %eax // NULL, meaning "do not run handler" - jmp Lepilog - .globl _PAL_CallRunHandler -_PAL_CallRunHandler: - // note: first two args already set when we get here - mov 12(%ebp), %eax // filter - mov %eax, 8(%esp) - mov 16(%ebp), %eax // param - mov %eax, 12(%esp) - mov 20(%ebp), %eax // pfExecuteHandler - mov %eax, 16(%esp) - call L_PAL_RunHandler$stub -Lepilog: - leave - ret -LFE7: - -#endif // BIT64 else - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -CIE_SEHPersonality: - .long LECIE1-LSCIE1 -LSCIE1: - .long 0x0 - .byte 0x1 - #ifdef BIT64 - .ascii "zPLR\0" - .byte 0x1 - .byte 0x78 // data_align: -8 - .byte 16 // return address register: rip - .byte 0x7 - .byte 0x9b - .long _PAL_SEHPersonalityRoutine+4@GOTPCREL - .byte 0x10 - .byte 0x10 - .byte 0xc // DW_CFA_def_cfa - .byte 0x7 // operand1 = rsp - .byte 0x8 // operand2 = offset 8 - .byte 0x80 | 16 // DW_CFA_offset of return address register - .byte 0x1 // operand1 = 1 word - .align 2 -#else // BIT64 - .ascii "zPLR\0" - .byte 0x1 - .byte 0x7c // data_align: -4 - .byte 0x8 // return address register: eip - .byte 0x7 - .byte 0x9b - .long L_PAL_SEHPersonalityRoutine$non_lazy_ptr-. - .byte 0x10 - .byte 0x10 - .byte 0xc // DW_CFA_def_cfa - .byte 0x5 // operand1 = esp - .byte 0x4 // operand2 = offset 4 - .byte 0x80 | 8 // DW_CFA_offset of return address register - .byte 0x1 // operand1 = 1 word - .align 2 -#endif // BIT64 else -LECIE1: - - .globl _PAL_TryExcept.eh -_PAL_TryExcept.eh: -LSFDE1: - .set LLFDE1,LEFDE1-LASFDE1 - .set LFL7,LFE7-LFB7 - .long LLFDE1 -LASFDE1: - .long LASFDE1-CIE_SEHPersonality -#ifdef BIT64 - .quad LFB7-. - .quad LFL7 - .byte 0x8 - .quad 0x0 - .byte 0x4 // DW_CFA_advance_loc4 -#else // BIT64 - .long LFB7-. - .long LFL7 - .byte 0x4 - .long 0x0 - .byte 0x4 // DW_CFA_advance_loc4 -#endif // BIT64 else - .long LCFI0-LFB7 - .byte 0xe // DW_CFA_def_cfa_offset -#ifdef BIT64 - .byte 0x10 - .byte 0x80 | 6 // DW_CFA_offset rbp -#else // BIT64 - .byte 0x8 - .byte 0x80 | 4 // DW_CFA_offset ebp -#endif // BIT64 else - .byte 0x2 - .byte 0x4 // DW_CFA_advance_loc4 - .long LCFI1-LCFI0 - .byte 0xd // DW_CFA_def_cfa_register -#ifdef BIT64 - .byte 6 // operand1 = rbp - .align 2 -#else // BIT64 - .byte 4 // operand1 = ebp - .align 2 -#endif // BIT64 - -LEFDE1: - -#ifndef BIT64 - - .section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5 -L_PAL_RunHandler$stub: - .indirect_symbol _PAL_RunHandler - hlt ; hlt ; hlt ; hlt ; hlt - - .section __IMPORT,__pointers,non_lazy_symbol_pointers -L_PAL_SEHPersonalityRoutine$non_lazy_ptr: - .indirect_symbol _PAL_SEHPersonalityRoutine - .long 0 - -#endif // !BIT64 - diff --git a/src/pal/src/config.h.in b/src/pal/src/config.h.in index 6a32a57d2c..03f31a0fe9 100644 --- a/src/pal/src/config.h.in +++ b/src/pal/src/config.h.in @@ -13,6 +13,7 @@ #cmakedefine01 HAVE_SYS_TIME_H #cmakedefine01 HAVE_PTHREAD_NP_H #cmakedefine01 HAVE_SYS_LWP_H +#cmakedefine01 HAVE_LIBUNWIND_H #cmakedefine01 HAVE_KQUEUE #cmakedefine01 HAVE_GETPWUID_R diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake index 0da2498e47..972d6add36 100644 --- a/src/pal/src/configure.cmake +++ b/src/pal/src/configure.cmake @@ -6,6 +6,7 @@ include(CheckIncludeFiles) include(CheckStructHasMember) include(CheckTypeSize) +set(CMAKE_REQUIRED_DEFINITIONS "-D_DEFAULT_SOURCE") check_include_files(ieeefp.h HAVE_IEEEFP_H) check_include_files(alloca.h HAVE_ALLOCA_H) check_include_files(sys/vmparam.h HAVE_SYS_VMPARAM_H) @@ -16,6 +17,7 @@ check_include_files(crt_externs.h HAVE_CRT_EXTERNS_H) check_include_files(sys/time.h HAVE_SYS_TIME_H) check_include_files(pthread_np.h HAVE_PTHREAD_NP_H) check_include_files(sys/lwp.h HAVE_SYS_LWP_H) +check_include_files(libunwind.h HAVE_LIBUNWIND_H) check_function_exists(kqueue HAVE_KQUEUE) check_function_exists(getpwuid_r HAVE_GETPWUID_R) @@ -51,7 +53,6 @@ check_function_exists(semget HAS_SYSV_SEMAPHORES) check_function_exists(pthread_mutex_init HAS_PTHREAD_MUTEXES) check_function_exists(ttrace HAVE_TTRACE) -set(CMAKE_REQUIRED_DEFINITIONS "-D_DEFAULT_SOURCE") check_struct_has_member ("struct stat" st_atimespec "sys/types.h;sys/stat.h" HAVE_STAT_TIMESPEC) check_struct_has_member ("struct stat" st_atimensec "sys/types.h;sys/stat.h" HAVE_STAT_NSEC) check_struct_has_member ("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF) @@ -76,7 +77,6 @@ set(CMAKE_EXTRA_INCLUDE_FILE procfs.h) check_type_size(prwatch_t PRWATCH_T) set(CMAKE_EXTRA_INCLUDE_FILE) check_type_size(off_t SIZEOF_OFF_T) -set(CMAKE_REQUIRED_DEFINITIONS) check_cxx_symbol_exists(tzname "time.h" HAVE_TZNAME) check_cxx_symbol_exists(timezone "time.h" HAVE_TIMEZONE_VAR) @@ -834,6 +834,7 @@ int main() return 1; }" FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL) +set(CMAKE_REQUIRED_DEFINITIONS) if(CMAKE_SYSTEM_NAME STREQUAL Darwin) set(HAVE_COREFOUNDATION 1) @@ -853,6 +854,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL Darwin) set(HAS_FTRUNCATE_LENGTH_ISSUE 1) set(UNWIND_CONTEXT_IS_UCONTEXT_T 0) else() + if(NOT HAVE_LIBUNWIND_H) + unset(HAVE_LIBUNWIND_H CACHE) + message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8 and libunwind8-dev (or the appropriate packages for your platform)") + endif() set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0) set(PAL_PTRACE "ptrace((cmd), (pid), (void*)(addr), (data))") set(PAL_PT_ATTACH PTRACE_ATTACH) diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp index b3b5d18f87..0b3a51187a 100644 --- a/src/pal/src/exception/seh-unwind.cpp +++ b/src/pal/src/exception/seh-unwind.cpp @@ -28,52 +28,16 @@ Abstract: #include "pal/context.h" #include <dlfcn.h> #include <exception> +#if HAVE_LIBUNWIND_H #define UNW_LOCAL_ONLY #include <libunwind.h> - -//---------------------------------------------------------------------- -// Exception Handling ABI Level I: Base ABI -//---------------------------------------------------------------------- - -typedef UINT_PTR _Unwind_Ptr; - -struct dwarf_eh_bases -{ - _Unwind_Ptr dataRelBase, textRelBase; -}; - -extern "C" _Unwind_Ptr _Unwind_GetDataRelBase(_Unwind_Context *context); -extern "C" _Unwind_Ptr _Unwind_GetTextRelBase(_Unwind_Context *context); - -typedef BYTE fde; -extern "C" const fde *_Unwind_Find_FDE(void *ip, dwarf_eh_bases *bases); - -//---------------------------------------------------------------------- -// Exception Handling ABI Level II: C++ ABI -//---------------------------------------------------------------------- - -struct __cxa_exception -{ - std::type_info *exceptionType; - void (*exceptionDestructor)(void *); - std::unexpected_handler unexpectedHandler; - std::terminate_handler terminateHandler; - __cxa_exception *nextException; - - int handlerCount; - int handlerSwitchValue; - const char *actionRecord; - const char *languageSpecificData; - void *catchTemp; - void *adjustedPtr; - - _Unwind_Exception unwindHeader; -}; +#endif //---------------------------------------------------------------------- // Virtual Unwinding //---------------------------------------------------------------------- +#if HAVE_LIBUNWIND_H #if UNWIND_CONTEXT_IS_UCONTEXT_T static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext) { @@ -195,297 +159,10 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP return TRUE; } - -#if _DEBUG -//---------------------------------------------------------------------- -// Virtual Unwinding Debugging Assertions -//---------------------------------------------------------------------- - -// Print a trace of virtually unwinding the stack. -// This helps us diagnose non-unwindable stacks. -// Unfortunately, calling this function from gdb will not be very useful, -// since gdb makes it look like it had been called directly from "start" -// (whose unwind info says we reached the end of the stack). -// You can still call it from, say, RaiseTheExceptionInternalOnly. - -// (non-static to ease debugging) -void DisplayContext(_Unwind_Context *context) -{ - fprintf(stderr, " ip =%p", _Unwind_GetIP(context)); - fprintf(stderr, " cfa=%p", _Unwind_GetCFA(context)); -#if defined(_X86_) - // TODO: display more registers -#endif - fprintf(stderr, "\n"); -} - -static _Unwind_Reason_Code PrintVirtualUnwindCallback(_Unwind_Context *context, void *pvParam) -{ - int *pFrameNumber = (int *) pvParam; - - void *ip = _Unwind_GetIP(context); - const char *module = NULL; - const char *name = 0; - int offset = 0; - - Dl_info dl_info; - if (dladdr(ip, &dl_info)) - { - module = dl_info.dli_fname; - if (dl_info.dli_sname) - { - name = dl_info.dli_sname; - offset = (char *) ip - (char *) dl_info.dli_saddr; - } - else - { - name = "<img-base>"; - offset = (char *) ip - (char *) dl_info.dli_fbase; - } - } - - if (module) - fprintf(stderr, "#%-3d %s!%s+%d\n", *pFrameNumber, module, name, offset); - else - fprintf(stderr, "#%-3d ??\n", *pFrameNumber); - DisplayContext(context); - (*pFrameNumber)++; - return _URC_NO_REASON; -} - -extern "C" void PAL_PrintVirtualUnwind() -{ - BOOL fEntered = PAL_ReenterForEH(); - - fprintf(stderr, "\nVirtual unwind of PAL thread %p\n", InternalGetCurrentThread()); - int frameNumber = 0; - _Unwind_Reason_Code urc = _Unwind_Backtrace(PrintVirtualUnwindCallback, &frameNumber); - fprintf(stderr, "End of stack (return code=%d).\n", urc); - - if (fEntered) - { - PAL_Leave(PAL_BoundaryEH); - } -} - -static const char *PAL_CHECK_UNWINDABLE_STACKS = "PAL_CheckUnwindableStacks"; - -enum CheckUnwindableStacksMode -{ - // special value to indicate we've not initialized yet - CheckUnwindableStacks_Uninitialized = -1, - - CheckUnwindableStacks_Off = 0, - CheckUnwindableStacks_On = 1, - CheckUnwindableStacks_Thorough = 2, - - CheckUnwindableStacks_Default = CheckUnwindableStacks_On -}; - -static CheckUnwindableStacksMode s_mode = CheckUnwindableStacks_Uninitialized; - -// A variant of the above. This one's not meant for CLR developers to use for tracing, -// but implements debug checks to assert stack consistency. -static _Unwind_Reason_Code CheckVirtualUnwindCallback(_Unwind_Context *context, void *pvParam) -{ - void *ip = _Unwind_GetIP(context); - - // If we reach an IP that we cannot find a module for, - // then we ended up in dynamically-generated code and - // the stack will not be unwindable past this point. - Dl_info dl_info; - if (dladdr(ip, &dl_info) == 0 || - ((s_mode == CheckUnwindableStacks_Thorough) && - ( dl_info.dli_sname == NULL || - ( _Unwind_Find_FDE(ip, NULL) == NULL && - strcmp(dl_info.dli_sname, "start") && - strcmp(dl_info.dli_sname, "_thread_create_running"))))) - { - *(BOOL *) pvParam = FALSE; - } - - return _URC_NO_REASON; -} - -extern "C" void PAL_CheckVirtualUnwind() -{ - if (s_mode == CheckUnwindableStacks_Uninitialized) - { - const char *checkUnwindableStacks = getenv(PAL_CHECK_UNWINDABLE_STACKS); - s_mode = checkUnwindableStacks ? - (CheckUnwindableStacksMode) atoi(checkUnwindableStacks) : CheckUnwindableStacks_Default; - } - - if (s_mode != CheckUnwindableStacks_Off) - { - BOOL fUnwindable = TRUE; - _ASSERTE(_Unwind_Backtrace(CheckVirtualUnwindCallback, &fUnwindable) == _URC_END_OF_STACK); - if (!fUnwindable) - { - PAL_PrintVirtualUnwind(); - ASSERT("Stack not unwindable. Throwing may terminate the process.\n"); - } - } -} -#endif // _DEBUG - -//---------------------------------------------------------------------- -// Registering Vectored Handlers -//---------------------------------------------------------------------- - -static PVECTORED_EXCEPTION_HANDLER VectoredExceptionHandler = NULL; -static PVECTORED_EXCEPTION_HANDLER VectoredContinueHandler = NULL; - -void SetVectoredExceptionHandler(PVECTORED_EXCEPTION_HANDLER pHandler) -{ - PERF_ENTRY(SetVectoredExceptionHandler); - ENTRY("SetVectoredExceptionHandler(pHandler=%p)\n", pHandler); - - _ASSERTE(VectoredExceptionHandler == NULL); - VectoredExceptionHandler = pHandler; - - LOGEXIT("SetVectoredExceptionHandler returns\n"); - PERF_EXIT(SetVectoredExceptionHandler); - -} - -void SetVectoredContinueHandler(PVECTORED_EXCEPTION_HANDLER pHandler) -{ - PERF_ENTRY(SetVectoredContinueHandler); - ENTRY("SetVectoredContinueHandler(pHandler=%p)\n", pHandler); - - _ASSERTE(VectoredContinueHandler == NULL); - VectoredContinueHandler = pHandler; - - LOGEXIT("SetVectoredContinueHandler returns\n"); - PERF_EXIT(SetVectoredContinueHandler); -} - -//---------------------------------------------------------------------- -// Representation of an SEH Exception as a C++ object -//---------------------------------------------------------------------- - -struct PAL_SEHException -{ -public: - // Note that the following two are actually embedded in this heap-allocated - // instance - in contrast to Win32, where the exception record would usually - // be allocated on the stack. This is needed because foreign cleanup handlers - // partially unwind the stack on the second pass. - EXCEPTION_POINTERS ExceptionPointers; - EXCEPTION_RECORD ExceptionRecord; - CONTEXT ContextRecord; - - PAL_SEHException(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContextRecord) - { - ExceptionPointers.ExceptionRecord = &ExceptionRecord; - ExceptionPointers.ContextRecord = &ContextRecord; - ExceptionRecord = *pExceptionRecord; - ContextRecord = *pContextRecord; - nestedExceptionEstablisherFrame = NULL; - } - - static PAL_SEHException *FromExceptionObject(_Unwind_Exception *exceptionObject) - { - if (exceptionObject->exception_class == Class) - { - if (*((__cxa_exception *) (exceptionObject + 1) - 1)->exceptionType == typeid(PAL_SEHException)) - { - return (PAL_SEHException *) (exceptionObject + 1); - } - } - return NULL; - } - - void NestedIn(_Unwind_Context *context) - { - nestedExceptionEstablisherFrame = _Unwind_GetCFA(context); - ExceptionRecord.ExceptionFlags |= EXCEPTION_NESTED_CALL; - } - - void RanThroughFilter(_Unwind_Context *context) - { - if (nestedExceptionEstablisherFrame == _Unwind_GetCFA(context)) - { - // We were processing a nested exception, and we have repeated - // the search phase past the filter that threw the nested exception. - // Thus, clear the corresponding flag now. - ExceptionRecord.ExceptionFlags &= ~EXCEPTION_NESTED_CALL; - } - } - -private: -#ifdef __GNUC__ - static const __uint64_t Class = 0x474e5543432b2b00ULL; // vendor = GNUC, language = C++\0 #else -#error Vendor code not defined for this platform. +#error don't know how to unwind on this platform #endif - // If we encountered a nested exception, the EXCEPTION_NESTED_CALL flag must - // remain set on the exception while unwinding to the frame with the CFA - // stored below. Note that this will always be a PAL_TryExcept frame. - void *nestedExceptionEstablisherFrame; -}; - -EXCEPTION_POINTERS * -PALAPI -PAL_GetExceptionPointers(_Unwind_Exception *exceptionObject) -{ - PAL_SEHException *pSEHException = PAL_SEHException::FromExceptionObject(exceptionObject); - if (pSEHException) - { - return &pSEHException->ExceptionPointers; - } - return NULL; -} - -//---------------------------------------------------------------------- -// Raising Exceptions -//---------------------------------------------------------------------- - -static void DeleteThrownException(_Unwind_Exception *exceptionObject) -{ - // The argument exception has been thrown. - _ASSERTE(std::uncaught_exception()); - - // Deleting it in this way will adjust the uncaught exceptions count. - __cxa_begin_catch(exceptionObject); - __cxa_end_catch(); -} - -static void RunVectoredHandler(EXCEPTION_POINTERS *pExceptionPointers, _Unwind_Exception *exceptionObject, PVECTORED_EXCEPTION_HANDLER pHandler) -{ - if (pHandler != NULL) - { - EXCEPTION_DISPOSITION disposition = pHandler(pExceptionPointers); - switch (disposition) - { - case EXCEPTION_CONTINUE_EXECUTION: - { - BOOL fNonContinuable = pExceptionPointers->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE; - CONTEXT *context = pExceptionPointers->ContextRecord; - if (fNonContinuable) - { - RaiseException(EXCEPTION_NONCONTINUABLE_EXCEPTION, - EXCEPTION_NONCONTINUABLE, 0, NULL); - } - else - { - SetThreadContext(PAL_GetCurrentThread(), context); - } - } - abort(); // should never reach here - case EXCEPTION_CONTINUE_SEARCH: - break; - default: - DeleteThrownException(exceptionObject); - RaiseException(EXCEPTION_INVALID_DISPOSITION, - EXCEPTION_NONCONTINUABLE, 0, NULL); - abort(); // should never reach here - } - } -} - PAL_NORETURN static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord) { @@ -495,35 +172,19 @@ static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord) ContextRecord.ContextFlags = CONTEXT_FULL; CONTEXT_CaptureContext(&ContextRecord); - // Find the caller of RtlpRaiseException. This provides the exact context - // that handlers expect to see, which is the one they would want to fix up - // to resume after a continuable exception. + // Find the caller of RtlpRaiseException. PAL_VirtualUnwind(&ContextRecord, NULL); - // The frame we're looking at now is either RaiseException or PAL_TryExcept. - // If it's RaiseException, we have to unwind one level further to get the - // actual context user code could be resumed at. + // The frame we're looking at now is RaiseException. We have to unwind one + // level further to get the actual context user code could be resumed at. + PAL_VirtualUnwind(&ContextRecord, NULL); #if defined(_X86_) - void *pc = (void *) ContextRecord.Eip; + ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Eip; #elif defined(_AMD64_) - void *pc = (void *) ContextRecord.Rip; + ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Rip; #else #error unsupported architecture #endif - if ((SIZE_T) pc - (SIZE_T) RaiseException < (SIZE_T) pc - (SIZE_T) PAL_TryExcept) - { - PAL_VirtualUnwind(&ContextRecord, NULL); -#if defined(_PPC_) - pc = (void *) ContextRecord.Iar; -#elif defined(_X86_) - pc = (void *) ContextRecord.Eip; -#elif defined(_AMD64_) - pc = (void *) ContextRecord.Rip; -#else -#error unsupported architecture -#endif - } - ExceptionRecord->ExceptionAddress = pc; EXCEPTION_POINTERS pointers; pointers.ExceptionRecord = ExceptionRecord; @@ -533,155 +194,11 @@ static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord) } PAL_NORETURN -static void RaiseExceptionObject(_Unwind_Exception *exceptionObject) -{ - // Dummy exception record for use by foreign exceptions. - EXCEPTION_RECORD ForeignExceptionRecord = { EXCEPTION_FOREIGN, EXCEPTION_NONCONTINUABLE, NULL, NULL, 0 }; - EXCEPTION_POINTERS ForeignExceptionPointers = { &ForeignExceptionRecord, NULL }; - - bool fSkipVEH = false; - - EXCEPTION_POINTERS *pExceptionPointers = PAL_GetExceptionPointers(exceptionObject); - if (!pExceptionPointers) - { - pExceptionPointers = &ForeignExceptionPointers; - } - else - { - fSkipVEH =(pExceptionPointers->ExceptionRecord->ExceptionFlags & EXCEPTION_SKIP_VEH)?true:false; - if (!fSkipVEH) - { - // For exceptions that we know about, keep a reference in the corresponding - // EXCEPTION_RECORD incase this turns out to be an async exception in managed code. - pExceptionPointers->ExceptionRecord->ExceptionInformation[NATIVE_EXCEPTION_ASYNC_SLOT] = (ULONG_PTR)exceptionObject; - } - } - - if (!fSkipVEH) - { - RunVectoredHandler(pExceptionPointers, exceptionObject, VectoredExceptionHandler); - } - - _Unwind_Reason_Code urc; - PAL_Leave(PAL_BoundaryEH); - urc = _Unwind_RaiseException(exceptionObject); - - // _Unwind_RaiseException is supposed to return an _Unwind_Reason_Code. - // However, it's not implemented according to spec. So we always have - // to assume that we got _URC_END_OF_STACK. - if (urc == (_Unwind_Reason_Code) (UINT_PTR) exceptionObject) - { - urc = _URC_END_OF_STACK; - } - _ASSERTE(urc == _URC_END_OF_STACK); - - PAL_Reenter(PAL_BoundaryEH); - RunVectoredHandler(pExceptionPointers, exceptionObject, VectoredContinueHandler); - - DeleteThrownException(exceptionObject); - - WARN("unhandled exception; terminating self\n"); - - abort(); - // unreached -} - -static void ThrowHelper(void *pvParam) -{ - PEXCEPTION_POINTERS lpExceptionPointers = (PEXCEPTION_POINTERS) pvParam; - PAL_Leave(PAL_BoundaryEH); - throw PAL_SEHException(lpExceptionPointers->ExceptionRecord, lpExceptionPointers->ContextRecord); -} - -static void RethrowHelper(void *pvParam) -{ - PAL_Leave(PAL_BoundaryEH); - throw; -} - -static EXCEPTION_DISPOSITION ThrowFilter( - EXCEPTION_POINTERS *ExceptionPointers, - PAL_DISPATCHER_CONTEXT *DispatcherContext, - void *pvParam) -{ - return EXCEPTION_EXECUTE_HANDLER; -} - -PAL_NORETURN -VOID -PALAPI -PAL_CppRethrow() -{ - // Throw the exception using C++ throw, but intercept the exception so that - // we can raise it using our runtime, which supported vectored handlers. - BOOL fExecuteHandler; - _Unwind_Exception *exceptionObject = - PAL_TryExcept(RethrowHelper, ThrowFilter, NULL, &fExecuteHandler); - _ASSERTE(exceptionObject != NULL); - PAL_CheckVirtualUnwind(); - RaiseExceptionObject(exceptionObject); -} - -PAL_NORETURN void SEHRaiseException(CPalThread *pthrCurrent, PEXCEPTION_POINTERS lpExceptionPointers, int signal_code) { - _Unwind_Exception *exceptionObject = NULL; - - if (lpExceptionPointers->ExceptionRecord->ExceptionFlags & EXCEPTION_SKIP_VEH) - { - // If we are going to skip VEH, then it implies we are going to dispatch - // an async exception in managed code. For this case, extract the - // native exception object from the ExceptionInformation array that was saved there - // when PAL_DispatchException had initially raised the exception. - exceptionObject = (_Unwind_Exception *)lpExceptionPointers->ExceptionRecord->ExceptionInformation[NATIVE_EXCEPTION_ASYNC_SLOT]; - lpExceptionPointers->ExceptionRecord->ExceptionInformation[NATIVE_EXCEPTION_ASYNC_SLOT] = (ULONG_PTR)NULL; - } - - if (exceptionObject == NULL) - { - // Throw the exception using C++ throw, but intercept the exception so that - // we can raise it using our runtime, which supported vectored handlers. - BOOL fExecuteHandler; - exceptionObject = PAL_TryExcept(ThrowHelper, ThrowFilter, lpExceptionPointers, &fExecuteHandler); - } - - _ASSERTE(exceptionObject != NULL); - - // Note: We cannot call PAL_CheckVirtualUnwind here, since we this function - // may be called for a fault in dynamically-generated code. - -#if defined(_AMD64_) - // When PAL_TryExcept returns, it has executed the second pass for handling the exception - // that was raised by ThrowHelper. As part of processing the second pass, PAL_RunHandler - // would have set the EXCEPTION_UNWINDING flag (and possibly, even the EXCEPTION_TARGET_UNWIND flag) - // in the ExceptionRecord contained inside the exception object. - // - // When this exception object is passed to the RunVectoredExceptionHandler, the exception pointers - // passed to the vectored handler would be the one extracted from the exception object. Since that - // would have the unwinding flag set, any code that checks for the flag to conditional process the - // exception would go awry. - // - // To fix this problem, we will fetch the ExceptionPointers from the exception object and clear off - // any such flags. - // - // Note 1: This problem is also present when the exception object is seen by the various native - // personality routines (e.g. UnwindThunkPersonality). However, stack frame based handling - // of exceptions is not affected by this problem since all of our native personality routines - // clear off the existing flags and reset them again based upon the active phase (first or second) - // of exception dispatch before passing the exception record to CLR's managed personality routines. - // - // Note 2: This problem is also applicable to Mac X86. TODO: Fix this problem for MacX86. - EXCEPTION_POINTERS *pExceptionPointers = PAL_GetExceptionPointers(exceptionObject); - _ASSERTE(pExceptionPointers != NULL); - - // Clear of the EXCEPTION_UNWINDING/EXCEPTION_TARGET_UNWIND flags - pExceptionPointers->ExceptionRecord->ExceptionFlags = - (pExceptionPointers->ExceptionRecord->ExceptionFlags & ~(EXCEPTION_UNWINDING|EXCEPTION_TARGET_UNWIND)); -#endif // defined(_AMD64_) - - RaiseExceptionObject(exceptionObject); + throw PAL_SEHException(lpExceptionPointers->ExceptionRecord, lpExceptionPointers->ContextRecord); } /*++ @@ -712,7 +229,13 @@ RaiseException(IN DWORD dwExceptionCode, dwExceptionCode ^= RESERVED_SEH_BIT; } - PAL_CheckVirtualUnwind(); + if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS) + { + WARN("Number of arguments (%d) exceeds the limit " + "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n", + nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS); + nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS; + } EXCEPTION_RECORD exceptionRecord; ZeroMemory(&exceptionRecord, sizeof(EXCEPTION_RECORD)); @@ -724,13 +247,6 @@ RaiseException(IN DWORD dwExceptionCode, exceptionRecord.NumberParameters = nNumberOfArguments; if (nNumberOfArguments) { - if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS) - { - WARN("Number of arguments (%d) exceeds the limit " - "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n", - nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS); - nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS; - } CopyMemory(exceptionRecord.ExceptionInformation, lpArguments, nNumberOfArguments * sizeof(ULONG_PTR)); } @@ -738,372 +254,3 @@ RaiseException(IN DWORD dwExceptionCode, LOGEXIT("RaiseException returns\n"); } - -PAL_NORETURN -VOID -PALAPI -PAL_RaiseException( - IN PEXCEPTION_POINTERS ExceptionPointers) -{ - PAL_CheckVirtualUnwind(); - ExceptionPointers->ExceptionRecord->ExceptionFlags |= EXCEPTION_NONCONTINUABLE; - SEHRaiseException(InternalGetCurrentThread(), ExceptionPointers, 0); -} - -//---------------------------------------------------------------------- -// SEH Personality -//---------------------------------------------------------------------- - -#if defined(__LINUX__) || defined(__APPLE__) -// TODO: Enable these routines for Linux. -EXCEPTION_DISPOSITION -PAL_RunFilter( - PEXCEPTION_POINTERS ExceptionPointers, - PAL_DISPATCHER_CONTEXT *DispatcherContext, - void *pvParam, - PFN_PAL_EXCEPTION_FILTER Filter) -{ - _ASSERT(FALSE); - return 0; -} - -void PAL_CallRunHandler() -{ - _ASSERT(FALSE); -} - -extern "C" -PALAPI -struct _Unwind_Exception *PAL_TryExcept( - PFN_PAL_BODY pfnBody, - PFN_PAL_EXCEPTION_FILTER pfnFilter, - void *pvParam, - BOOL *pfExecuteHandler) -{ - // UNIXTODO: Exception handling - pfnBody(pvParam); - *pfExecuteHandler = FALSE; - return NULL; -} -#else -// from runfilter.s -extern "C" -EXCEPTION_DISPOSITION -PAL_RunFilter(PEXCEPTION_POINTERS ExceptionPointers, - PAL_DISPATCHER_CONTEXT *DispatcherContext, - void *pvParam, - PFN_PAL_EXCEPTION_FILTER Filter); -extern "C" void PAL_CallRunHandler(); -#endif // __LINUX__ - -extern "C" -_Unwind_Reason_Code PAL_SEHPersonalityRoutine( - int version, - _Unwind_Action actions, - __uint64_t exceptionClass, - _Unwind_Exception *exceptionObject, - _Unwind_Context *context) -{ - _Unwind_Reason_Code urc = _URC_NO_REASON; - PAL_Reenter(PAL_BoundaryEH); - - TRACE("actions=%x\n", actions); - _ASSERTE(version == 1); - - // Determine what state the frame is in for which this personality routine - // was invoked. The only function this personality routine is affiliated - // with is PAL_TryExcept, which is assembly code. That function contains - // two calls: one to run the try block, one to run a handler. The - // PAL_CallRunHandler label sits in-between these two, thus we can - // use it to make the distinction which call the exception escaped from. - if (_Unwind_GetIP(context) > (void *) PAL_CallRunHandler) - { - // This personality routine had invoked the handler associated - // with this frame, and the handler raised an exception. - // This is called a "collided unwind". - TRACE("collided unwind\n"); - PAL_SEHException *pSEHException = PAL_SEHException::FromExceptionObject(exceptionObject); - if (pSEHException) - { - pSEHException->ExceptionRecord.ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND; - } - urc = _URC_CONTINUE_UNWIND; - goto exit; - } - - if ((actions & _UA_PHASE_MASK) == _UA_SEARCH_PHASE) - { - // Determine whether this is an SEH exception or a foreign exception. - PAL_SEHException *pSEHException = PAL_SEHException::FromExceptionObject(exceptionObject); - if (pSEHException) - { - pSEHException->ExceptionRecord.ExceptionFlags &= ~EXCEPTION_UNWIND; - } - - // Obtain the filter and parameter from the original frame. - PFN_PAL_EXCEPTION_FILTER pfnFilter; - void *pvParam; -#if defined(_X86_) - pfnFilter = ((PFN_PAL_EXCEPTION_FILTER *) _Unwind_GetGR(context, 4))[3]; // [ebp+12] - pvParam = ((void **) _Unwind_GetGR(context, 4))[4]; // [ebp+16] -#elif defined(_AMD64_) - // Filter address is stored at RSP+8 - // pvParam is stored at RSP+16 - // Refer to PAL_TryExcept implementation for details. - pfnFilter = ((PFN_PAL_EXCEPTION_FILTER *) _Unwind_GetCFA(context))[1]; - pvParam = ((void **) _Unwind_GetCFA(context))[2]; -#else -#error unsupported architecture -#endif - - // Make some of our state available to the filter. - PAL_DISPATCHER_CONTEXT dispatcherContext; - dispatcherContext.actions = actions; - dispatcherContext.exception_object = exceptionObject; - dispatcherContext.context = context; - - // Dummy exception record for use by foreign exceptions. - EXCEPTION_RECORD ForeignExceptionRecord = { EXCEPTION_FOREIGN, EXCEPTION_NONCONTINUABLE, NULL, NULL, 0 }; - EXCEPTION_POINTERS ForeignExceptionPointers = { &ForeignExceptionRecord, NULL }; - - // Run the filter. If this throws, the PAL_SEHFilterPersonalityRoutine - // will be invoked. - EXCEPTION_DISPOSITION disposition = - PAL_RunFilter(pSEHException ? &pSEHException->ExceptionPointers : &ForeignExceptionPointers, - &dispatcherContext, - pvParam, pfnFilter); - TRACE("filter returned %d\n", disposition); - - if (pSEHException) - { - pSEHException->RanThroughFilter(context); - } - - switch (disposition) - { - case EXCEPTION_CONTINUE_EXECUTION: - if (!pSEHException || // foreign exceptions are never continuable - (pSEHException->ExceptionRecord.ExceptionFlags & EXCEPTION_NONCONTINUABLE)) - { - DeleteThrownException(exceptionObject); - RaiseException(EXCEPTION_NONCONTINUABLE_EXCEPTION, - EXCEPTION_NONCONTINUABLE, 0, NULL); - } - else - { - CONTEXT *newContext = pSEHException->ExceptionPointers.ContextRecord; - DeleteThrownException(exceptionObject); - SetThreadContext(PAL_GetCurrentThread(), newContext); - } - abort(); // should never reach here - case EXCEPTION_EXECUTE_HANDLER: - urc = _URC_HANDLER_FOUND; - goto exit; - case EXCEPTION_CONTINUE_SEARCH: - urc = _URC_CONTINUE_UNWIND; - goto exit; - default: - DeleteThrownException(exceptionObject); - RaiseException(EXCEPTION_INVALID_DISPOSITION, - EXCEPTION_NONCONTINUABLE, 0, NULL); - // The above call should never return, but the compiler doesn't know that. - urc = _URC_FATAL_PHASE1_ERROR; - goto exit; - } - } - else - { - _ASSERTE((actions & _UA_PHASE_MASK) == _UA_CLEANUP_PHASE); - - // There is a cleanup to run. Here we behave differently from - // Windows SEH: We unwind the stack up to the frame that installed - // this personality routine, and run the handler from there. - // The advantage is that this is consistent with C++ on this - // platform, wich unwinds the stack also to run destructors for - // objects allocated on the stack. By behaving in the same way, - // we can deal with C++ exceptions colliding with SEH unwinds. -#if defined(_PPC_) - _Unwind_SetGR(context, 3, (void *) actions); - _Unwind_SetGR(context, 4, exceptionObject); -#elif defined(_X86_) - void **args = (void **) _Unwind_GetCFA(context); - args[0] = (void *) actions; - args[1] = exceptionObject; -#elif defined(_AMD64_) - // We have allocated two slots on the stack for preserving these two. - // They are beyond the locations where we spilled the args to PAL_TryExcept - // and hence, are at RSP+32 and RSP+40 respectively. - void **args = (void **) _Unwind_GetCFA(context); - args[4] = (void *) actions; - args[5] = exceptionObject; -#else -#error unsupported architecture -#endif - TRACE("unwinding to ip=%p, cfa=%p\n", _Unwind_GetIP(context), _Unwind_GetCFA(context)); - - // Fix the context to invoke PAL_CallRunHandler - _Unwind_SetIP(context, (void *) PAL_CallRunHandler); - urc = _URC_INSTALL_CONTEXT; - goto exit; - } - -exit: - _ASSERTE(urc != _URC_NO_REASON); - if (urc != _URC_INSTALL_CONTEXT) - { - // If we're installing a context, it's because we want to run - // code that depends on the PAL. Otherwise, bye-bye. - PAL_Leave(PAL_BoundaryEH); - } - return urc; -} - -extern "C" -_Unwind_Exception *PAL_RunHandler( - _Unwind_Action actions, - _Unwind_Exception *exceptionObject, - PFN_PAL_EXCEPTION_FILTER pfnFilter, - void *pvParam, - BOOL *pfExecuteHandler) -{ - _ASSERTE((actions & _UA_PHASE_MASK) == _UA_CLEANUP_PHASE); - - PAL_SEHException *pSEHException = PAL_SEHException::FromExceptionObject(exceptionObject); - - PAL_DISPATCHER_CONTEXT dispatcherContext; - dispatcherContext.actions = actions; - dispatcherContext.exception_object = exceptionObject; - dispatcherContext.context = NULL; - - // Dummy exception record for use by foreign exceptions. - EXCEPTION_RECORD ForeignExceptionRecord = { EXCEPTION_FOREIGN, EXCEPTION_NONCONTINUABLE, NULL, NULL, 0 }; - EXCEPTION_POINTERS ForeignExceptionPointers = { &ForeignExceptionRecord, NULL }; - EXCEPTION_RECORD *pExceptionRecord = &ForeignExceptionRecord; - if (pSEHException) - { - pExceptionRecord = &pSEHException->ExceptionRecord; - } - - pExceptionRecord->ExceptionFlags = - (pExceptionRecord->ExceptionFlags & ~(EXCEPTION_UNWINDING|EXCEPTION_TARGET_UNWIND)) | - EXCEPTION_UNWINDING | ((actions & _UA_HANDLER_FRAME) ? EXCEPTION_TARGET_UNWIND : 0); - - EXCEPTION_DISPOSITION disposition; - PAL_CPP_TRY - { - // MACTODO: Why do we invoke the PAL_EXCEPT macro's filter in the - // unwind pass when it simply returns with the original disposition that - // was provided in the first pass? - disposition = pfnFilter(pSEHException ? &pSEHException->ExceptionPointers : &ForeignExceptionPointers, - &dispatcherContext, pvParam); - } - PAL_CPP_CATCH_ALL - { - // In case of a collided unwind, delete the original exception - // and propagate the new one instead. - _Unwind_DeleteException(exceptionObject); - PAL_CPP_RETHROW; - } - PAL_CPP_ENDTRY - - if ((actions & _UA_HANDLER_FRAME) && disposition == EXCEPTION_EXECUTE_HANDLER) - { - // Return to PAL_TryExcept, which will return the exception that - // occurred, so that the PAL_EXCEPT/PAL_FINALLY body will be run. - *pfExecuteHandler = TRUE; - return exceptionObject; - } - else if (~(actions & _UA_HANDLER_FRAME) && disposition == EXCEPTION_CONTINUE_SEARCH) - { - // Cleanups have been run for this frame; continue running cleanups - // up the stack. - *pfExecuteHandler = FALSE; - return exceptionObject; - } - else - { - // This filter misbehaved; it claimed it would handle/not handle - // the exception, but it didn't/did. - DeleteThrownException(exceptionObject); - RaiseException(EXCEPTION_INVALID_DISPOSITION, - EXCEPTION_NONCONTINUABLE, 0, NULL); - // The above call should never return, but the compiler doesn't know that. - return NULL; - } -} - -//---------------------------------------------------------------------- -// SEH Filter Personality -//---------------------------------------------------------------------- - -extern "C" -_Unwind_Reason_Code PAL_SEHFilterPersonalityRoutine( - int version, - _Unwind_Action actions, - __uint64_t exceptionClass, - _Unwind_Exception *exceptionObject, - _Unwind_Context *context) -{ - PAL_Reenter(PAL_BoundaryEH); - - _ASSERTE(version == 1); - - // When this personality routine runs, we have two activations - // of _Unwind_RaiseException: The outer _Unwind_RaiseException - // was running a filter in the search phase, and that filter - // threw an exception. This is called a "nested exception". - // The inner _Unwind_RaiseException activation is dispatching - // the nested exception, and called this routine. - TRACE("actions=%x\n", actions); - - // Retrieve the dispatcher context of the outer _Unwind_RaiseException. - PAL_DISPATCHER_CONTEXT *outerDispatcherContext; -#if defined(_X86_) - outerDispatcherContext = (PAL_DISPATCHER_CONTEXT *) ((void **) _Unwind_GetGR(context, 4))[3]; // [ebp+12] -#elif defined(_AMD64_) - // Filter address is stored at RSP+8 - // Refer to PAL_RunFilter implementation for details. - outerDispatcherContext = (PAL_DISPATCHER_CONTEXT *)((void **)_Unwind_GetCFA(context))[1]; -#else -#error unsupported architecture -#endif - _ASSERTE(outerDispatcherContext->actions & _UA_SEARCH_PHASE); - - if ((actions & _UA_PHASE_MASK) == _UA_SEARCH_PHASE) - { - TRACE("nested exception\n"); - PAL_SEHException *pSEHException = PAL_SEHException::FromExceptionObject(exceptionObject); - if (pSEHException) - { - pSEHException->NestedIn(outerDispatcherContext->context); - } - else - { - // A foreign exception escaped from a filter. This is not a - // supported action for a filter to take (neither in our SEH - // model, nor in the unwind library's model). Let the system - // execute its (unspecified) behavior. - } - PAL_Leave(PAL_BoundaryEH); - return _URC_CONTINUE_UNWIND; - } - else - { - _ASSERTE((actions & _UA_PHASE_MASK) == _UA_CLEANUP_PHASE); - - // Rethrowing the exception itself from a filter is not supported. - // (That would mess up reference counting of the exception object - // in standard C++.) - _ASSERT(outerDispatcherContext->exception_object != exceptionObject); - - // We're in the cleanup phase of a nested exception. This means - // that nobody fixed up the context of that exception and resumed - // execution. In other words, we'll never resume the outer unwind - // and we have to clean up its state. - _Unwind_DeleteException(outerDispatcherContext->exception_object); - - // No cleanup to run for a nested exception. - PAL_Leave(PAL_BoundaryEH); - return _URC_CONTINUE_UNWIND; - } -} diff --git a/src/pal/src/init/pal.cpp b/src/pal/src/init/pal.cpp index 18e5f239e1..336a11c439 100644 --- a/src/pal/src/init/pal.cpp +++ b/src/pal/src/init/pal.cpp @@ -93,7 +93,7 @@ static PCRITICAL_SECTION init_critsec = NULL; char g_szCoreCLRPath[MAX_PATH] = { 0 }; static BOOL INIT_IncreaseDescriptorLimit(void); -static LPWSTR INIT_FormatCommandLine (CPalThread *pThread, int argc, const char **argv); +static LPWSTR INIT_FormatCommandLine (CPalThread *pThread, int argc, const char * const *argv); static LPWSTR INIT_FindEXEPath(CPalThread *pThread, LPCSTR exe_name); #ifdef _DEBUG @@ -135,7 +135,7 @@ int PALAPI PAL_Initialize( int argc, - const char *argv[]) + const char *const argv[]) { PAL_ERROR palError = ERROR_GEN_FAILURE; CPalThread *pThread = NULL; @@ -1064,7 +1064,7 @@ Note : not all peculiarities of Windows command-line processing are supported; passed to argv as \\a... there may be other similar cases -there may be other characters which must be escaped --*/ -static LPWSTR INIT_FormatCommandLine (CPalThread *pThread, int argc, const char **argv) +static LPWSTR INIT_FormatCommandLine (CPalThread *pThread, int argc, const char * const *argv) { LPWSTR retval; LPSTR command_line=NULL, command_ptr; diff --git a/src/pal/tests/palsuite/CMakeLists.txt b/src/pal/tests/palsuite/CMakeLists.txt index 4eda0238de..7095aa691b 100644 --- a/src/pal/tests/palsuite/CMakeLists.txt +++ b/src/pal/tests/palsuite/CMakeLists.txt @@ -9,7 +9,7 @@ add_compile_options(-Wno-int-to-void-pointer-cast) # TODO: make these tests compile # add_subdirectory(composite) -# add_subdirectory(exception_handling) +add_subdirectory(exception_handling) add_subdirectory(c_runtime) add_subdirectory(debug_api) diff --git a/src/pal/tests/palsuite/common/palsuite.h b/src/pal/tests/palsuite/common/palsuite.h index b61435ff48..4156f10190 100644 --- a/src/pal/tests/palsuite/common/palsuite.h +++ b/src/pal/tests/palsuite/common/palsuite.h @@ -18,6 +18,7 @@ #ifndef __PALSUITE_H__ #define __PALSUITE_H__ +#include <pal_assert.h> #include <pal.h> enum @@ -27,7 +28,7 @@ enum }; -void Trace(char *format, ...) +void Trace(const char *format, ...) { va_list arglist; @@ -38,7 +39,7 @@ void Trace(char *format, ...) va_end(arglist); } -void Fail(char *format, ...) +void Fail(const char *format, ...) { va_list arglist; diff --git a/src/pal/tests/palsuite/exception_handling/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/CMakeLists.txt index 23e82e1a7f..3e2c9eb9b5 100644 --- a/src/pal/tests/palsuite/exception_handling/CMakeLists.txt +++ b/src/pal/tests/palsuite/exception_handling/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required(VERSION 2.8.12.2) -add_subdirectory(pal_except) -add_subdirectory(PAL_EXCEPT_FILTER) -add_subdirectory(PAL_EXCEPT_FILTER_EX) -add_subdirectory(pal_finally) -add_subdirectory(PAL_GetBottommostRegistration) -add_subdirectory(PAL_TRY_EXCEPT) -add_subdirectory(PAL_TRY_EXCEPT_EX) -add_subdirectory(PAL_TRY_LEAVE_FINALLY) +#add_subdirectory(pal_except) +#add_subdirectory(PAL_EXCEPT_FILTER) +#add_subdirectory(PAL_EXCEPT_FILTER_EX) +#add_subdirectory(pal_finally) +#add_subdirectory(PAL_GetBottommostRegistration) +#add_subdirectory(PAL_TRY_EXCEPT) +#add_subdirectory(PAL_TRY_EXCEPT_EX) +#add_subdirectory(PAL_TRY_LEAVE_FINALLY) add_subdirectory(RaiseException) -add_subdirectory(SetUnhandledExceptionFilter) +#add_subdirectory(SetUnhandledExceptionFilter) diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/CMakeLists.txt index 48a7d44d79..3cd0a1f747 100644 --- a/src/pal/tests/palsuite/exception_handling/RaiseException/test1/CMakeLists.txt +++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8.12.2) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(SOURCES - test1.c + test1.cpp ) add_executable(paltest_raiseexception_test1 diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test1/test1.c b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/test1.cpp index 2908aeb4d3..1e8dfaa34b 100644 --- a/src/pal/tests/palsuite/exception_handling/RaiseException/test1/test1.c +++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/test1.cpp @@ -17,11 +17,12 @@ #include <palsuite.h> +BOOL bExcept = FALSE; +BOOL bTry = FALSE; +BOOL bFinally = FALSE; + int __cdecl main(int argc, char *argv[]) { - BOOL bExcept = FALSE; - BOOL bTry = FALSE; - BOOL bFinally = FALSE; if(0 != (PAL_Initialize(argc, argv))) { @@ -31,7 +32,7 @@ int __cdecl main(int argc, char *argv[]) /********************************************************* * Tests that RaiseException throws a catchable exception */ - PAL_TRY + PAL_TRY(VOID*, unused, NULL) { bTry = TRUE; RaiseException(0,0,0,0); @@ -72,9 +73,9 @@ int __cdecl main(int argc, char *argv[]) * PAL_FINALLY * (bFinally should be set before bExcept) */ - PAL_TRY + PAL_TRY(VOID*, unused, NULL) { - PAL_TRY + PAL_TRY(VOID*, unused, NULL) { bTry = TRUE; RaiseException(0,0,0,0); diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test2/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/CMakeLists.txt index fbb9a60a98..f7715f5b07 100644 --- a/src/pal/tests/palsuite/exception_handling/RaiseException/test2/CMakeLists.txt +++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8.12.2) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(SOURCES - test2.c + test2.cpp ) add_executable(paltest_raiseexception_test2 diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test2/test2.c b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/test2.cpp index 7c08c15ea8..0265ce8114 100644 --- a/src/pal/tests/palsuite/exception_handling/RaiseException/test2/test2.c +++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/test2.cpp @@ -19,9 +19,9 @@ #include <palsuite.h> -BOOL bFilter = FALSE; -BOOL bTry = FALSE; -const int nValidator = 0; +BOOL bFilter; +BOOL bTry; +BOOL bExcept; ULONG_PTR lpArguments_test1[EXCEPTION_MAXIMUM_PARAMETERS]; DWORD nArguments_test1 = EXCEPTION_MAXIMUM_PARAMETERS; @@ -35,7 +35,7 @@ DWORD nArguments_test2 = EXCEPTION_MAXIMUM_PARAMETERS+1; ** Filter function that checks for the parameters ** **/ -LONG Filter_test1(EXCEPTION_POINTERS* ep, VOID *pnTestInt) +LONG Filter_test1(EXCEPTION_POINTERS* ep, VOID *unused) { int i; @@ -81,7 +81,7 @@ LONG Filter_test1(EXCEPTION_POINTERS* ep, VOID *pnTestInt) ** Filter function that checks for the maximum parameters ** **/ -LONG Filter_test2(EXCEPTION_POINTERS* ep, VOID *pnTestInt) +LONG Filter_test2(EXCEPTION_POINTERS* ep, VOID* unused) { /* let the main know we've hit the filter function */ bFilter = TRUE; @@ -99,8 +99,7 @@ LONG Filter_test2(EXCEPTION_POINTERS* ep, VOID *pnTestInt) int __cdecl main(int argc, char *argv[]) { - int i; - BOOL bExcept = FALSE; + bExcept = FALSE; if (0 != PAL_Initialize(argc, argv)) { @@ -111,12 +110,12 @@ int __cdecl main(int argc, char *argv[]) * Test that the correct arguments are passed * to the filter by RaiseException */ - PAL_TRY + PAL_TRY(VOID*, unused, NULL) { bTry = TRUE; /* indicate we hit the PAL_TRY block */ /* Initialize arguments to pass to filter */ - for( i = 0; ((DWORD)i) < nArguments_test1; i++ ) + for(int i = 0; ((DWORD)i) < nArguments_test1; i++ ) { lpArguments_test1[i] = i; } @@ -126,7 +125,7 @@ int __cdecl main(int argc, char *argv[]) Fail("RaiseException: ERROR -> code was executed after the " "exception was raised.\n"); } - PAL_EXCEPT_FILTER(Filter_test1, (LPVOID)&nValidator) + PAL_EXCEPT_FILTER(Filter_test1) { if (!bTry) { @@ -170,12 +169,12 @@ int __cdecl main(int argc, char *argv[]) * exceeds EXCEPTION_MAXIMUM_PARAMETERS, even though we * pass a greater number of arguments */ - PAL_TRY + PAL_TRY(VOID*, unused, NULL) { bTry = TRUE; /* indicate we hit the PAL_TRY block */ /* Initialize arguments to pass to filter */ - for( i = 0; ((DWORD)i) < nArguments_test2; i++ ) + for(int i = 0; ((DWORD)i) < nArguments_test2; i++ ) { lpArguments_test2[i] = i; } @@ -185,7 +184,7 @@ int __cdecl main(int argc, char *argv[]) Fail("RaiseException: ERROR -> code was executed after the " "exception was raised.\n"); } - PAL_EXCEPT_FILTER(Filter_test2, (LPVOID)&nValidator) + PAL_EXCEPT_FILTER(Filter_test2) { if (!bTry) { diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test3/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/CMakeLists.txt index c176afcae4..61125b4d7d 100644 --- a/src/pal/tests/palsuite/exception_handling/RaiseException/test3/CMakeLists.txt +++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8.12.2) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(SOURCES - test.c + test.cpp ) add_executable(paltest_raiseexception_test3 diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test3/test.c b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/test.cpp index 434d475a66..1b0d4ec8ab 100644 --- a/src/pal/tests/palsuite/exception_handling/RaiseException/test3/test.c +++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/test.cpp @@ -17,16 +17,15 @@ #include <palsuite.h> BOOL bFilter = FALSE; -BOOL bTry = FALSE; -const int nValidator = 0; - +BOOL bTry = FALSE; +BOOL bExcept = FALSE; /** ** ** Filter function that checks for the parameters ** **/ -LONG Filter_test1(EXCEPTION_POINTERS* ep, VOID *pnTestInt) +LONG Filter_test1(EXCEPTION_POINTERS* ep, VOID* unused) { /* let the main know we've hit the filter function */ bFilter = TRUE; @@ -53,7 +52,7 @@ LONG Filter_test1(EXCEPTION_POINTERS* ep, VOID *pnTestInt) int __cdecl main(int argc, char *argv[]) { - BOOL bExcept = FALSE; + bExcept = FALSE; if (0 != PAL_Initialize(argc, argv)) { @@ -64,7 +63,7 @@ int __cdecl main(int argc, char *argv[]) * Test that the correct arguments are passed * to the filter by RaiseException */ - PAL_TRY + PAL_TRY(VOID*, unused, NULL) { bTry = TRUE; /* indicate we hit the PAL_TRY block */ @@ -75,7 +74,7 @@ int __cdecl main(int argc, char *argv[]) Fail("RaiseException: ERROR -> code was executed after the " "exception was raised.\n"); } - PAL_EXCEPT_FILTER(Filter_test1, (LPVOID)&nValidator) + PAL_EXCEPT_FILTER(Filter_test1) { if (!bTry) { diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.c b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.c index a2c6f639df..48cd83efb4 100644 --- a/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.c +++ b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.c @@ -84,7 +84,7 @@ int __cdecl main(int argc, char *argv[]) */ TimeDiff[i] = (DWORD)(((EndTime.QuadPart - StartTime.QuadPart)*1000)/ (Freq.QuadPart)); - TotalTimeDiff += abs(TimeDiff[i] - SleepInterval); + TotalTimeDiff += TimeDiff[i] - SleepInterval; } diff --git a/src/pal/tests/palsuite/paltestlist.txt b/src/pal/tests/palsuite/paltestlist.txt index fa3183e5e7..920a0cbb9b 100644 --- a/src/pal/tests/palsuite/paltestlist.txt +++ b/src/pal/tests/palsuite/paltestlist.txt @@ -438,6 +438,9 @@ c_runtime/_wsplitpath/test1/paltest_wsplitpath_test1 c_runtime/_wtoi/test1/paltest_wtoi_test1 c_runtime/__iscsym/test1/paltest_iscsym_test1 debug_api/OutputDebugStringW/test1/paltest_outputdebugstringw_test1 +exception_handling/RaiseException/test1/paltest_raiseexception_test1 +exception_handling/RaiseException/test2/paltest_raiseexception_test2 +exception_handling/RaiseException/test3/paltest_raiseexception_test3 filemapping_memmgt/CreateFileMappingA/test1/paltest_createfilemappinga_test1 filemapping_memmgt/CreateFileMappingA/test3/paltest_createfilemappinga_test3 filemapping_memmgt/CreateFileMappingA/test4/paltest_createfilemappinga_test4 diff --git a/src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt b/src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt index 0f135a040b..64b87d518a 100644 --- a/src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt +++ b/src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt @@ -57,9 +57,6 @@ exception_handling/PAL_TRY_EXCEPT_EX/test1/paltest_pal_try_except_ex_test1 exception_handling/PAL_TRY_EXCEPT_EX/test2/paltest_pal_try_except_ex_test2 exception_handling/PAL_TRY_EXCEPT_EX/test3/paltest_pal_try_except_ex_test3 exception_handling/PAL_TRY_LEAVE_FINALLY/test1/paltest_pal_try_leave_finally_test1 -exception_handling/RaiseException/test1/paltest_raiseexception_test1 -exception_handling/RaiseException/test2/paltest_raiseexception_test2 -exception_handling/RaiseException/test3/paltest_raiseexception_test3 exception_handling/SetUnhandledExceptionFilter/test1/paltest_setunhandledexceptionfilter_test1 filemapping_memmgt/CreateFileMappingA/test5/paltest_createfilemappinga_test5 filemapping_memmgt/CreateFileMappingA/test6/paltest_createfilemappinga_test6 diff --git a/src/pal/tests/palsuite/threading/SleepEx/test2/test2.c b/src/pal/tests/palsuite/threading/SleepEx/test2/test2.c index b0fcdcee89..cce842ae52 100644 --- a/src/pal/tests/palsuite/threading/SleepEx/test2/test2.c +++ b/src/pal/tests/palsuite/threading/SleepEx/test2/test2.c @@ -57,7 +57,7 @@ int __cdecl main( int argc, char **argv ) for (i=0;i<Iterations;i++) { RunTest(TRUE); - dwAvgDelta += abs(ThreadSleepDelta - InterruptTime); + dwAvgDelta += ThreadSleepDelta - InterruptTime; } dwAvgDelta /= Iterations; @@ -76,7 +76,7 @@ int __cdecl main( int argc, char **argv ) for (i=0;i<Iterations;i++) { RunTest(FALSE); - dwAvgDelta += abs(ThreadSleepDelta - ChildThreadSleepTime); + dwAvgDelta += ThreadSleepDelta - ChildThreadSleepTime; } dwAvgDelta /= Iterations; diff --git a/src/pal/tests/palsuite/threading/SuspendThread/test4/test4.c b/src/pal/tests/palsuite/threading/SuspendThread/test4/test4.c index 4b3c5b7d99..ca8a4c63e8 100644 --- a/src/pal/tests/palsuite/threading/SuspendThread/test4/test4.c +++ b/src/pal/tests/palsuite/threading/SuspendThread/test4/test4.c @@ -19,6 +19,9 @@ #include <palsuite.h> +// Declare sched_yield(), as we cannot include <sched.h> here. +int sched_yield(void); + #define NUM_MALLOCS 256 #define MAX_THREADS 64 int numThreads, numIterations, targetThreadsSelectionAlgo, targetThreadsPos; diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/test2.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/test2.c index 1f8534246b..ee40fed95c 100644 --- a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/test2.c +++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/test2.c @@ -57,8 +57,8 @@ int __cdecl main( int argc, char **argv ) // Make sure that the wait returns in time greater than interrupt and less than // wait timeout if ( - ((ThreadWaitDelta >= ChildThreadWaitTime) && ( abs( ThreadWaitDelta - ChildThreadWaitTime) > TOLERANCE )) - || (( ThreadWaitDelta < InterruptTime) && ( abs( ThreadWaitDelta - InterruptTime) > TOLERANCE ) ) + ((ThreadWaitDelta >= ChildThreadWaitTime) && (ThreadWaitDelta - ChildThreadWaitTime) > TOLERANCE) + || (( ThreadWaitDelta < InterruptTime) && (ThreadWaitDelta - InterruptTime) > TOLERANCE) ) { Fail("Expected thread to wait for %d ms (and get interrupted).\n" @@ -75,7 +75,7 @@ int __cdecl main( int argc, char **argv ) // Make sure that time taken for thread to return from wait is more than interrupt // and also not less than the complete child thread wait time - delta = abs( ThreadWaitDelta - ChildThreadWaitTime); + delta = ThreadWaitDelta - ChildThreadWaitTime; if( (ThreadWaitDelta < ChildThreadWaitTime) && ( delta > TOLERANCE) ) { Fail("Expected thread to wait for %d ms (and not get interrupted).\n" diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.c index 35ecb1ee5f..deacabf1be 100644 --- a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.c +++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.c @@ -75,7 +75,7 @@ int __cdecl main( int argc, char **argv ) */ RunTest(TRUE); - if (abs(ThreadWaitDelta - InterruptTime) > AcceptableDelta) + if ((ThreadWaitDelta - InterruptTime) > AcceptableDelta) { Fail("Expected thread to wait for %d ms (and get interrupted).\n" "Thread waited for %d ms! (Acceptable delta: %d)\n", @@ -88,7 +88,7 @@ int __cdecl main( int argc, char **argv ) * it, if it is not in an alertable state. */ RunTest(FALSE); - if (abs(ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta) + if ((ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta) { Fail("Expected thread to wait for %d ms (and not be interrupted).\n" "Thread waited for %d ms! (Acceptable delta: %d)\n", diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/WFSOExSemaphoreTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/WFSOExSemaphoreTest.c index ad8697c52c..a788e72e6f 100644 --- a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/WFSOExSemaphoreTest.c +++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/WFSOExSemaphoreTest.c @@ -50,7 +50,7 @@ int __cdecl main( int argc, char **argv ) */ RunTest(TRUE); - if (abs(ThreadWaitDelta - InterruptTime) > AcceptableDelta) + if ((ThreadWaitDelta - InterruptTime) > AcceptableDelta) { Fail("Expected thread to wait for %d ms (and get interrupted).\n" "Thread waited for %d ms! (Acceptable delta: %d)\n", @@ -63,7 +63,7 @@ int __cdecl main( int argc, char **argv ) * it, if it is not in an alertable state. */ RunTest(FALSE); - if (abs(ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta) + if ((ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta) { Fail("Expected thread to wait for %d ms (and not be interrupted).\n" "Thread waited for %d ms! (Acceptable delta: %d)\n", diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/WFSOExThreadTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/WFSOExThreadTest.c index b7b035819a..63e2fc3723 100644 --- a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/WFSOExThreadTest.c +++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/WFSOExThreadTest.c @@ -51,7 +51,7 @@ int __cdecl main( int argc, char **argv ) */ RunTest(TRUE); - if (abs(ThreadWaitDelta - InterruptTime) > AcceptableDelta) + if ((ThreadWaitDelta - InterruptTime) > AcceptableDelta) { Fail("Expected thread to wait for %d ms (and get interrupted).\n" "Thread waited for %d ms! (Acceptable delta: %d)\n", @@ -64,7 +64,7 @@ int __cdecl main( int argc, char **argv ) * it, if it is not in an alertable state. */ RunTest(FALSE); - if (abs(ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta) + if ((ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta) { Fail("Expected thread to wait for %d ms (and not be interrupted).\n" "Thread waited for %d ms! (Acceptable delta: %d)\n", diff --git a/src/vm/amd64/unixasmhelpers.S b/src/vm/amd64/unixasmhelpers.S index 873db7ad1e..17846947fa 100644 --- a/src/vm/amd64/unixasmhelpers.S +++ b/src/vm/amd64/unixasmhelpers.S @@ -101,7 +101,7 @@ NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler // Make sure to preserve r11 as well as it is used to pass the stack argument size from JIT // PUSH_ARGUMENT_REGISTERS - push r11 + push_register r11 // // Allocate space for XMM parameter registers @@ -123,12 +123,12 @@ NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler // // epilogue, rax contains the native target address // - add rsp, 0x80 + free_stack 0x80 // // Restore integer parameter registers and r11 // - pop r11 + pop_register r11 POP_ARGUMENT_REGISTERS TAILJMP_RAX @@ -153,9 +153,9 @@ LEAF_END moveOWord, _TEXT NESTED_ENTRY JIT_RareDisableHelper, _TEXT, NoHandler // First integer return register - push rax + push_register rax // Second integer return register - push rdx + push_register rdx alloc_stack 0x28 END_PROLOGUE // First float return register @@ -167,9 +167,9 @@ NESTED_ENTRY JIT_RareDisableHelper, _TEXT, NoHandler movdqa xmm0, [rsp] movdqa xmm1, [rsp+0x10] - add rsp, 0x28 - pop rdx - pop rax + free_stack 0x28 + pop_register rdx + pop_register rax ret NESTED_END JIT_RareDisableHelper, _TEXT diff --git a/src/vm/amd64/unixasmmacros.inc b/src/vm/amd64/unixasmmacros.inc index 8fb0ff201b..aaf4390c47 100644 --- a/src/vm/amd64/unixasmmacros.inc +++ b/src/vm/amd64/unixasmmacros.inc @@ -173,11 +173,15 @@ C_FUNC(\Name\()_End): .endm -.macro push_argument_register Reg +.macro push_register Reg push \Reg .cfi_adjust_cfa_offset 8 .endm +.macro push_argument_register Reg + push_register \Reg +.endm + .macro PUSH_ARGUMENT_REGISTERS push_argument_register r9 @@ -189,11 +193,15 @@ C_FUNC(\Name\()_End): .endm -.macro pop_argument_register Reg +.macro pop_register Reg pop \Reg .cfi_adjust_cfa_offset -8 .endm +.macro pop_argument_register Reg + pop_register \Reg +.endm + .macro POP_ARGUMENT_REGISTERS pop_argument_register rdi diff --git a/src/vm/object.h b/src/vm/object.h index 009e505cea..396d1acbb9 100644 --- a/src/vm/object.h +++ b/src/vm/object.h @@ -1107,9 +1107,9 @@ class StringObject : public Object static SIZE_T GetSize(DWORD stringLength); DWORD GetStringLength() { LIMITED_METHOD_DAC_CONTRACT; return( m_StringLength );} - WCHAR* GetBuffer() { LIMITED_METHOD_CONTRACT; _ASSERTE(this); return (WCHAR*)( dac_cast<TADDR>(this) + offsetof(StringObject, m_Characters) ); } - WCHAR* GetBuffer(DWORD *pdwSize) { LIMITED_METHOD_CONTRACT; _ASSERTE(this && pdwSize); *pdwSize = GetStringLength(); return GetBuffer(); } - WCHAR* GetBufferNullable() { LIMITED_METHOD_CONTRACT; return( (this == 0) ? 0 : (WCHAR*)( dac_cast<TADDR>(this) + offsetof(StringObject, m_Characters) ) ); } + WCHAR* GetBuffer() { LIMITED_METHOD_CONTRACT; _ASSERTE(this != nullptr); return (WCHAR*)( dac_cast<TADDR>(this) + offsetof(StringObject, m_Characters) ); } + WCHAR* GetBuffer(DWORD *pdwSize) { LIMITED_METHOD_CONTRACT; _ASSERTE((this != nullptr) && pdwSize); *pdwSize = GetStringLength(); return GetBuffer(); } + WCHAR* GetBufferNullable() { LIMITED_METHOD_CONTRACT; return( (this == nullptr) ? nullptr : (WCHAR*)( dac_cast<TADDR>(this) + offsetof(StringObject, m_Characters) ) ); } DWORD GetHighCharState() { WRAPPER_NO_CONTRACT; diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp index 0d21e1579a..3fc78f1e8a 100644 --- a/src/vm/threads.cpp +++ b/src/vm/threads.cpp @@ -3577,7 +3577,7 @@ Thread::~Thread() #endif #ifdef _DEBUG - if (m_pFiberInfo) { + if (m_pFiberInfo != NULL) { delete [] (DWORD_PTR*)m_pFiberInfo[0]; } #endif diff --git a/tests/runtest.cmd b/tests/runtest.cmd index 5c9d887722..8ef43dd0f7 100644 --- a/tests/runtest.cmd +++ b/tests/runtest.cmd @@ -8,7 +8,7 @@ if /i "%1" == "x64" (set __BuildArch=x64&set __MSBuildBuildArch=x64&shift&got if /i "%1" == "debug" (set __BuildType=debug&shift&goto Arg_Loop) if /i "%1" == "release" (set __BuildType=release&shift&goto Arg_Loop) if /i "%1" == "SkipWrapperGeneration" (set __SkipWrapperGeneration=true&shift&goto Arg_Loop) -if /i "%1" == "EnableMSILC" (set __EnableMSILC=true&shift&goto Arg_Loop) +if /i "%1" == "EnableAltJit" (set __EnableAltJit=true&set Alt_Jit_Name=%2&shift&shift&goto Arg_Loop) if /i "%1" == "/?" (goto Usage) @@ -54,6 +54,7 @@ set Core_Root=%__BinDir% if not exist %XunitTestBinBase% echo Error: Ensure the Test Binaries are built and are present at %XunitTestBinBase%, Run - buildtest.cmd %__BuildArch% %__BuildType% to build the tests first. && exit /b 1 if "%Core_Root%" == "" echo Error: Ensure you have done a successful build of the Product and Run - runtest BuildArch BuildType {path to product binaries}. && exit /b 1 if not exist %Core_Root%\coreclr.dll echo Error: Ensure you have done a successful build of the Product and %Core_Root% contains runtime binaries. && exit /b 1 +if defined __EnableAltJit (if not exist %Core_Root%\%Alt_Jit_Name%.dll echo Error: Ensure alternative JIT %Alt_Jit_Name%.dll exist in %Core_Root%. && exit /b 1) if not exist %__LogsDir% md %__LogsDir% :SkipDefaultCoreRootSetup @@ -128,12 +129,12 @@ goto :eof :Usage echo. echo Usage: -echo %0 BuildArch BuildType [SkipWrapperGeneration] CORE_ROOT where: +echo %0 BuildArch BuildType [SkipWrapperGeneration] [EnableAltJit ALT_JIT_NAME] CORE_ROOT where: echo. echo BuildArch is x64 echo BuildType can be: Debug, Release echo SkipWrapperGeneration- Optional parameter this will run the same set of tests as the last time it was run -echo EnableMSILC- Optional parameter this will use MSILC JIT, an alternative JIT for testing +echo EnableAltJit- Optional parameter this will use alternative JIT specified by ALT_JIT_NAME for testing echo CORE_ROOT The path to the runtime goto :eof diff --git a/tests/src/dir.props b/tests/src/dir.props index c8f86c4345..13dca4c8da 100644 --- a/tests/src/dir.props +++ b/tests/src/dir.props @@ -9,9 +9,9 @@ <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute> </PropertyGroup> - <!-- Enable MSILC JIT for testing if specified --> + <!-- Enable alternative JIT for testing if specified --> <PropertyGroup> - <_CLRTestPreCommands>IF NOT "%__EnableMSILC%"=="" set COMPLus_AltJit=*;IF NOT "%__EnableMSILC%"=="" set COMPLus_AltJitName=MSILCJit.dll</_CLRTestPreCommands> + <_CLRTestPreCommands>IF NOT "%__EnableAltJit%"=="" set COMPLus_AltJit=*;IF NOT "%__EnableAltJit%"=="" set COMPLus_AltJitName=%Alt_Jit_Name%.dll</_CLRTestPreCommands> </PropertyGroup> </Project> |