Port dbgshim to the diagnostics repo (#2842)
authorMike McLaughlin <mikem@microsoft.com>
Tue, 8 Feb 2022 02:01:35 +0000 (18:01 -0800)
committerGitHub <noreply@github.com>
Tue, 8 Feb 2022 02:01:35 +0000 (18:01 -0800)
Port dbgshim to the diagnostics repo

runtime repo commit hash: 442a42147ef23c3b9742abcd8b997e8f472af68a

Add a subset of utilcode. Add more runtime include files.

Add PAL_RegisterForRuntimeStartup and the other PAL support it needs like WaitForSingleObject, OpenProcess, EnumProcessModules, etc.

Add dbgshim packaging support.

Sync diagnostics/eng/native to the runtime

Make IsShipping* properties consistent

Change eeversion not to require the DAC to display runtime version

178 files changed:
CMakeLists.txt
diagnostics.sln
eng/ci-prepare-artifacts.cmd
eng/native/build-commons.sh
eng/native/configurecompiler.cmake
eng/native/configureplatform.cmake
eng/native/configuretools.cmake
eng/native/functions.cmake
eng/native/init-os-and-arch.sh
eng/native/tryrun.cmake
eng/testassets/pack.csproj
eng/testassets/rebuild/pack.csproj
src/CMakeLists.txt
src/Directory.Build.props
src/Microsoft.Diagnostics.DebugServices.Implementation/Microsoft.Diagnostics.DebugServices.Implementation.csproj
src/Microsoft.Diagnostics.DebugServices/Microsoft.Diagnostics.DebugServices.csproj
src/Microsoft.Diagnostics.ExtensionCommands/Microsoft.Diagnostics.ExtensionCommands.csproj
src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj
src/Microsoft.Diagnostics.Monitoring/Microsoft.Diagnostics.Monitoring.csproj
src/Microsoft.Diagnostics.Repl/Microsoft.Diagnostics.Repl.csproj
src/SOS/CMakeLists.txt
src/SOS/SOS.Extensions/SOS.Extensions.csproj
src/SOS/SOS.Hosting/SOS.Hosting.csproj
src/SOS/SOS.InstallHelper/SOS.InstallHelper.csproj
src/SOS/SOS.Package/SOS.Package.csproj
src/SOS/SOS.Package/SOS.Symbol.Package.csproj
src/SOS/SOS.UnitTests/Debuggees/Directory.Build.props
src/SOS/Strike/CMakeLists.txt
src/SOS/Strike/strike.cpp
src/SOS/Strike/symbols.cpp
src/SOS/Strike/util.cpp
src/SOS/dbgutil/CMakeLists.txt
src/SOS/debugshim/CMakeLists.txt [deleted file]
src/SOS/debugshim/debugshim.cpp [deleted file]
src/SOS/debugshim/debugshim.h [deleted file]
src/SOS/debugshim/debugshim.vcxproj [deleted file]
src/SOS/extensions/CMakeLists.txt
src/SOS/extensions/hostcoreclr.cpp
src/SOS/gcdump/gcdump.cpp
src/SOS/gcdump/i386/gcdumpx86.cpp
src/dbgshim/CMakeLists.txt [new file with mode: 0644]
src/dbgshim/dbgshim.cpp [new file with mode: 0644]
src/dbgshim/dbgshim.h [new file with mode: 0644]
src/dbgshim/dbgshim.ntdef [new file with mode: 0644]
src/dbgshim/dbgshim.rc [new file with mode: 0644]
src/dbgshim/dbgshim.vcxproj [new file with mode: 0644]
src/dbgshim/dbgshim.vcxproj.filters [new file with mode: 0644]
src/dbgshim/dbgshim_unixexports.src [new file with mode: 0644]
src/dbgshim/debugshim.cpp [new file with mode: 0644]
src/dbgshim/debugshim.h [new file with mode: 0644]
src/dbgshim/pkg/Directory.Build.props [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-arm.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-arm64.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-musl-arm64.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-musl-x64.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-x64.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.osx-arm64.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.osx-x64.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.props [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-arm.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-arm64.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-x64.proj [new file with mode: 0644]
src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-x86.proj [new file with mode: 0644]
src/inc/CMakeLists.txt
src/inc/check.h [new file with mode: 0644]
src/inc/check.inl [new file with mode: 0644]
src/inc/clrhost.h [new file with mode: 0644]
src/inc/clrnt.h [new file with mode: 0644]
src/inc/clrprivappxhosting.idl [deleted file]
src/inc/clrprivbinding.idl [deleted file]
src/inc/clrprivhosting.idl [deleted file]
src/inc/clrprivruntimebinders.idl [deleted file]
src/inc/clrtypes.h [new file with mode: 0644]
src/inc/contract.h [new file with mode: 0644]
src/inc/contract.inl [new file with mode: 0644]
src/inc/corhlprpriv.h [new file with mode: 0644]
src/inc/crsttypes.h [new file with mode: 0644]
src/inc/crtwrap.h [new file with mode: 0644]
src/inc/daccess.h
src/inc/dbgenginemetrics.h [new file with mode: 0644]
src/inc/debugmacros.h
src/inc/debugreturn.h [new file with mode: 0644]
src/inc/entrypoints.h [new file with mode: 0644]
src/inc/ex.h [new file with mode: 0644]
src/inc/fstring.h [new file with mode: 0644]
src/inc/getproductversionnumber.h [new file with mode: 0644]
src/inc/holder.h [new file with mode: 0644]
src/inc/iterator.h [new file with mode: 0644]
src/inc/mdcommon.h [new file with mode: 0644]
src/inc/memoryrange.h [new file with mode: 0644]
src/inc/metadata.h [new file with mode: 0644]
src/inc/nibblemapmacros.h [new file with mode: 0644]
src/inc/nsutilpriv.h [new file with mode: 0644]
src/inc/ostype.h [new file with mode: 0644]
src/inc/pedecoder.h [new file with mode: 0644]
src/inc/pedecoder.inl [new file with mode: 0644]
src/inc/readytorun.h [new file with mode: 0644]
src/inc/readytoruninstructionset.h [new file with mode: 0644]
src/inc/registrywrapper.h [new file with mode: 0644]
src/inc/resource.h [new file with mode: 0644]
src/inc/safewrap.h [new file with mode: 0644]
src/inc/sbuffer.h [new file with mode: 0644]
src/inc/sbuffer.inl [new file with mode: 0644]
src/inc/securityutil.h [new file with mode: 0644]
src/inc/securitywrapper.h [new file with mode: 0644]
src/inc/sigparser.h
src/inc/sstring.h [new file with mode: 0644]
src/inc/sstring.inl [new file with mode: 0644]
src/inc/stacktrace.h [deleted file]
src/inc/stdmacros.h [new file with mode: 0644]
src/inc/stresslog.h
src/inc/switches.h
src/inc/utilcode.h
src/inc/volatile.h
src/inc/win64unwind.h [new file with mode: 0644]
src/inc/winwrap.h [new file with mode: 0644]
src/inc/yieldprocessornormalized.h [new file with mode: 0644]
src/pal/CMakeLists.txt
src/pal/inc/pal.h
src/pal/inc/unixasmmacros.inc
src/pal/inc/unixasmmacrosarm.inc
src/pal/prebuilt/inc/buildnumber.h [deleted file]
src/pal/prebuilt/inc/clrprivbinding.h [deleted file]
src/pal/prebuilt/inc/mscorsvc.h [deleted file]
src/pal/src/CMakeLists.txt
src/pal/src/cruntime/printfcpp.cpp
src/pal/src/cruntime/wchar.cpp
src/pal/src/cruntime/wchartls.cpp [deleted file]
src/pal/src/include/pal/corunix.hpp
src/pal/src/include/pal/modulename.h [deleted file]
src/pal/src/include/pal/mutex.hpp [new file with mode: 0644]
src/pal/src/include/pal/process.h
src/pal/src/include/pal/procobj.hpp [new file with mode: 0644]
src/pal/src/include/pal/synchcache.hpp [new file with mode: 0644]
src/pal/src/include/pal/synchobjects.hpp [new file with mode: 0644]
src/pal/src/include/pal/thread.hpp
src/pal/src/include/pal/threadsusp.hpp
src/pal/src/include/pal/utils.h
src/pal/src/init/pal.cpp
src/pal/src/init/sxs.cpp
src/pal/src/loader/module.cpp
src/pal/src/loader/modulename.cpp [deleted file]
src/pal/src/memory/local.cpp [deleted file]
src/pal/src/misc/fmtmessage.cpp
src/pal/src/objmgr/shmobject.cpp
src/pal/src/objmgr/shmobject.hpp
src/pal/src/objmgr/shmobjectmanager.cpp
src/pal/src/synchmgr/synchcontrollers.cpp [new file with mode: 0644]
src/pal/src/synchmgr/synchmanager.cpp [new file with mode: 0644]
src/pal/src/synchmgr/synchmanager.hpp [new file with mode: 0644]
src/pal/src/synchmgr/wait.cpp [new file with mode: 0644]
src/pal/src/synchobj/mutex.cpp [new file with mode: 0644]
src/pal/src/thread/process.cpp [new file with mode: 0644]
src/pal/src/thread/procprivate.hpp [new file with mode: 0644]
src/pal/src/thread/thread.cpp
src/pal/src/thread/threadsusp.cpp [new file with mode: 0644]
src/palrt/CMakeLists.txt
src/utilcode/CMakeLists.txt [new file with mode: 0644]
src/utilcode/check.cpp [new file with mode: 0644]
src/utilcode/clrhost_nodependencies.cpp [new file with mode: 0644]
src/utilcode/debug.cpp [new file with mode: 0644]
src/utilcode/dlwrap.cpp [new file with mode: 0644]
src/utilcode/ex.cpp [new file with mode: 0644]
src/utilcode/fstring.cpp [new file with mode: 0644]
src/utilcode/hostimpl.cpp [new file with mode: 0644]
src/utilcode/longfilepathwrappers.cpp [new file with mode: 0644]
src/utilcode/namespaceutil.cpp [new file with mode: 0644]
src/utilcode/pedecoder.cpp [new file with mode: 0644]
src/utilcode/safewrap.cpp [new file with mode: 0644]
src/utilcode/sbuffer.cpp [new file with mode: 0644]
src/utilcode/securityutil.cpp [new file with mode: 0644]
src/utilcode/securitywrapper.cpp [new file with mode: 0644]
src/utilcode/sstring.cpp [new file with mode: 0644]
src/utilcode/sstring_com.cpp [new file with mode: 0644]
src/utilcode/stdafx.h [new file with mode: 0644]
src/utilcode/utilcode.vcxproj [new file with mode: 0644]
src/utilcode/utilcode.vcxproj.filters [new file with mode: 0644]

index 93edd88858b226281acd527523debce49332bf72..488392bd339e8cbe58ec8059cab3adb5d4dfc834 100644 (file)
@@ -4,9 +4,7 @@
 # Verify minimum required version
 cmake_minimum_required(VERSION 3.6.2)
 
-if(CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0)
-  cmake_policy(SET CMP0042 NEW)
-endif()
+cmake_policy(SET CMP0042 NEW) # MACOSX_RPATH is enabled by default.
 
 # Set the project name
 project(diagnostics)
@@ -32,26 +30,26 @@ endif (MSVC)
 set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME diagnostics)
 add_component(diagnostics)
 
-if (WIN32)
+if(CLR_CMAKE_HOST_WIN32)
   message(STATUS "VS_PLATFORM_TOOLSET is ${CMAKE_VS_PLATFORM_TOOLSET}")
   message(STATUS "VS_PLATFORM_NAME is ${CMAKE_VS_PLATFORM_NAME}")
-endif (WIN32)
+endif(CLR_CMAKE_HOST_WIN32)
 
 set(ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
-if (NOT WIN32)
+if(CLR_CMAKE_HOST_UNIX)
   # Drop the static scope for SOS, so it's available outside the
   # compilation unit for external linkage; see extern declaration
   # in SOS sources.
   file(READ "${VERSION_FILE_PATH}" VERSION_FILE_CONTENTS)
   string(REPLACE "static char" "char" VERSION_LINE_WITHOUT_STATIC "${VERSION_FILE_CONTENTS}")
   file(WRITE "${VERSION_FILE_PATH}" "${VERSION_LINE_WITHOUT_STATIC}")
-endif (NOT WIN32)
+endif(CLR_CMAKE_HOST_UNIX)
 
 # Where _version.h for Windows is generated
-if (WIN32)
+if(CLR_CMAKE_HOST_WIN32)
 include_directories(${CLR_ARTIFACTS_OBJ_DIR})
-endif (WIN32)
+endif(CLR_CMAKE_HOST_WIN32)
 
 set(CORECLR_SET_RPATH ON)
 if(CORECLR_SET_RPATH)
@@ -62,6 +60,17 @@ endif(CORECLR_SET_RPATH)
 OPTION(CLR_CMAKE_ENABLE_CODE_COVERAGE "Enable code coverage" OFF)
 OPTION(CLR_CMAKE_WARNINGS_ARE_ERRORS "Warnings are errors" ON)
 
+#----------------------------------------------------
+# Cross target Component build specific configuration
+#----------------------------------------------------
+if(CLR_CROSS_COMPONENTS_BUILD)
+  add_definitions(-DCROSS_COMPILE)
+
+  if(CLR_CMAKE_HOST_ARCH_AMD64 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_I386))
+    set(FEATURE_CROSSBITNESS 1)
+  endif(CLR_CMAKE_HOST_ARCH_AMD64 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_I386))
+endif(CLR_CROSS_COMPONENTS_BUILD)
+
 #------------------------------------
 # Definitions (for platform)
 #-----------------------------------
@@ -138,14 +147,17 @@ else ()
   clr_unknown_arch()
 endif (CLR_CMAKE_TARGET_ARCH_AMD64)
 
-if(WIN32)
+if(CLR_CMAKE_HOST_WIN32)
   add_definitions(-DWIN32)
   add_definitions(-D_WIN32)
   add_definitions(-DWINVER=0x0602)
   add_definitions(-D_WIN32_WINNT=0x0602)
   add_definitions(-DWIN32_LEAN_AND_MEAN=1)
   add_definitions(-D_CRT_SECURE_NO_WARNINGS)
-endif(WIN32)
+endif(CLR_CMAKE_HOST_WIN32)
+
+add_definitions(-DUNICODE)
+add_definitions(-D_UNICODE)
 
 #--------------------------------------
 # FEATURE Defines
@@ -159,9 +171,9 @@ if(CLR_CMAKE_HOST_UNIX)
     add_definitions(-DFEATURE_PAL_ANSI)
 endif(CLR_CMAKE_HOST_UNIX)
 
-if(WIN32)
+if(CLR_CMAKE_HOST_WIN32)
     add_definitions(-DFEATURE_COMINTEROP)
-endif(WIN32)
+endif(CLR_CMAKE_HOST_WIN32)
 
 if(NOT CMAKE_SYSTEM_NAME STREQUAL NetBSD)
     add_definitions(-DFEATURE_HIJACK)
index 8f3e2edc5c00d8f604281f3f935c39d35f983663..35fb836a1a878d933e5c3a711fadf8df7e3a5e8d 100644 (file)
@@ -26,8 +26,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Strike", "src\SOS\Strike\St
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbgutil", "src\SOS\dbgutil\dbgutil.vcxproj", "{A9A7C879-C320-3327-BB84-16E1322E17AE}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "debugshim", "src\SOS\debugshim\debugshim.vcxproj", "{6A94C5FE-8706-3505-834E-DA16242F3864}"
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gcdump", "src\SOS\gcdump\gcdump.vcxproj", "{20EBC3C4-917C-402D-B778-9A6E3742BF5A}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SOS.InstallHelper", "src\SOS\SOS.InstallHelper\SOS.InstallHelper.csproj", "{1F012743-941B-4915-8C55-02097894CF3F}"
@@ -78,13 +76,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "inc", "inc", "{41BDFD6D-D16
        ProjectSection(SolutionItems) = preProject
                src\inc\arrayholder.h = src\inc\arrayholder.h
                src\inc\bitvector.h = src\inc\bitvector.h
+               src\inc\check.h = src\inc\check.h
+               src\inc\check.inl = src\inc\check.inl
                src\inc\clrdata.idl = src\inc\clrdata.idl
+               src\inc\clrhost.h = src\inc\clrhost.h
                src\inc\clrinternal.idl = src\inc\clrinternal.idl
+               src\inc\clrnt.h = src\inc\clrnt.h
                src\inc\clrprivappxhosting.idl = src\inc\clrprivappxhosting.idl
                src\inc\clrprivbinding.idl = src\inc\clrprivbinding.idl
                src\inc\clrprivhosting.idl = src\inc\clrprivhosting.idl
                src\inc\clrprivruntimebinders.idl = src\inc\clrprivruntimebinders.idl
+               src\inc\clrtypes.h = src\inc\clrtypes.h
                src\inc\CMakeLists.txt = src\inc\CMakeLists.txt
+               src\inc\contract.h = src\inc\contract.h
+               src\inc\contract.inl = src\inc\contract.inl
                src\inc\cor.h = src\inc\cor.h
                src\inc\cordebug.idl = src\inc\cordebug.idl
                src\inc\coreclrhost.h = src\inc\coreclrhost.h
@@ -92,19 +97,27 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "inc", "inc", "{41BDFD6D-D16
                src\inc\corhdr.h = src\inc\corhdr.h
                src\inc\corhlpr.cpp = src\inc\corhlpr.cpp
                src\inc\corhlpr.h = src\inc\corhlpr.h
+               src\inc\corhlprpriv.h = src\inc\corhlprpriv.h
                src\inc\corjitflags.h = src\inc\corjitflags.h
                src\inc\corprof.idl = src\inc\corprof.idl
                src\inc\corpub.idl = src\inc\corpub.idl
                src\inc\corsym.idl = src\inc\corsym.idl
                src\inc\cortypeinfo.h = src\inc\cortypeinfo.h
                src\inc\crosscomp.h = src\inc\crosscomp.h
+               src\inc\crsttypes.h = src\inc\crsttypes.h
+               src\inc\crtwrap.h = src\inc\crtwrap.h
                src\inc\daccess.h = src\inc\daccess.h
                src\inc\dacprivate.h = src\inc\dacprivate.h
+               src\inc\dbgenginemetrics.h = src\inc\dbgenginemetrics.h
                src\inc\dbgportable.h = src\inc\dbgportable.h
                src\inc\dbgtargetcontext.h = src\inc\dbgtargetcontext.h
                src\inc\dbgutil.h = src\inc\dbgutil.h
                src\inc\debugmacros.h = src\inc\debugmacros.h
                src\inc\debugmacrosext.h = src\inc\debugmacrosext.h
+               src\inc\debugreturn.h = src\inc\debugreturn.h
+               src\inc\entrypoints.h = src\inc\entrypoints.h
+               src\inc\ex.h = src\inc\ex.h
+               src\inc\fstring.h = src\inc\fstring.h
                src\inc\fusion.idl = src\inc\fusion.idl
                src\inc\gcdecoder.cpp = src\inc\gcdecoder.cpp
                src\inc\gcdesc.h = src\inc\gcdesc.h
@@ -113,39 +126,69 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "inc", "inc", "{41BDFD6D-D16
                src\inc\gcinfodecoder.h = src\inc\gcinfodecoder.h
                src\inc\gcinfodumper.h = src\inc\gcinfodumper.h
                src\inc\gcinfotypes.h = src\inc\gcinfotypes.h
+               src\inc\gcmsg.inl = src\inc\gcmsg.inl
                src\inc\genericstackprobe.h = src\inc\genericstackprobe.h
+               src\inc\getproductversionnumber.h = src\inc\getproductversionnumber.h
                src\inc\hillclimbing.h = src\inc\hillclimbing.h
                src\inc\holder.h = src\inc\holder.h
                src\inc\iallocator.h = src\inc\iallocator.h
+               src\inc\iterator.h = src\inc\iterator.h
                src\inc\livedatatarget.h = src\inc\livedatatarget.h
                src\inc\log.h = src\inc\log.h
                src\inc\loglf.h = src\inc\loglf.h
                src\inc\longfilepathwrappers.h = src\inc\longfilepathwrappers.h
+               src\inc\mdcommon.h = src\inc\mdcommon.h
+               src\inc\memoryrange.h = src\inc\memoryrange.h
+               src\inc\metadata.h = src\inc\metadata.h
                src\inc\metahost.idl = src\inc\metahost.idl
                src\inc\MSCOREE.IDL = src\inc\MSCOREE.IDL
                src\inc\mscorsvc.idl = src\inc\mscorsvc.idl
                src\inc\msodw.h = src\inc\msodw.h
                src\inc\new.hpp = src\inc\new.hpp
+               src\inc\nibblemapmacros.h = src\inc\nibblemapmacros.h
+               src\inc\nsutilpriv.h = src\inc\nsutilpriv.h
                src\inc\opcode.def = src\inc\opcode.def
                src\inc\openum.h = src\inc\openum.h
+               src\inc\ostype.h = src\inc\ostype.h
                src\inc\palclr.h = src\inc\palclr.h
                src\inc\palclr_win.h = src\inc\palclr_win.h
+               src\inc\pedecoder.h = src\inc\pedecoder.h
+               src\inc\pedecoder.inl = src\inc\pedecoder.inl
                src\inc\predeftlsslot.h = src\inc\predeftlsslot.h
                src\inc\random.h = src\inc\random.h
+               src\inc\readytorun.h = src\inc\readytorun.h
+               src\inc\readytoruninstructionset.h = src\inc\readytoruninstructionset.h
                src\inc\regdisp.h = src\inc\regdisp.h
+               src\inc\registrywrapper.h = src\inc\registrywrapper.h
+               src\inc\releaseholder.h = src\inc\releaseholder.h
+               src\inc\resource.h = src\inc\resource.h
                src\inc\runtimeinfo.h = src\inc\runtimeinfo.h
                src\inc\safemath.h = src\inc\safemath.h
+               src\inc\safewrap.h = src\inc\safewrap.h
+               src\inc\sbuffer.h = src\inc\sbuffer.h
+               src\inc\sbuffer.inl = src\inc\sbuffer.inl
+               src\inc\securityutil.h = src\inc\securityutil.h
+               src\inc\securitywrapper.h = src\inc\securitywrapper.h
+               src\inc\sigparser.h = src\inc\sigparser.h
                src\inc\sospriv.idl = src\inc\sospriv.idl
+               src\inc\sstring.h = src\inc\sstring.h
+               src\inc\sstring.inl = src\inc\sstring.inl
                src\inc\stacktrace.h = src\inc\stacktrace.h
                src\inc\static_assert.h = src\inc\static_assert.h
                src\inc\staticcontract.h = src\inc\staticcontract.h
+               src\inc\stdmacros.h = src\inc\stdmacros.h
                src\inc\stresslog.h = src\inc\stresslog.h
                src\inc\switches.h = src\inc\switches.h
                src\inc\tls.h = src\inc\tls.h
+               src\inc\unreachable.h = src\inc\unreachable.h
+               src\inc\utilcode.h = src\inc\utilcode.h
                src\inc\volatile.h = src\inc\volatile.h
                src\inc\warningcontrol.h = src\inc\warningcontrol.h
+               src\inc\win64unwind.h = src\inc\win64unwind.h
+               src\inc\winwrap.h = src\inc\winwrap.h
                src\inc\xclrdata.idl = src\inc\xclrdata.idl
                src\inc\xcordebug.idl = src\inc\xcordebug.idl
+               src\inc\yieldprocessornormalized.h = src\inc\yieldprocessornormalized.h
        EndProjectSection
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "clr_std", "clr_std", "{33239640-6F4B-4DA4-A780-2F5B26D57EAD}"
@@ -203,6 +246,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExitCodeTracee", "src\tests
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-dsrouter", "src\Tools\dotnet-dsrouter\dotnet-dsrouter.csproj", "{2BD55143-B102-4FEC-84AD-DC3B330FA9AC}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbgshim", "src\dbgshim\dbgshim.vcxproj", "{BD779298-8631-3F5D-AA59-82897E5454A7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "utilcode", "src\utilcode\utilcode.vcxproj", "{8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Checked|Any CPU = Checked|Any CPU
@@ -468,30 +515,6 @@ Global
                {A9A7C879-C320-3327-BB84-16E1322E17AE}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
                {A9A7C879-C320-3327-BB84-16E1322E17AE}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
                {A9A7C879-C320-3327-BB84-16E1322E17AE}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Checked|Any CPU.ActiveCfg = Checked|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Checked|ARM.ActiveCfg = Checked|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Checked|ARM64.ActiveCfg = Checked|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Checked|x64.ActiveCfg = Checked|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Checked|x64.Build.0 = Checked|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Checked|x86.ActiveCfg = Checked|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Debug|Any CPU.ActiveCfg = Debug|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Debug|ARM.ActiveCfg = Debug|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Debug|ARM64.ActiveCfg = Debug|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Debug|x64.ActiveCfg = Debug|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Debug|x64.Build.0 = Debug|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Debug|x86.ActiveCfg = Debug|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Release|Any CPU.ActiveCfg = Release|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Release|ARM.ActiveCfg = Release|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Release|ARM64.ActiveCfg = Release|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Release|x64.ActiveCfg = Release|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Release|x64.Build.0 = Release|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.Release|x86.ActiveCfg = Release|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.RelWithDebInfo|ARM.ActiveCfg = RelWithDebInfo|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
-               {6A94C5FE-8706-3505-834E-DA16242F3864}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
                {20EBC3C4-917C-402D-B778-9A6E3742BF5A}.Checked|Any CPU.ActiveCfg = Checked|x64
                {20EBC3C4-917C-402D-B778-9A6E3742BF5A}.Checked|ARM.ActiveCfg = Checked|x64
                {20EBC3C4-917C-402D-B778-9A6E3742BF5A}.Checked|ARM64.ActiveCfg = Checked|x64
@@ -1660,6 +1683,54 @@ Global
                {2BD55143-B102-4FEC-84AD-DC3B330FA9AC}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
                {2BD55143-B102-4FEC-84AD-DC3B330FA9AC}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
                {2BD55143-B102-4FEC-84AD-DC3B330FA9AC}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Checked|Any CPU.ActiveCfg = Checked|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Checked|ARM.ActiveCfg = Checked|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Checked|ARM64.ActiveCfg = Checked|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Checked|x64.ActiveCfg = Checked|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Checked|x64.Build.0 = Checked|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Checked|x86.ActiveCfg = Checked|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Debug|Any CPU.ActiveCfg = Debug|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Debug|ARM.ActiveCfg = Debug|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Debug|ARM64.ActiveCfg = Debug|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Debug|x64.ActiveCfg = Debug|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Debug|x64.Build.0 = Debug|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Debug|x86.ActiveCfg = Debug|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Release|Any CPU.ActiveCfg = Release|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Release|ARM.ActiveCfg = Release|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Release|ARM64.ActiveCfg = Release|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Release|x64.ActiveCfg = Release|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Release|x64.Build.0 = Release|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.Release|x86.ActiveCfg = Release|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.RelWithDebInfo|ARM.ActiveCfg = RelWithDebInfo|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+               {BD779298-8631-3F5D-AA59-82897E5454A7}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Checked|Any CPU.ActiveCfg = Checked|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Checked|ARM.ActiveCfg = Checked|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Checked|ARM64.ActiveCfg = Checked|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Checked|x64.ActiveCfg = Checked|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Checked|x64.Build.0 = Checked|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Checked|x86.ActiveCfg = Checked|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Debug|Any CPU.ActiveCfg = Debug|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Debug|ARM.ActiveCfg = Debug|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Debug|ARM64.ActiveCfg = Debug|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Debug|x64.ActiveCfg = Debug|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Debug|x64.Build.0 = Debug|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Debug|x86.ActiveCfg = Debug|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Release|Any CPU.ActiveCfg = Release|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Release|ARM.ActiveCfg = Release|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Release|ARM64.ActiveCfg = Release|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Release|x64.ActiveCfg = Release|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Release|x64.Build.0 = Release|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.Release|x86.ActiveCfg = Release|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.RelWithDebInfo|ARM.ActiveCfg = RelWithDebInfo|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -1674,7 +1745,6 @@ Global
                {43D41DE9-7CCC-4DCB-A68A-B9099E538125} = {B62728C8-1267-4043-B46F-5537BBAEC692}
                {41F59D85-FC36-3015-861B-F177863252BC} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
                {A9A7C879-C320-3327-BB84-16E1322E17AE} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
-               {6A94C5FE-8706-3505-834E-DA16242F3864} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
                {20EBC3C4-917C-402D-B778-9A6E3742BF5A} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
                {1F012743-941B-4915-8C55-02097894CF3F} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
                {41351955-16D5-48D7-AF4C-AF25F5FB2E78} = {B62728C8-1267-4043-B46F-5537BBAEC692}
@@ -1712,6 +1782,8 @@ Global
                {064BC7DD-D44C-400E-9215-7546E092AB98} = {03479E19-3F18-49A6-910A-F5041E27E7C0}
                {61F73DD0-F346-4D7A-AB12-63415B4EEEE1} = {03479E19-3F18-49A6-910A-F5041E27E7C0}
                {2BD55143-B102-4FEC-84AD-DC3B330FA9AC} = {B62728C8-1267-4043-B46F-5537BBAEC692}
+               {BD779298-8631-3F5D-AA59-82897E5454A7} = {19FAB78C-3351-4911-8F0C-8C6056401740}
+               {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D} = {19FAB78C-3351-4911-8F0C-8C6056401740}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
                SolutionGuid = {46465737-C938-44FC-BE1A-4CE139EBB5E0}
index 23b321c144a682b56fe9a23f1919061997064f21..5632c47db3db5f8805e38a128bbfd581c8a24064 100644 (file)
@@ -12,6 +12,10 @@ echo Creating bundles
 powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0Build.ps1""" %_commonArgs% -bundletools %*"
 if NOT '%ERRORLEVEL%' == '0' goto ExitWithCode
 
+echo Creating dbgshim packages
+powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0common\Build.ps1""" %_commonArgs% -pack -noBl /bl:'%_logDir%PackDbgShim.binlog' -projects %~dp0..\src\dbgshim\pkg\Microsoft.Diagnostics.DbgShim.proj %*"
+if NOT '%ERRORLEVEL%' == '0' goto ExitWithCode
+
 echo Signing and publishing manifest
 powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0common\Build.ps1""" %_commonArgs% -sign -publish -noBl /bl:'%_logDir%SignPublish.binlog' %*"
 if NOT '%ERRORLEVEL%' == '0' goto ExitWithCode
index 373091b13a0014c4b900104cee8d716fd251c0fb..294e9832ad3105edd4c031616de4f1a835040d22 100755 (executable)
@@ -197,7 +197,7 @@ usage()
     echo ""
     echo "Common Options:"
     echo ""
-    echo "BuildArch can be: -arm, -armel, -arm64, -loongarch64, -s390x, x64, x86, -wasm"
+    echo "BuildArch can be: -arm, -armv6, -armel, -arm64, -loongarch64, -s390x, x64, x86, -wasm"
     echo "BuildType can be: -debug, -checked, -release"
     echo "-os: target OS (defaults to running OS)"
     echo "-bindir: output directory (defaults to $__ProjectRoot/artifacts)"
@@ -270,6 +270,10 @@ while :; do
             __BuildArch=arm
             ;;
 
+        armv6|-armv6)
+            __BuildArch=armv6
+            ;;
+
         arm64|-arm64)
             __BuildArch=arm64
             ;;
index fad1ac58d39c883e224b1336f7fccbce85b9f801..b67594cb60fb2a88633a0a7432648607d873ff2c 100644 (file)
@@ -213,6 +213,9 @@ elseif (CLR_CMAKE_HOST_ARCH_I386)
 elseif (CLR_CMAKE_HOST_ARCH_ARM)
   set(ARCH_HOST_NAME arm)
   add_definitions(-DHOST_ARM)
+elseif (CLR_CMAKE_HOST_ARCH_ARMV6)
+  set(ARCH_HOST_NAME armv6)
+  add_definitions(-DHOST_ARMV6)
 elseif (CLR_CMAKE_HOST_ARCH_ARM64)
   set(ARCH_HOST_NAME arm64)
   add_definitions(-DHOST_ARM64 -DHOST_64BIT)
@@ -238,6 +241,8 @@ if (CLR_CMAKE_HOST_UNIX)
       message("Detected Linux x86_64")
     elseif(CLR_CMAKE_HOST_UNIX_ARM)
       message("Detected Linux ARM")
+    elseif(CLR_CMAKE_HOST_UNIX_ARMV6)
+      message("Detected Linux ARMv6")
     elseif(CLR_CMAKE_HOST_UNIX_ARM64)
       message("Detected Linux ARM64")
     elseif(CLR_CMAKE_HOST_UNIX_LOONGARCH64)
@@ -301,6 +306,12 @@ elseif (CLR_CMAKE_TARGET_ARCH_ARM)
     set(ARCH_TARGET_NAME arm)
     add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_ARCH>>>:TARGET_ARM>)
     add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_ARCH>>>:TARGET_32BIT>)
+elseif (CLR_CMAKE_TARGET_ARCH_ARMV6)
+    set(ARCH_SOURCES_DIR arm)
+    set(ARCH_TARGET_NAME armv6)
+    add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_ARCH>>>:TARGET_ARM>)
+    add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_ARCH>>>:TARGET_ARMV6>)
+    add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_ARCH>>>:TARGET_32BIT>)
 elseif (CLR_CMAKE_TARGET_ARCH_I386)
     set(ARCH_TARGET_NAME x86)
     set(ARCH_SOURCES_DIR i386)
@@ -507,6 +518,14 @@ if(CLR_CMAKE_HOST_UNIX_ARM)
    endif(ARM_SOFTFP)
 endif(CLR_CMAKE_HOST_UNIX_ARM)
 
+if(CLR_CMAKE_HOST_UNIX_ARMV6)
+   add_compile_options(-mfpu=vfp)
+   add_definitions(-DCLR_ARM_FPU_CAPABILITY=0x0)
+   add_compile_options(-march=armv6zk)
+   add_compile_options(-mcpu=arm1176jzf-s)
+   add_compile_options(-mfloat-abi=hard)
+endif(CLR_CMAKE_HOST_UNIX_ARMV6)
+
 if(CLR_CMAKE_HOST_UNIX_X86)
   add_compile_options(-msse2)
 endif()
index cdf33430b49f112dc723c626fa6e7c66b7b6ed08..ecf10a8d4c39ef210baae50fe2e5edd60a7a37e9 100644 (file)
@@ -41,6 +41,8 @@ if(CLR_CMAKE_HOST_OS STREQUAL Linux)
             set(CLR_CMAKE_HOST_UNIX_ARMV7L 1)
         elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL arm OR CMAKE_SYSTEM_PROCESSOR STREQUAL armv7-a)
             set(CLR_CMAKE_HOST_UNIX_ARM 1)
+        elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv6 OR CMAKE_SYSTEM_PROCESSOR STREQUAL armv6l)
+            set(CLR_CMAKE_HOST_UNIX_ARMV6 1)
         elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL arm64)
             set(CLR_CMAKE_HOST_UNIX_ARM64 1)
         elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL loongarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL loongarch64)
@@ -217,6 +219,13 @@ if(CLR_CMAKE_HOST_UNIX_ARM)
     if(CLR_CMAKE_HOST_UNIX_ARMV7L)
         set(CLR_CMAKE_HOST_ARCH_ARMV7L 1)
     endif()
+elseif(CLR_CMAKE_HOST_UNIX_ARMV6)
+    set(CLR_CMAKE_HOST_ARCH_ARMV6 1)
+    set(CLR_CMAKE_HOST_ARCH "armv6")
+
+    if(CLR_CMAKE_HOST_UNIX_ARMV6L)
+        set(CLR_CMAKE_HOST_ARCH_ARMV6L 1)
+    endif()
 elseif(CLR_CMAKE_HOST_UNIX_ARM64)
     set(CLR_CMAKE_HOST_ARCH_ARM64 1)
     set(CLR_CMAKE_HOST_ARCH "arm64")
@@ -277,6 +286,8 @@ if (CLR_CMAKE_TARGET_ARCH STREQUAL x64)
     set(CLR_CMAKE_TARGET_ARCH_LOONGARCH64 1)
   elseif(CLR_CMAKE_TARGET_ARCH STREQUAL arm)
     set(CLR_CMAKE_TARGET_ARCH_ARM 1)
+  elseif(CLR_CMAKE_TARGET_ARCH STREQUAL armv6)
+    set(CLR_CMAKE_TARGET_ARCH_ARMV6 1)
   elseif(CLR_CMAKE_TARGET_ARCH STREQUAL armel)
     set(CLR_CMAKE_TARGET_ARCH_ARM 1)
     set(CLR_CMAKE_TARGET_ARCH_ARMV7L 1)
@@ -379,6 +390,8 @@ if(CLR_CMAKE_TARGET_UNIX)
         set(CLR_CMAKE_TARGET_UNIX_ARM 1)
     elseif(CLR_CMAKE_TARGET_ARCH STREQUAL arm)
         set(CLR_CMAKE_TARGET_UNIX_ARM 1)
+    elseif(CLR_CMAKE_TARGET_ARCH STREQUAL armv6)
+        set(CLR_CMAKE_TARGET_UNIX_ARMV6 1)
     elseif(CLR_CMAKE_TARGET_ARCH STREQUAL arm64)
         set(CLR_CMAKE_TARGET_UNIX_ARM64 1)
     elseif(CLR_CMAKE_TARGET_ARCH STREQUAL loongarch64)
index 136cd67925d0cb48797a0658e8dcadeffcb72a3b..ad5dc38107c33f3937b1b352b1c38c5647872509 100644 (file)
@@ -52,8 +52,8 @@ if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_BROWSER)
 
     if(CLR_CMAKE_TARGET_ANDROID)
       set(TOOLSET_PREFIX ${ANDROID_TOOLCHAIN_PREFIX})
-    elseif(CMAKE_CROSSCOMPILING AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD AND (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l OR
-       CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL arm OR CMAKE_SYSTEM_PROCESSOR STREQUAL s390x))
+    elseif(CMAKE_CROSSCOMPILING AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD AND
+        CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv7l|armv6l|aarch64|arm|s390x)$")
       set(TOOLSET_PREFIX "${TOOLCHAIN}-")
     else()
       set(TOOLSET_PREFIX "")
index 4e68a9be01e8c9ea2ddda36b77b9af0bd9c83e84..0c28f75706de1959a2a00e443a1f44d92f261cdd 100644 (file)
@@ -4,10 +4,75 @@ function(clr_unknown_arch)
     elseif(CLR_CROSS_COMPONENTS_BUILD)
         message(FATAL_ERROR "Only AMD64, I386 host are supported for linux cross-architecture component. Found: ${CMAKE_SYSTEM_PROCESSOR}")
     else()
-        message(FATAL_ERROR "Only AMD64, ARM64, LOONGARCH64 and ARM are supported. Found: ${CMAKE_SYSTEM_PROCESSOR}")
+        message(FATAL_ERROR "Only AMD64, ARMV6, ARM64, LOONGARCH64 and ARM are supported. Found: ${CMAKE_SYSTEM_PROCESSOR}")
     endif()
 endfunction()
 
+# C to MASM include file translator
+# This is replacement for the deprecated h2inc tool that used to be part of VS.
+function(h2inc filename output)
+    file(STRINGS ${filename} lines)
+    get_filename_component(path "${filename}" DIRECTORY)
+    file(RELATIVE_PATH relative_filename "${CLR_REPO_ROOT_DIR}" "${filename}")
+
+    file(APPEND "${output}" "// File start: ${relative_filename}\n")
+
+    # Use of NEWLINE_CONSUME is needed for lines with trailing backslash
+    file(STRINGS ${filename} contents NEWLINE_CONSUME)
+    string(REGEX REPLACE "\\\\\n" "\\\\\\\\ \n" contents "${contents}")
+    string(REGEX REPLACE "\n" ";" lines "${contents}")
+
+    foreach(line IN LISTS lines)
+        string(REGEX REPLACE "\\\\\\\\ " "\\\\" line "${line}")
+
+        if(line MATCHES "^ *# pragma")
+            # Ignore pragmas
+            continue()
+        endif()
+
+        if(line MATCHES "^ *# *include *\"(.*)\"")
+            # Expand includes.
+            h2inc("${path}/${CMAKE_MATCH_1}" "${output}")
+            continue()
+        endif()
+
+        if(line MATCHES "^ *#define +([0-9A-Za-z_()]+) *(.*)")
+            # Augment #defines with their MASM equivalent
+            set(name "${CMAKE_MATCH_1}")
+            set(value "${CMAKE_MATCH_2}")
+
+            # Note that we do not handle multiline constants
+
+            # Strip comments from value
+            string(REGEX REPLACE "//.*" "" value "${value}")
+            string(REGEX REPLACE "/\\*.*\\*/" "" value "${value}")
+
+            # Strip whitespaces from value
+            string(REPLACE " +$" "" value "${value}")
+
+            # ignore #defines with arguments
+            if(NOT "${name}" MATCHES "\\(")
+                set(HEX_NUMBER_PATTERN "0x([0-9A-Fa-f]+)")
+                set(DECIMAL_NUMBER_PATTERN "(-?[0-9]+)")
+
+                if("${value}" MATCHES "${HEX_NUMBER_PATTERN}")
+                    string(REGEX REPLACE "${HEX_NUMBER_PATTERN}" "0\\1h" value "${value}")    # Convert hex constants
+                    file(APPEND "${output}" "${name} EQU ${value}\n")
+                elseif("${value}" MATCHES "${DECIMAL_NUMBER_PATTERN}" AND (NOT "${value}" MATCHES "[G-Zg-z]+" OR "${value}" MATCHES "\\("))
+                    string(REGEX REPLACE "${DECIMAL_NUMBER_PATTERN}" "\\1t" value "${value}") # Convert dec constants
+                    file(APPEND "${output}" "${name} EQU ${value}\n")
+                else()
+                    file(APPEND "${output}" "${name} TEXTEQU <${value}>\n")
+                endif()
+            endif()
+        endif()
+
+        file(APPEND "${output}" "${line}\n")
+    endforeach()
+
+    file(APPEND "${output}" "// File end: ${relative_filename}\n")
+endfunction()
+
 # 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
@@ -90,6 +155,10 @@ function(find_unwind_libs UnwindLibs)
       find_library(UNWIND_ARCH NAMES unwind-arm)
     endif()
 
+    if(CLR_CMAKE_HOST_ARCH_ARMV6)
+      find_library(UNWIND_ARCH NAMES unwind-arm)
+    endif()
+
     if(CLR_CMAKE_HOST_ARCH_ARM64)
       find_library(UNWIND_ARCH NAMES unwind-aarch64)
     endif()
index 586534be1c8aa91142fccbc14f9286e1010087d5..eda07a5feebbdf7dd6595b1b030be334696f45fe 100644 (file)
@@ -53,6 +53,10 @@ case "$CPUName" in
         fi
         ;;
 
+    armv6l)
+        arch=armv6
+        ;;
+
     i[3-6]86)
         echo "Unsupported CPU $CPUName detected, build might not succeed!"
         arch=x86
index e8a04c5698ad357b0ae993bcd027a42122863f33..fca410fcb4b42fd50e88adad45fb43c64947a079 100644 (file)
@@ -68,7 +68,7 @@ if(DARWIN)
   else()
     message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only arm64 or x64 is supported for OSX cross build!")
   endif()
-elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|arm64|loongarch64|s390x|x86)$" OR FREEBSD OR ILLUMOS)
+elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|armv6|arm64|loongarch64|s390x|x86)$" OR FREEBSD OR ILLUMOS)
   set_cache_value(FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL_EXITCODE 1)
   set_cache_value(GETPWUID_R_SETS_ERRNO_EXITCODE 0)
   set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 0)
@@ -146,9 +146,9 @@ elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|arm64|loongarch64|s390x|x86)$" OR F
     set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 0)
   endif()
 else()
-  message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64, loongarch64, s390x and x86 are supported!")
+  message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, armv6, arm64, loongarch64, s390x and x86 are supported!")
 endif()
 
-if(TARGET_ARCH_NAME STREQUAL "x86" OR TARGET_ARCH_NAME STREQUAL "s390x" OR TARGET_ARCH_NAME STREQUAL "loongarch64")
+if(TARGET_ARCH_NAME STREQUAL "x86" OR TARGET_ARCH_NAME STREQUAL "s390x" OR TARGET_ARCH_NAME STREQUAL "armv6" OR TARGET_ARCH_NAME STREQUAL "loongarch64")
   set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 0)
 endif()
index 31f1e5400ece158962249e11d57629397e981a0f..9eebfe97cfb192280925dd72b992820132fefb67 100644 (file)
@@ -2,6 +2,7 @@
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
     <IsPackable>true</IsPackable>
+    <IsShipping>false</IsShipping>
     <IsShippingPackage>false</IsShippingPackage>
     <PreReleaseVersionLabel></PreReleaseVersionLabel>
     <VersionPrefix></VersionPrefix>
index 5f08b4bc7305a3ced623808d216926fae961180d..3bc4b89655edd06f53f3fe8257496c0a1dd32087 100644 (file)
@@ -2,6 +2,7 @@
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
     <IsPackable>true</IsPackable>
+    <IsShipping>false</IsShipping>
     <IsShippingPackage>false</IsShippingPackage>
     <PreReleaseVersionLabel></PreReleaseVersionLabel>
     <VersionPrefix></VersionPrefix>
index 194b91559fd62d975d09e454b5a9942dc2ebf334..bec77d77569b35882f3714612cfeecaa71806e68 100644 (file)
@@ -1,11 +1,27 @@
+if (CLR_CMAKE_HOST_UNIX)
+  include_directories("${ROOT_DIR}/src/pal/inc")
+  include_directories("${ROOT_DIR}/src/pal/inc/rt")
+  include_directories("${ROOT_DIR}/src/pal/src/safecrt")
+endif (CLR_CMAKE_HOST_UNIX)
+
 include_directories(${ROOT_DIR}/src)
 include_directories(${ROOT_DIR}/src/pal/prebuilt/inc)
 include_directories(inc)
 
 if (CLR_CMAKE_HOST_UNIX)
-    add_subdirectory(palrt)
-    add_subdirectory(pal)
+  add_subdirectory(pal)
 endif(CLR_CMAKE_HOST_UNIX)
 
 add_subdirectory(inc)
 add_subdirectory(SOS)
+
+if (CLR_CMAKE_HOST_UNIX)
+  # This prevents inclusion of standard C compiler headers
+  add_compile_options(-nostdinc)
+  include_directories(${ROOT_DIR}/src/pal/inc/rt/cpp)
+
+  add_subdirectory(palrt)
+endif(CLR_CMAKE_HOST_UNIX)
+
+add_subdirectory(utilcode)
+add_subdirectory(dbgshim)
index 7dfea314a2bdbcb00f0873ac50b2d7536b50e794..a57c548c0bc0c28f83ea887aa91cd8a5d974fffb 100644 (file)
@@ -3,8 +3,7 @@
   <Import Project="Sdk.props" Sdk="Microsoft.DotNet.Arcade.Sdk" />
 
   <PropertyGroup>
-    <IsShipping>true</IsShipping>
-    <IsShippingAssembly>false</IsShippingAssembly>
+    <IsShipping>false</IsShipping>
     <WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
     <NoPackageAnalysis>true</NoPackageAnalysis>
     <DebugSymbols>true</DebugSymbols>
index a7ede1880dd8f3a8e83d3d04a5c3b34d9671cc71..d36528d89ab3d2ab346328ff3f115d8eadf36b5f 100644 (file)
@@ -9,8 +9,8 @@
     <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <IncludeSymbols>true</IncludeSymbols>
-    <IsShipping>false</IsShipping>
-    <IsShippingAssembly>true</IsShippingAssembly>
+    <IsShipping>true</IsShipping>
+    <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
   
   <ItemGroup>
index 2e64849144470ea3c3ca62d70cef415e9b915496..a441d0e6bd2a3de0056cb358e0df4be2bfb19614 100644 (file)
@@ -9,6 +9,7 @@
     <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <IncludeSymbols>true</IncludeSymbols>
+    <IsShipping>true</IsShipping>
     <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
   
index 1d7fac1122dbd71053154b5aa0d681de7975c004..a18bae92284f20278db409e53a9032eb372782e6 100644 (file)
@@ -6,12 +6,12 @@
     <NoWarn>;1591;1701</NoWarn>
     <Description>Diagnostics extension commands</Description>
     <IsPackable>true</IsPackable>
-    <IsShipping>false</IsShipping>
     <PackageTags>Diagnostic</PackageTags>
     <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <IncludeSymbols>true</IncludeSymbols>
-    <IsShippingAssembly>true</IsShippingAssembly>
+    <IsShipping>true</IsShipping>
+    <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
 
   <ItemGroup>
index efc358643fb6aedadc8fab193128ec21205d609b..733d18da1e0734a8c3f10fa3a54a04233895c926 100644 (file)
@@ -12,6 +12,7 @@
     <IncludeSymbols>true</IncludeSymbols>
     <!-- Do not ship this package until ready to be consumed. -->
     <IsShipping>false</IsShipping>
+    <IsShippingAssembly>true</IsShippingAssembly>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <!-- Version information -->
     <VersionPrefix>5.0.0</VersionPrefix>
index edbd3ef9a63db540b12c735d86539a7fdd2dadfd..0f4d550e78b6a84a2c6f88ae67e71724d25c13ef 100644 (file)
@@ -12,6 +12,7 @@
     <IncludeSymbols>true</IncludeSymbols>
     <!-- Do not ship this package until ready to be consumed. -->
     <IsShipping>false</IsShipping>
+    <IsShippingAssembly>true</IsShippingAssembly>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <!-- Version information -->
     <VersionPrefix>5.0.0</VersionPrefix>
index 9016c741969ee0928e8c0bd2b58283cd83344414..4dd5472a3b225bf84db1fc88d9229da1e05a8971 100644 (file)
@@ -3,12 +3,13 @@
     <TargetFramework>netstandard2.0</TargetFramework>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <NoWarn>;1591;1701</NoWarn>
-    <Description>Diagnostic utility functions and helpers</Description>
+    <Description>Diagnostic command line REPL support</Description>
     <IsPackable>true</IsPackable>
     <PackageTags>Diagnostic</PackageTags>
     <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <IncludeSymbols>true</IncludeSymbols>
+    <IsShipping>true</IsShipping>
     <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
   
index 7f26813730377ea5c8f221ec242ff885b07b8f4b..3dc1781e0405701c5f9af6c8f55f872b00d6310c 100644 (file)
@@ -1,12 +1,9 @@
 if(CLR_CMAKE_HOST_UNIX)
-    include_directories(${ROOT_DIR}/src/pal/inc)
-    include_directories(${ROOT_DIR}/src/pal/inc/rt)
-
-    add_subdirectory(lldbplugin)
+  add_subdirectory(lldbplugin)
 endif(CLR_CMAKE_HOST_UNIX)
 
 # lldbplugin doesn't build with these options
-if(WIN32)
+if(CLR_CMAKE_HOST_WIN32)
   message(STATUS "CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
 
   message(STATUS "VSInstallDir: $ENV{VSInstallDir}")
@@ -19,7 +16,7 @@ if(WIN32)
   if(NOT CLR_CMAKE_TARGET_ARCH_ARM64)
     add_subdirectory(SOS.UnitTests/Debuggees/DesktopClrHost)
   endif()
-endif(WIN32)
+endif(CLR_CMAKE_HOST_WIN32)
 
 add_definitions(-D_SECURE_SCL=0)
 
@@ -34,13 +31,3 @@ add_subdirectory(extensions)
 add_subdirectory(dbgutil)
 add_subdirectory(SOS.Extensions)
 add_subdirectory(Strike)
-
-if(CLR_CMAKE_HOST_UNIX)
-  add_compile_options(-fPIC)
-
-  # Include the dummy c++ include files
-  include_directories(${ROOT_DIR}/src/pal/inc/rt/cpp)
-
-  # This prevents inclusion of standard C compiler headers
-  add_compile_options(-nostdinc)
-endif(CLR_CMAKE_HOST_UNIX)
index fc0ab84f3f2964d20dc20a79e8907705cd60686d..0185dcec4aaa37edb5d6418951b17ac871d6314e 100644 (file)
@@ -6,6 +6,7 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <NoWarn>;1591;1701</NoWarn>
     <Description>.NET Diagnostic Extensions support</Description>
+    <IsShipping>true</IsShipping>
     <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
   
index 0abaa83e9b8f0be0ffd70c3d5cdb8c160431a0a9..5eab9ca5bcb04cd4131592344e6d320521e2eff8 100644 (file)
@@ -5,6 +5,8 @@
     <NoWarn>;1591;1701</NoWarn>
     <Description>SOS Hosting support</Description>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <IsShipping>true</IsShipping>
+    <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
   
   <ItemGroup>
index aa0ced1ddbaee4ce68ad213c678921e5eb473ff3..9f007f06429529f0a5c79062ca70c84e06a4cd41 100644 (file)
@@ -3,8 +3,11 @@
     <TargetFramework>netstandard2.0</TargetFramework>
     <AssemblyName>SOS.InstallHelper</AssemblyName>
     <NoWarn>;1591;1701</NoWarn>
+    <IsPackable>false</IsPackable>
     <Description>Diagnostic SOS Install Helper</Description>
     <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
     <PackageTags>SOS</PackageTags>
+    <IsShipping>true</IsShipping>
+    <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
 </Project>
index 4a8e97e2dd70ca907d249892d82be8097c777268..8ae407ed74a277ce8a2e0ed9167ea461b9d8834e 100644 (file)
@@ -11,6 +11,7 @@
     <SOSPackagePathPrefix>tools</SOSPackagePathPrefix>
     <GalleryManifestName>$(ArtifactsPackagesDir)\GalleryManifest.xml</GalleryManifestName>
     <BeforePack>GenerateGalleryZip;GenerateSymbolsZip</BeforePack>
+    <IsShipping>true</IsShipping>
     <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
     
index d5256031e425736e0f90ea9f32767817ae666ee0..83cd791cffb446a257293a0e2a92a0560e03dd88 100644 (file)
@@ -7,9 +7,10 @@
     <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
     <IsPackable>true</IsPackable>
     <IncludeBuildOutput>false</IncludeBuildOutput>
-    <IsShippingPackage>false</IsShippingPackage>
     <IncludeSymbols>true</IncludeSymbols>
     <SOSPackagePathPrefix>tools</SOSPackagePathPrefix>
+    <IsShipping>true</IsShipping>
+    <IsShippingPackage>false</IsShippingPackage>
   </PropertyGroup>
 
   <ItemGroup>
index 832fbf046af49dee37a517b9b3faf7b266382eee..84fd31988ea1c2e4fee8babb7bc91af0ff5fefb7 100644 (file)
@@ -4,7 +4,6 @@
   <PropertyGroup>
     <DebugType Condition="'$(TargetFramework)' == 'net462'">full</DebugType>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <IsShippingAssembly>false</IsShippingAssembly>
     <Optimize>false</Optimize>
     <BuildTargetFrameworks>netcoreapp3.1;net5.0;net6.0</BuildTargetFrameworks>
   </PropertyGroup>
index 4d70c6b32edb1dd5897622d2a92ff70862d237a1..589abfc8fdf6ccee44b87cfe7f8db59bdb5663ff 100644 (file)
@@ -145,8 +145,6 @@ else(WIN32)
 
   include_directories(BEFORE xplat)
 
-  add_compile_options(-fPIC)
-
   set(SOS_SOURCES
     disasm.cpp
     eeheap.cpp
index aabb53e32a0a0b9d0ad300e6c55ab93136922d2c..eafce1b5e001466a8dcfc497b123f9d61ac3d360 100644 (file)
@@ -10907,7 +10907,7 @@ extern char sccsid[];
 \**********************************************************************/
 DECLARE_API(EEVersion)
 {
-    INIT_API();
+    INIT_API_NO_RET_ON_FAILURE();
 
     static const int fileVersionBufferSize = 1024;
     ArrayHolder<char> fileVersionBuffer = new char[fileVersionBufferSize];
@@ -10949,15 +10949,20 @@ DECLARE_API(EEVersion)
         }
     }
 
-    if (!InitializeHeapData())
-        ExtOut("GC Heap not initialized, so GC mode is not determined yet.\n");
-    else if (IsServerBuild())
-        ExtOut("Server mode with %d gc heaps\n", GetGcHeapCount());
-    else
-        ExtOut("Workstation mode\n");
+    // Only print if DAC was loaded/initialized
+    if (g_sos != nullptr)
+    {
+        if (!InitializeHeapData())
+            ExtOut("GC Heap not initialized, so GC mode is not determined yet.\n");
+        else if (IsServerBuild())
+            ExtOut("Server mode with %d gc heaps\n", GetGcHeapCount());
+        else
+            ExtOut("Workstation mode\n");
 
-    if (!GetGcStructuresValid()) {
-        ExtOut("In plan phase of garbage collection\n");
+        if (!GetGcStructuresValid()) 
+        {
+            ExtOut("In plan phase of garbage collection\n");
+        }
     }
 
     // Print SOS version
@@ -11171,7 +11176,7 @@ DECLARE_API (ProcInfo)
         typedef BOOL (WINAPI *FntGetProcessTimes)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
         static FntGetProcessTimes pFntGetProcessTimes = (FntGetProcessTimes)-1;
         if (pFntGetProcessTimes == (FntGetProcessTimes)-1) {
-            HINSTANCE hstat = LoadLibrary ("Kernel32.dll");
+            HINSTANCE hstat = LoadLibraryA("kernel32.dll");
             if (hstat != 0)
             {
                 pFntGetProcessTimes = (FntGetProcessTimes)GetProcAddress (hstat, "GetProcessTimes");
@@ -11270,7 +11275,7 @@ DECLARE_API (ProcInfo)
 
         static FntNtQueryInformationProcess pFntNtQueryInformationProcess = (FntNtQueryInformationProcess)-1;
         if (pFntNtQueryInformationProcess == (FntNtQueryInformationProcess)-1) {
-            HINSTANCE hstat = LoadLibrary ("ntdll.dll");
+            HINSTANCE hstat = LoadLibraryA("ntdll.dll");
             if (hstat != 0)
             {
                 pFntNtQueryInformationProcess = (FntNtQueryInformationProcess)GetProcAddress (hstat, "NtQueryInformationProcess");
index dbd92db0bd2484768817d82442e89f8c6feca16c..da46121b853a5f70a9d8dff359511f22e91a50f0 100644 (file)
@@ -256,7 +256,7 @@ BOOL GetProcAddressT(PCSTR FunctionName, PCSTR DllName, T* OutFunctionPointer, H
     HMODULE DllHandle = *InOutDllHandle;
     if (DllHandle == NULL)
     {
-        DllHandle = LoadLibraryEx(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+        DllHandle = LoadLibraryExA(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
         if (DllHandle != NULL)
             *InOutDllHandle = DllHandle;
     }
index 0bf6aac459f7fb98c2b827c735f05b59c1250454..ff722fb0e0937be8624ab97b27aee0b4511ed091 100644 (file)
@@ -243,8 +243,8 @@ const WCHAR GetTargetDirectorySeparatorW()
 // Check if a file exist
 BOOL FileExist (const char *filename)
 {
-    WIN32_FIND_DATA FindFileData;
-    HANDLE handle = FindFirstFile (filename, &FindFileData);
+    WIN32_FIND_DATAA FindFileData;
+    HANDLE handle = FindFirstFileA(filename, &FindFileData);
     if (handle != INVALID_HANDLE_VALUE) {
         FindClose (handle);
         return TRUE;
@@ -3604,7 +3604,7 @@ BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo)
             {
                 VS_FIXEDFILEINFO *pTmpFileInfo = NULL;
                 UINT uLen = 0;
-                if (VerQueryValue(pVersionInfo, "\\", (LPVOID *) &pTmpFileInfo, &uLen))
+                if (VerQueryValueA(pVersionInfo, "\\", (LPVOID *) &pTmpFileInfo, &uLen))
                 {
                     if (pFileInfo->dwFileVersionMS == (DWORD)-1) {
                         return FALSE;
index 34bacd1424cf6ad4a9224969090029c42b77561c..84bac1501d19eef4092fe8f5d8886dc1b2e646f5 100644 (file)
@@ -3,7 +3,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
 if(CLR_CMAKE_HOST_WIN32)
     include_directories(${ROOT_DIR}/src/inc/llvm)
     #use static crt
-    add_definitions(-MT)
+    set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
 endif(CLR_CMAKE_HOST_WIN32)
 
 add_definitions(-DPAL_STDCPP_COMPAT)
@@ -22,5 +22,4 @@ if(NOT DEFINED CLR_CMAKE_HOST_OSX)
     )
 endif(NOT DEFINED CLR_CMAKE_HOST_OSX)
 
-
 add_library(dbgutil STATIC ${DBGUTIL_SOURCES})
diff --git a/src/SOS/debugshim/CMakeLists.txt b/src/SOS/debugshim/CMakeLists.txt
deleted file mode 100644 (file)
index e200564..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-if(WIN32)
-  #use static crt
-  add_definitions(-MT) 
-  add_definitions(-DHOST_IS_WINDOWS_OS)
-endif(WIN32)
-
-if(CLR_CMAKE_HOST_UNIX)
-    add_compile_options(-fPIC)
-endif(CLR_CMAKE_HOST_UNIX)
-
-set(DEBUGSHIM_SOURCES
-  debugshim.cpp
-)
-
-add_library(debugshim STATIC ${DEBUGSHIM_SOURCES})
diff --git a/src/SOS/debugshim/debugshim.cpp b/src/SOS/debugshim/debugshim.cpp
deleted file mode 100644 (file)
index f7d7a7a..0000000
+++ /dev/null
@@ -1,789 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-//*****************************************************************************
-// debugshim.cpp
-// 
-
-//
-//*****************************************************************************
-
-#include "debugshim.h"
-#include "dbgutil.h"
-#include <crtdbg.h>
-#include <clrinternal.h> //has the CLR_ID_V4_DESKTOP guid in it
-#include "palclr.h"
-
-#ifndef IMAGE_FILE_MACHINE_ARMNT
-#define IMAGE_FILE_MACHINE_ARMNT             0x01c4  // ARM Thumb-2 Little-Endian
-#endif
-
-#ifndef IMAGE_FILE_MACHINE_ARM64
-#define IMAGE_FILE_MACHINE_ARM64             0xAA64  // ARM64 Little-Endian
-#endif
-
-#ifndef IMAGE_FILE_MACHINE_MIPS64
-#define IMAGE_FILE_MACHINE_MIPS64             0xDD64  // MIPS64 Little-Endian
-#endif
-
-// making the defines very clear, these represent the host architecture - aka
-// the arch on which this code is running
-#if defined(_X86_)
-#define _HOST_X86_
-#elif defined(_AMD64_)
-#define _HOST_AMD64_
-#elif defined(_ARM_)
-#define _HOST_ARM_
-#elif defined(_ARM64_)
-#define _HOST_ARM64_
-#elif defined(_MIPS64_)
-#define _HOST_MIPS64_
-#endif
-
-//*****************************************************************************
-// CLRDebuggingImpl implementation (ICLRDebugging)
-//*****************************************************************************
-
-typedef HRESULT (STDAPICALLTYPE  *OpenVirtualProcessImpl2FnPtr)(ULONG64 clrInstanceId, 
-    IUnknown * pDataTarget,
-    LPCWSTR pDacModulePath,
-    CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
-    REFIID riid,
-    IUnknown ** ppInstance,
-    CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
-
-typedef HRESULT (STDAPICALLTYPE  *OpenVirtualProcessImplFnPtr)(ULONG64 clrInstanceId, 
-    IUnknown * pDataTarget,
-    HMODULE hDacDll,
-    CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
-    REFIID riid,
-    IUnknown ** ppInstance,
-    CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
-
-typedef HRESULT (STDAPICALLTYPE  *OpenVirtualProcess2FnPtr)(ULONG64 clrInstanceId, 
-    IUnknown * pDataTarget,
-    HMODULE hDacDll,
-    REFIID riid,
-    IUnknown ** ppInstance,
-    CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
-
-typedef HMODULE (STDAPICALLTYPE  *LoadLibraryWFnPtr)(LPCWSTR lpLibFileName);
-
-// Implementation of ICLRDebugging::OpenVirtualProcess
-//
-// Arguments:
-//   moduleBaseAddress - the address of the module which might be a CLR
-//   pDataTarget - the data target for inspecting the process
-//   pLibraryProvider - a callback for locating DBI and DAC
-//   pMaxDebuggerSupportedVersion - the max version of the CLR that this debugger will support debugging
-//   riidProcess - the IID of the interface that should be passed back in ppProcess
-//   ppProcess - output for the ICorDebugProcess# if this module is a CLR
-//   pVersion - the CLR version if this module is a CLR
-//   pFlags - output, see the CLR_DEBUGGING_PROCESS_FLAGS for more details. Right now this has only one possible
-//            value which indicates this runtime had an unhandled exception
-STDMETHODIMP CLRDebuggingImpl::OpenVirtualProcess(
-    ULONG64 moduleBaseAddress,
-    IUnknown * pDataTarget,
-    ICLRDebuggingLibraryProvider * pLibraryProvider,
-    CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
-    REFIID riidProcess,
-    IUnknown ** ppProcess,
-    CLR_DEBUGGING_VERSION * pVersion,
-    CLR_DEBUGGING_PROCESS_FLAGS * pFlags)
-{
-    //PRECONDITION(CheckPointer(pDataTarget));
-
-    HRESULT hr = S_OK;
-    ICorDebugDataTarget * pDt = NULL;
-    HMODULE hDbi = NULL;
-    HMODULE hDac = NULL;
-    LPWSTR pDacModulePath = NULL;
-    LPWSTR pDbiModulePath = NULL;
-    DWORD dbiTimestamp;
-    DWORD dbiSizeOfImage;
-    WCHAR dbiName[MAX_PATH_FNAME] = { 0 };
-    DWORD dacTimestamp;
-    DWORD dacSizeOfImage;
-    WCHAR dacName[MAX_PATH_FNAME] = { 0 };
-    CLR_DEBUGGING_VERSION version;
-    BOOL versionSupportedByCaller = FALSE;
-
-    // argument checking
-    if ((ppProcess != NULL || pFlags != NULL) && pLibraryProvider == NULL)
-    {
-        hr = E_POINTER; // the library provider must be specified if either
-                            // ppProcess or pFlags is non-NULL
-    }
-    else if ((ppProcess != NULL || pFlags != NULL) && pMaxDebuggerSupportedVersion == NULL)
-    {
-        hr = E_POINTER; // the max supported version must be specified if either
-                            // ppProcess or pFlags is non-NULL
-    }
-    else if (pVersion != NULL && pVersion->wStructVersion != 0)
-    {
-        hr = CORDBG_E_UNSUPPORTED_VERSION_STRUCT;
-    }
-    else if (FAILED(pDataTarget->QueryInterface(__uuidof(ICorDebugDataTarget), (void**)&pDt)))
-    {
-        hr = CORDBG_E_MISSING_DATA_TARGET_INTERFACE;
-    }
-
-    if (SUCCEEDED(hr))
-    {
-        // get CLR version
-        // The expectation is that new versions of the CLR will continue to use the same GUID
-        // (unless there's a reason to hide them from older shims), but debuggers will tell us the
-        // CLR version they're designed for and mscordbi.dll can decide whether or not to accept it.
-        version.wStructVersion = 0;
-        hr = GetCLRInfo(pDt,
-            moduleBaseAddress,
-            &version,
-            &dbiTimestamp,
-            &dbiSizeOfImage,
-            dbiName,
-            MAX_PATH_FNAME,
-            &dacTimestamp,
-            &dacSizeOfImage,
-            dacName,
-            MAX_PATH_FNAME);
-    }
-
-    // If we need to fetch either the process info or the flags info then we need to find
-    // mscordbi and DAC and do the version specific OVP work
-    if (SUCCEEDED(hr) && (ppProcess != NULL || pFlags != NULL))
-    {
-        ICLRDebuggingLibraryProvider2* pLibraryProvider2;
-        if (SUCCEEDED(pLibraryProvider->QueryInterface(__uuidof(ICLRDebuggingLibraryProvider2), (void**)&pLibraryProvider2)))
-        {
-            if (FAILED(pLibraryProvider2->ProvideLibrary2(dbiName, dbiTimestamp, dbiSizeOfImage, &pDbiModulePath)) ||
-                pDbiModulePath == NULL)
-            {
-                hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
-            }
-
-            if (SUCCEEDED(hr))
-            {
-                hDbi = LoadLibraryW(pDbiModulePath);
-                if (hDbi == NULL)
-                {
-                    hr = HRESULT_FROM_WIN32(GetLastError());
-                }
-            }
-
-            if (SUCCEEDED(hr))
-            {
-                // Adjust the timestamp and size of image if this DAC is a known buggy version and needs to be retargeted
-                RetargetDacIfNeeded(&dacTimestamp, &dacSizeOfImage);
-
-                // Ask library provider for dac
-                if (FAILED(pLibraryProvider2->ProvideLibrary2(dacName, dacTimestamp, dacSizeOfImage, &pDacModulePath)) ||
-                    pDacModulePath == NULL)
-                {
-                    hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
-                }
-
-                if (SUCCEEDED(hr))
-                {
-                    hDac = LoadLibraryW(pDacModulePath);
-                    if (hDac == NULL)
-                    {
-                        hr = HRESULT_FROM_WIN32(GetLastError());
-                    }
-                }
-            }
-
-            pLibraryProvider2->Release();
-        }
-        else {
-            // Ask library provider for dbi
-            if (FAILED(pLibraryProvider->ProvideLibrary(dbiName, dbiTimestamp, dbiSizeOfImage, &hDbi)) ||
-                hDbi == NULL)
-            {
-                hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
-            }
-
-            if (SUCCEEDED(hr))
-            {
-                // Adjust the timestamp and size of image if this DAC is a known buggy version and needs to be retargeted
-                RetargetDacIfNeeded(&dacTimestamp, &dacSizeOfImage);
-
-                // ask library provider for dac
-                if (FAILED(pLibraryProvider->ProvideLibrary(dacName, dacTimestamp, dacSizeOfImage, &hDac)) ||
-                    hDac == NULL)
-                {
-                    hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
-                }
-            }
-        }
-
-        *ppProcess = NULL;
-
-        if (SUCCEEDED(hr) && pDacModulePath != NULL)
-        {
-            // Get access to the latest OVP implementation and call it
-            OpenVirtualProcessImpl2FnPtr ovpFn = (OpenVirtualProcessImpl2FnPtr)GetProcAddress(hDbi, "OpenVirtualProcessImpl2");
-            if (ovpFn != NULL)
-            {
-                hr = ovpFn(moduleBaseAddress, pDataTarget, pDacModulePath, pMaxDebuggerSupportedVersion, riidProcess, ppProcess, pFlags);
-                if (FAILED(hr))
-                {
-                    _ASSERTE(ppProcess == NULL || *ppProcess == NULL);
-                    _ASSERTE(pFlags == NULL || *pFlags == 0);
-                }
-            }
-#ifdef FEATURE_PAL
-            else
-            {
-                // On Linux/MacOS the DAC module handle needs to be re-created using the DAC PAL instance
-                // before being passed to DBI's OpenVirtualProcess* implementation. The DBI and DAC share 
-                // the same PAL where dbgshim has it's own.
-                LoadLibraryWFnPtr loadLibraryWFn = (LoadLibraryWFnPtr)GetProcAddress(hDac, "LoadLibraryW");
-                if (loadLibraryWFn != NULL)
-                {
-                    hDac = loadLibraryWFn(pDacModulePath);
-                    if (hDac == NULL)
-                    {
-                        hr = E_HANDLE;
-                    }
-                }
-                else
-                {
-                    hr = E_HANDLE;
-                }
-            }
-#endif // FEATURE_PAL
-        }
-
-        // If no errors so far and "OpenVirtualProcessImpl2" doesn't exist
-        if (SUCCEEDED(hr) && *ppProcess == NULL)
-        {
-            // Get access to OVP and call it
-            OpenVirtualProcessImplFnPtr ovpFn = (OpenVirtualProcessImplFnPtr)GetProcAddress(hDbi, "OpenVirtualProcessImpl");
-            if (ovpFn == NULL)
-            {
-                // Fallback to CLR v4 Beta1 path, but skip some of the checking we'd normally do (maxSupportedVersion, etc.)
-                OpenVirtualProcess2FnPtr ovp2Fn = (OpenVirtualProcess2FnPtr)GetProcAddress(hDbi, "OpenVirtualProcess2");
-                if (ovp2Fn == NULL)
-                {
-                    hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
-                }
-                else
-                {
-                    hr = ovp2Fn(moduleBaseAddress, pDataTarget, hDac, riidProcess, ppProcess, pFlags);
-                }
-            }
-            else
-            {
-                // Have a CLR v4 Beta2+ DBI, call it and let it do the version check
-                hr = ovpFn(moduleBaseAddress, pDataTarget, hDac, pMaxDebuggerSupportedVersion, riidProcess, ppProcess, pFlags);
-                if (FAILED(hr))
-                {
-                    _ASSERTE(ppProcess == NULL || *ppProcess == NULL);
-                    _ASSERTE(pFlags == NULL || *pFlags == 0);
-                }
-            }
-        }
-    }
-
-    //version is still valid in some failure cases
-    if (pVersion != NULL &&
-        (SUCCEEDED(hr) ||
-        (hr == CORDBG_E_UNSUPPORTED_DEBUGGING_MODEL) ||
-            (hr == CORDBG_E_UNSUPPORTED_FORWARD_COMPAT)))
-    {
-        memcpy(pVersion, &version, sizeof(CLR_DEBUGGING_VERSION));
-    }
-
-    if (pDacModulePath != NULL)
-    {
-#ifdef FEATURE_PAL
-        free(pDacModulePath);
-#else
-        CoTaskMemFree(pDacModulePath);
-#endif
-    }
-
-    if (pDbiModulePath != NULL)
-    {
-#ifdef FEATURE_PAL
-        free(pDbiModulePath);
-#else
-        CoTaskMemFree(pDbiModulePath);
-#endif
-    }
-
-    // free the data target we QI'ed earlier
-    if (pDt != NULL)
-    {
-        pDt->Release();
-    }
-
-    return hr;
-}
-
-// Checks to see if this DAC is one of a known set of old DAC builds which contains an issue.
-// If so we retarget to a newer compatible version which has the bug fixed. This is done
-// by changing the PE information used to lookup the DAC.
-//
-// Arguments
-//   pdwTimeStamp - on input, the timestamp of DAC as embedded in the CLR image
-//                  on output, a potentially new timestamp for an updated DAC to use
-//                  instead
-//   pdwSizeOfImage - on input, the sizeOfImage of DAC as embedded in the CLR image
-//                  on output, a potentially new sizeOfImage for an updated DAC to use
-//                  instead
-VOID CLRDebuggingImpl::RetargetDacIfNeeded(DWORD* pdwTimeStamp,
-                                           DWORD* pdwSizeOfImage)
-{
-    
-    // This code is auto generated by the CreateRetargetTable tool
-    // on 3/4/2011 6:35 PM
-    // and then copy-pasted here.
-    //
-    //
-    //
-    // Retarget the GDR1 amd64 build
-    if( (*pdwTimeStamp == 0x4d536868) && (*pdwSizeOfImage == 0x17b000))
-    {
-        *pdwTimeStamp = 0x4d71a160;
-        *pdwSizeOfImage = 0x17b000;
-    }
-    // Retarget the GDR1 x86 build
-    else if( (*pdwTimeStamp == 0x4d5368f2) && (*pdwSizeOfImage == 0x120000))
-    {
-        *pdwTimeStamp = 0x4d71a14f;
-        *pdwSizeOfImage = 0x120000;
-    }
-    // Retarget the RTM amd64 build
-    else if( (*pdwTimeStamp == 0x4ba21fa7) && (*pdwSizeOfImage == 0x17b000))
-    {
-        *pdwTimeStamp = 0x4d71a13c;
-        *pdwSizeOfImage = 0x17b000;
-    }
-    // Retarget the RTM x86 build
-    else if( (*pdwTimeStamp == 0x4ba1da25) && (*pdwSizeOfImage == 0x120000))
-    {
-        *pdwTimeStamp = 0x4d71a128;
-        *pdwSizeOfImage = 0x120000;
-    }
-    // This code is auto generated by the CreateRetargetTable tool
-    // on 8/17/2011 1:28 AM
-    // and then copy-pasted here.
-    //
-    //
-    //
-    // Retarget the GDR2 amd64 build
-    else if( (*pdwTimeStamp == 0x4da428c7) && (*pdwSizeOfImage == 0x17b000))
-    {
-        *pdwTimeStamp = 0x4e4b7bc2;
-        *pdwSizeOfImage = 0x17b000;
-    }
-    // Retarget the GDR2 x86 build
-    else if( (*pdwTimeStamp == 0x4da3fe52) && (*pdwSizeOfImage == 0x120000))
-    {
-        *pdwTimeStamp = 0x4e4b7bb1;
-        *pdwSizeOfImage = 0x120000;
-    }
-    // End auto-generated code
-}
-
-#define PE_FIXEDFILEINFO_SIGNATURE 0xFEEF04BD
-
-// The format of the special debugging resource we embed in CLRs starting in
-// v4
-struct CLR_DEBUG_RESOURCE
-{
-    DWORD dwVersion;
-    GUID signature;
-    DWORD dwDacTimeStamp;
-    DWORD dwDacSizeOfImage;
-    DWORD dwDbiTimeStamp;
-    DWORD dwDbiSizeOfImage;
-};
-
-// Checks to see if a module is a CLR and if so, fetches the debug data
-// from the embedded resource
-//
-// Arguments
-//   pDataTarget - dataTarget for the process we are inspecting
-//   moduleBaseAddress - base address of a module we should inspect
-//   pVersion - output, the version of the CLR detected if this is a CLR
-//   pdwDbiTimeStamp - the timestamp of DBI as embedded in the CLR image
-//   pdwDbiSizeOfImage - the SizeOfImage of DBI as embedded in the CLR image
-//   pDbiName - output, the filename of DBI (as calculated by this function but that might change)
-//   dwDbiNameCharCount - input, the number of WCHARs in the buffer pointed to by pDbiName
-//   pdwDacTimeStampe - the timestamp of DAC as embedded in the CLR image
-//   pdwDacSizeOfImage - the SizeOfImage of DAC as embedded in the CLR image
-//   pDacName - output, the filename of DAC (as calculated by this function but that might change)
-//   dwDacNameCharCount - input, the number of WCHARs in the buffer pointed to by pDacName
-HRESULT CLRDebuggingImpl::GetCLRInfo(ICorDebugDataTarget* pDataTarget,
-                                     ULONG64 moduleBaseAddress,
-                                     CLR_DEBUGGING_VERSION* pVersion,
-                                     DWORD* pdwDbiTimeStamp,
-                                     DWORD* pdwDbiSizeOfImage,
-                                     __out_z __inout_ecount(dwDbiNameCharCount) WCHAR* pDbiName,
-                                     DWORD  dwDbiNameCharCount,
-                                     DWORD* pdwDacTimeStamp,
-                                     DWORD* pdwDacSizeOfImage,
-                                     __out_z __inout_ecount(dwDacNameCharCount) WCHAR* pDacName,
-                                     DWORD  dwDacNameCharCount)
-{
-#ifndef FEATURE_PAL
-    if (m_isWindowsTarget)
-    {
-        WORD imageFileMachine = 0;
-        DWORD resourceSectionRVA = 0;
-        HRESULT hr = GetMachineAndResourceSectionRVA(pDataTarget, moduleBaseAddress, &imageFileMachine, &resourceSectionRVA);
-
-        // We want the version resource which has type = RT_VERSION = 16, name = 1, language = 0x409
-        DWORD versionResourceRVA = 0;
-        DWORD versionResourceSize = 0;
-        if(SUCCEEDED(hr))
-        {
-            hr = GetResourceRvaFromResourceSectionRva(pDataTarget, moduleBaseAddress, resourceSectionRVA, 16, 1, 0x409,
-                     &versionResourceRVA, &versionResourceSize);
-        }
-
-        // At last we get our version info
-        VS_FIXEDFILEINFO fixedFileInfo = {0};
-        if(SUCCEEDED(hr))
-        {
-            // The version resource has 3 words, then the unicode string "VS_VERSION_INFO"
-            // (16 WCHARS including the null terminator) 
-            // then padding to a 32-bit boundary, then the VS_FIXEDFILEINFO struct
-            DWORD fixedFileInfoRVA = ((versionResourceRVA + 3*2 + 16*2 + 3)/4)*4;
-            hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + fixedFileInfoRVA, (BYTE*)&fixedFileInfo, sizeof(fixedFileInfo));
-        }
-
-        //Verify the signature on the version resource
-        if(SUCCEEDED(hr) && fixedFileInfo.dwSignature != PE_FIXEDFILEINFO_SIGNATURE)
-        {
-            hr = CORDBG_E_NOT_CLR;
-        }
-
-        // Record the version information
-        if(SUCCEEDED(hr))
-        {
-            pVersion->wMajor = (WORD) (fixedFileInfo.dwProductVersionMS >> 16);
-            pVersion->wMinor = (WORD) (fixedFileInfo.dwProductVersionMS & 0xFFFF);
-            pVersion->wBuild = (WORD) (fixedFileInfo.dwProductVersionLS >> 16);
-            pVersion->wRevision = (WORD) (fixedFileInfo.dwProductVersionLS & 0xFFFF);
-        }
-
-        // Now grab the special clr debug info resource
-        // We may need to scan a few different names searching though...
-        // 1) CLRDEBUGINFO<host_os><host_arch> where host_os = 'WINDOWS' or 'CORESYS' and host_arch = 'X86' or 'ARM' or 'AMD64'
-        // 2) For back-compat if the host os is windows and the host architecture matches the target then CLRDEBUGINFO is used with no suffix.
-        DWORD debugResourceRVA = 0;
-        DWORD debugResourceSize = 0;
-        BOOL useCrossPlatformNaming = FALSE;
-        if(SUCCEEDED(hr))
-        {
-            // the initial state is that we haven't found a proper resource
-            HRESULT hrGetResource = E_FAIL; 
-     
-            // First check for the resource which has type = RC_DATA = 10, name = "CLRDEBUGINFO<host_os><host_arch>", language = 0        
-    #if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_X86_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSX86");
-    #endif
-
-    #if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_X86_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSX86");
-    #endif
-
-    #if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_AMD64_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSAMD64");
-    #endif
-
-    #if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_AMD64_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSAMD64");
-    #endif
-
-    #if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_ARM64_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSARM64");
-    #endif
-
-    #if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_ARM64_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSARM64");
-    #endif
-
-    #if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_MIPS64_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSMIPS64");
-    #endif
-
-    #if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_ARM_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSARM");
-    #endif
-
-    #if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_ARM_)
-            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSARM");
-    #endif        
-
-            hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, resourceName, 0,
-                     &debugResourceRVA, &debugResourceSize);
-            useCrossPlatformNaming = SUCCEEDED(hrGetResource);        
-
-        
-    #if defined(HOST_IS_WINDOWS_OS) && (defined(_HOST_X86_) || defined(_HOST_AMD64_) || defined(_HOST_ARM_))
-      #if defined(_HOST_X86_)
-        #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_I386
-      #elif defined(_HOST_AMD64_)
-        #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64
-      #elif defined(_HOST_ARM_)
-        #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_ARMNT
-      #endif
-
-            // if this is windows, and if host_arch matches target arch then we can fallback to searching for CLRDEBUGINFO on failure
-            if(FAILED(hrGetResource) && (imageFileMachine == _HOST_MACHINE_TYPE))
-            {
-                hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, W("CLRDEBUGINFO"), 0,
-                     &debugResourceRVA, &debugResourceSize);
-            }
-
-      #undef _HOST_MACHINE_TYPE
-    #endif
-            // if the search failed, we don't recognize the CLR
-            if(FAILED(hrGetResource))
-                hr = CORDBG_E_NOT_CLR;
-        }
-
-        CLR_DEBUG_RESOURCE debugResource;
-        if(SUCCEEDED(hr) && debugResourceSize != sizeof(debugResource))
-        {
-            hr = CORDBG_E_NOT_CLR;
-        }
-
-        // Get the special debug resource from the image and return the results
-        if(SUCCEEDED(hr))
-        {
-            hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + debugResourceRVA, (BYTE*)&debugResource, sizeof(debugResource));
-        }
-        if(SUCCEEDED(hr) && (debugResource.dwVersion != 0))
-        {
-            hr = CORDBG_E_NOT_CLR;
-        }
-    
-        // The signature needs to match m_skuId exactly, except for m_skuId=CLR_ID_ONECORE_CLR which is
-        // also compatible with the older CLR_ID_PHONE_CLR signature.
-        if(SUCCEEDED(hr) && 
-           (debugResource.signature != m_skuId) && 
-           !( (debugResource.signature == CLR_ID_PHONE_CLR) && (m_skuId == CLR_ID_ONECORE_CLR) ))
-        {
-            hr = CORDBG_E_NOT_CLR;
-        }
-
-        if(SUCCEEDED(hr) &&
-           (debugResource.signature != CLR_ID_ONECORE_CLR) &&
-           useCrossPlatformNaming)
-        {
-            FormatLongDacModuleName(pDacName, dwDacNameCharCount, imageFileMachine, &fixedFileInfo);
-            swprintf_s(pDbiName, dwDbiNameCharCount, W("%s_%s.dll"), MAIN_DBI_MODULE_NAME_W, W("x86"));
-        }
-        else
-        {
-            if(m_skuId == CLR_ID_V4_DESKTOP)
-                swprintf_s(pDacName, dwDacNameCharCount, W("%s.dll"), CLR_DAC_MODULE_NAME_W);
-            else
-                swprintf_s(pDacName, dwDacNameCharCount, W("%s.dll"), CORECLR_DAC_MODULE_NAME_W);
-            swprintf_s(pDbiName, dwDbiNameCharCount, W("%s.dll"), MAIN_DBI_MODULE_NAME_W);
-        }
-
-        if(SUCCEEDED(hr))
-        {
-            *pdwDbiTimeStamp = debugResource.dwDbiTimeStamp;
-            *pdwDbiSizeOfImage = debugResource.dwDbiSizeOfImage;
-            *pdwDacTimeStamp = debugResource.dwDacTimeStamp;
-            *pdwDacSizeOfImage = debugResource.dwDacSizeOfImage;
-        }
-
-        // any failure should be interpreted as this module not being a CLR
-        if(FAILED(hr))
-        {
-            return CORDBG_E_NOT_CLR;
-        }
-        else
-        {
-            return S_OK;
-        }
-    }
-    else
-#endif // FEATURE_PAL
-    {
-        swprintf_s(pDacName, dwDacNameCharCount, W("%s"), MAKEDLLNAME_W(CORECLR_DAC_MODULE_NAME_W));
-        swprintf_s(pDbiName, dwDbiNameCharCount, W("%s"), MAKEDLLNAME_W(MAIN_DBI_MODULE_NAME_W));
-
-        pVersion->wMajor = 0;
-        pVersion->wMinor = 0;
-        pVersion->wBuild = 0;
-        pVersion->wRevision = 0;
-
-        *pdwDbiTimeStamp = 0;
-        *pdwDbiSizeOfImage = 0;
-        *pdwDacTimeStamp = 0;
-        *pdwDacSizeOfImage = 0;
-
-        return S_OK;
-    }
-}
-
-// Formats the long name for DAC
-HRESULT CLRDebuggingImpl::FormatLongDacModuleName(__out_z __inout_ecount(cchBuffer) WCHAR * pBuffer,
-                                                  DWORD cchBuffer,
-                                                  DWORD targetImageFileMachine,
-                                                  VS_FIXEDFILEINFO * pVersion)
-{
-
-#ifndef HOST_IS_WINDOWS_OS
-    _ASSERTE(!"NYI");
-    return E_NOTIMPL;
-#endif
-
-#if defined(_HOST_X86_)
-    const WCHAR* pHostArch = W("x86");
-#elif defined(_HOST_AMD64_)
-    const WCHAR* pHostArch = W("amd64");
-#elif defined(_HOST_ARM_)
-    const WCHAR* pHostArch = W("arm");
-#elif defined(_HOST_ARM64_)
-    const WCHAR* pHostArch = W("arm64");
-#elif defined(_HOST_MIPS64_)
-    const WCHAR* pHostArch = W("mips64");
-#else
-    _ASSERTE(!"Unknown host arch");
-    return E_NOTIMPL;
-#endif
-
-    const WCHAR* pDacBaseName = NULL;
-    if(m_skuId == CLR_ID_V4_DESKTOP)
-        pDacBaseName = CLR_DAC_MODULE_NAME_W;
-    else if(m_skuId == CLR_ID_CORECLR || m_skuId == CLR_ID_PHONE_CLR || m_skuId == CLR_ID_ONECORE_CLR)
-        pDacBaseName = CORECLR_DAC_MODULE_NAME_W;
-    else
-    {
-        _ASSERTE(!"Unknown SKU id");
-        return E_UNEXPECTED;
-    }
-
-    const WCHAR* pTargetArch = NULL;
-    if(targetImageFileMachine == IMAGE_FILE_MACHINE_I386)
-    {
-        pTargetArch = W("x86");
-    }
-    else if(targetImageFileMachine == IMAGE_FILE_MACHINE_AMD64)
-    {
-        pTargetArch = W("amd64");
-    }
-    else if(targetImageFileMachine == IMAGE_FILE_MACHINE_ARMNT)
-    {
-        pTargetArch = W("arm");
-    }
-    else if(targetImageFileMachine == IMAGE_FILE_MACHINE_ARM64)
-    {
-        pTargetArch = W("arm64");
-    }
-    else if(targetImageFileMachine == IMAGE_FILE_MACHINE_MIPS64)
-    {
-        pTargetArch = W("mips64");
-    }
-    else
-    {
-        _ASSERTE(!"Unknown target image file machine type");
-        return E_INVALIDARG;
-    }
-
-    const WCHAR* pBuildFlavor = W("");
-    if(pVersion->dwFileFlags & VS_FF_DEBUG)
-    {
-        if(pVersion->dwFileFlags & VS_FF_SPECIALBUILD)
-            pBuildFlavor = W(".dbg");
-        else
-            pBuildFlavor = W(".chk");
-    }
-
-    // WARNING: if you change the formatting make sure you recalculate the maximum
-    // possible size string and verify callers pass a big enough buffer. This doesn't
-    // have to be a tight estimate, just make sure its >= the biggest possible DAC name
-    // and it can be calculated statically
-    DWORD minCchBuffer =
-        (DWORD) wcslen(CLR_DAC_MODULE_NAME_W) + (DWORD) wcslen(CORECLR_DAC_MODULE_NAME_W) + // max name
-        10 + // max host arch
-        10 + // max target arch
-        40 + // max version
-        10 + // max build flavor
-        (DWORD) wcslen(W("name_host_target_version.flavor.dll")) + // max intermediate formatting chars
-        1; // null terminator 
-
-    // validate the output buffer is larger than our estimate above
-    _ASSERTE(cchBuffer >= minCchBuffer);
-    if(!(cchBuffer >= minCchBuffer)) return E_INVALIDARG;
-
-    swprintf_s(pBuffer, cchBuffer, W("%s_%s_%s_%u.%u.%u.%02u%s.dll"), 
-        pDacBaseName,
-        pHostArch,
-        pTargetArch,
-        pVersion->dwProductVersionMS >> 16,
-        pVersion->dwProductVersionMS & 0xFFFF,
-        pVersion->dwProductVersionLS >> 16,
-        pVersion->dwProductVersionLS & 0xFFFF,
-        pBuildFlavor);
-    return S_OK;
-}
-
-// An implementation of ICLRDebugging::CanUnloadNow
-//
-// Arguments:
-//   hModule - a handle to a module provided earlier by ProvideLibrary
-//
-// Returns:
-//   S_OK if the library is no longer in use and can be unloaded, S_FALSE otherwise
-//
-STDMETHODIMP CLRDebuggingImpl::CanUnloadNow(HMODULE hModule)
-{
-    // In V4 at least we don't support any unloading.
-    HRESULT hr = S_FALSE;
-
-    return hr;
-}
-
-
-
-STDMETHODIMP CLRDebuggingImpl::QueryInterface(REFIID riid, void **ppvObject)
-{
-    HRESULT hr = S_OK;
-
-    if (riid == __uuidof(IUnknown))
-    {
-        IUnknown *pItf = static_cast<IUnknown *>(this);
-        pItf->AddRef();
-        *ppvObject = pItf;
-    }
-    else if (riid == __uuidof(ICLRDebugging))
-    {
-        ICLRDebugging *pItf = static_cast<ICLRDebugging *>(this);
-        pItf->AddRef();
-        *ppvObject = pItf;
-    }
-    else
-        hr = E_NOINTERFACE;
-
-    return hr;
-}
-
-// Standard AddRef implementation
-ULONG CLRDebuggingImpl::AddRef()
-{
-    return InterlockedIncrement(&m_cRef);
-}
-
-// Standard Release implementation.
-ULONG CLRDebuggingImpl::Release()
-{
-    _ASSERTE(m_cRef > 0);
-
-    ULONG cRef = InterlockedDecrement(&m_cRef);
-
-    if (cRef == 0)
-        delete this; // Relies on virtual dtor to work properly.
-
-    return cRef;
-}
diff --git a/src/SOS/debugshim/debugshim.h b/src/SOS/debugshim/debugshim.h
deleted file mode 100644 (file)
index d762e4a..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-//*****************************************************************************
-// debugshim.h
-// 
-
-//
-//*****************************************************************************
-
-#ifndef _DEBUG_SHIM_
-#define _DEBUG_SHIM_
-
-#include "cor.h"
-#include "cordebug.h"
-#include <wchar.h>
-#include <metahost.h>
-
-#define CORECLR_DAC_MODULE_NAME_W W("mscordaccore")
-#define CLR_DAC_MODULE_NAME_W W("mscordacwks")
-#define MAIN_DBI_MODULE_NAME_W W("mscordbi")
-
-// forward declaration
-struct ICorDebugDataTarget;
-
-// ICLRDebugging implementation.
-class CLRDebuggingImpl : public ICLRDebugging
-{
-
-public:
-    CLRDebuggingImpl(GUID skuId, bool isWindowsTarget) : m_cRef(0), m_skuId(skuId), m_isWindowsTarget(isWindowsTarget)
-    {
-    }
-
-    virtual ~CLRDebuggingImpl() {}
-    
-public:
-    // ICLRDebugging methods:
-    STDMETHOD(OpenVirtualProcess(
-        ULONG64 moduleBaseAddress,
-        IUnknown * pDataTarget,
-        ICLRDebuggingLibraryProvider * pLibraryProvider,
-        CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
-        REFIID riidProcess,
-        IUnknown ** ppProcess,
-        CLR_DEBUGGING_VERSION * pVersion,
-        CLR_DEBUGGING_PROCESS_FLAGS * pFlags));
-    
-    STDMETHOD(CanUnloadNow(HMODULE hModule));
-
-    //IUnknown methods:
-    STDMETHOD(QueryInterface(
-                REFIID riid,
-                void **ppvObject));
-
-    // Standard AddRef implementation
-    STDMETHOD_(ULONG, AddRef());
-
-    // Standard Release implementation.
-    STDMETHOD_(ULONG, Release());
-
-
-
-private:
-    VOID RetargetDacIfNeeded(DWORD* pdwTimeStamp,
-                             DWORD* pdwSizeOfImage);
-
-    HRESULT GetCLRInfo(ICorDebugDataTarget * pDataTarget,
-                       ULONG64 moduleBaseAddress,
-                       CLR_DEBUGGING_VERSION * pVersion,
-                       DWORD * pdwDbiTimeStamp,
-                       DWORD * pdwDbiSizeOfImage,
-                       __out_z __inout_ecount(dwDbiNameCharCount) WCHAR * pDbiName,
-                       DWORD   dwDbiNameCharCount,
-                       DWORD * pdwDacTimeStamp,
-                       DWORD * pdwDacSizeOfImage,
-                       __out_z __inout_ecount(dwDacNameCharCount) WCHAR * pDacName,
-                       DWORD   dwDacNameCharCount);
-
-    HRESULT FormatLongDacModuleName(__out_z __inout_ecount(cchBuffer) WCHAR * pBuffer,
-                                    DWORD cchBuffer,
-                                    DWORD targetImageFileMachine,
-                                    VS_FIXEDFILEINFO * pVersion);
-
-    volatile LONG m_cRef;
-    GUID m_skuId;
-    bool m_isWindowsTarget;
-
-};  // class CLRDebuggingImpl
-
-#endif
diff --git a/src/SOS/debugshim/debugshim.vcxproj b/src/SOS/debugshim/debugshim.vcxproj
deleted file mode 100644 (file)
index 4bd8dba..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Checked|x64">
-      <Configuration>Checked</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="RelWithDebInfo|x64">
-      <Configuration>RelWithDebInfo</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{6A94C5FE-8706-3505-834E-DA16242F3864}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
-    <Keyword>Win32Proj</Keyword>
-    <Platform>x64</Platform>
-    <ProjectName>debugshim</ProjectName>
-    <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v142</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Checked|x64'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup>
-    <_ProjectFileVersion>10.0.20506.1</_ProjectFileVersion>
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ArtifactsObjDir)Windows_NT.x64.Debug\src\SOS\debugshim\Debug\</OutDir>
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">debugshim.dir\Debug\</IntDir>
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">debugshim</TargetName>
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.lib</TargetExt>
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">$(ArtifactsObjDir)Windows_NT.x64.Debug\src\SOS\debugshim\Checked\</OutDir>
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">debugshim.dir\Checked\</IntDir>
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">debugshim</TargetName>
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">.lib</TargetExt>
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ArtifactsObjDir)Windows_NT.x64.Debug\src\SOS\debugshim\Release\</OutDir>
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">debugshim.dir\Release\</IntDir>
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">debugshim</TargetName>
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.lib</TargetExt>
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">$(ArtifactsObjDir)Windows_NT.x64.Debug\src\SOS\debugshim\RelWithDebInfo\</OutDir>
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">debugshim.dir\RelWithDebInfo\</IntDir>
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">debugshim</TargetName>
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">.lib</TargetExt>
-  </PropertyGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <AdditionalOptions>%(AdditionalOptions) /d2Zi+ /Zm200 /ZH:SHA_256 /source-charset:utf-8 /homeparams</AdditionalOptions>
-      <AssemblerListingLocation>Debug/</AssemblerListingLocation>
-      <BufferSecurityCheck>true</BufferSecurityCheck>
-      <CompileAs>CompileAsCpp</CompileAs>
-      <ControlFlowGuard>Guard</ControlFlowGuard>
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <DisableSpecificWarnings>4960;4961;4603;4627;4838;4456;4457;4458;4459;4091</DisableSpecificWarnings>
-      <ExceptionHandling>Async</ExceptionHandling>
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
-      <ForcedIncludeFiles>WarningControl.h</ForcedIncludeFiles>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <MinimalRebuild>false</MinimalRebuild>
-      <MultiProcessorCompilation>true</MultiProcessorCompilation>
-      <OmitDefaultLibName>true</OmitDefaultLibName>
-      <OmitFramePointers>false</OmitFramePointers>
-      <Optimization>Disabled</Optimization>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <RuntimeTypeInfo>false</RuntimeTypeInfo>
-      <StringPooling>true</StringPooling>
-      <StructMemberAlignment>8Bytes</StructMemberAlignment>
-      <SuppressStartupBanner>true</SuppressStartupBanner>
-      <TreatSpecificWarningsAsErrors>4640</TreatSpecificWarningsAsErrors>
-      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <UndefinePreprocessorDefinitions>_MT</UndefinePreprocessorDefinitions>
-      <UseFullPaths>true</UseFullPaths>
-      <WarningLevel>Level3</WarningLevel>
-      <PreprocessorDefinitions>DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ObjectFileName>$(IntDir)</ObjectFileName>
-    </ClCompile>
-    <ResourceCompile>
-      <PreprocessorDefinitions>WIN32;_DEBUG;DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-    </ResourceCompile>
-    <MASM>
-      <PreprocessorDefinitions>DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalOptions>%(AdditionalOptions) /ZH:SHA_256</AdditionalOptions>
-      <IncludePaths>..\..\pal\prebuilt\inc;..\..\inc;%(IncludePaths)</IncludePaths>
-    </MASM>
-    <Midl>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
-      <HeaderFileName>%(Filename).h</HeaderFileName>
-      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
-      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
-      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
-    </Midl>
-    <Lib>
-      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /IGNORE:4221</AdditionalOptions>
-    </Lib>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">
-    <ClCompile>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <AdditionalOptions>%(AdditionalOptions) /d2Zi+ /Zm200 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
-      <AssemblerListingLocation>Checked/</AssemblerListingLocation>
-      <BufferSecurityCheck>true</BufferSecurityCheck>
-      <CompileAs>CompileAsCpp</CompileAs>
-      <ControlFlowGuard>Guard</ControlFlowGuard>
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <DisableSpecificWarnings>4960;4961;4603;4627;4838;4456;4457;4458;4459;4091</DisableSpecificWarnings>
-      <ExceptionHandling>Async</ExceptionHandling>
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
-      <ForcedIncludeFiles>WarningControl.h</ForcedIncludeFiles>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <MinimalRebuild>false</MinimalRebuild>
-      <MultiProcessorCompilation>true</MultiProcessorCompilation>
-      <OmitDefaultLibName>true</OmitDefaultLibName>
-      <OmitFramePointers>false</OmitFramePointers>
-      <Optimization>MinSpace</Optimization>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <RuntimeTypeInfo>false</RuntimeTypeInfo>
-      <StringPooling>true</StringPooling>
-      <StructMemberAlignment>8Bytes</StructMemberAlignment>
-      <SuppressStartupBanner>true</SuppressStartupBanner>
-      <TreatSpecificWarningsAsErrors>4640</TreatSpecificWarningsAsErrors>
-      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <UndefinePreprocessorDefinitions>_MT</UndefinePreprocessorDefinitions>
-      <UseFullPaths>true</UseFullPaths>
-      <WarningLevel>Level3</WarningLevel>
-      <PreprocessorDefinitions>DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR="Checked";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ObjectFileName>$(IntDir)</ObjectFileName>
-    </ClCompile>
-    <ResourceCompile>
-      <PreprocessorDefinitions>WIN32;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR=\"Checked\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-    </ResourceCompile>
-    <MASM>
-      <PreprocessorDefinitions>DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR="Checked";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalOptions>%(AdditionalOptions) /ZH:SHA_256</AdditionalOptions>
-      <IncludePaths>..\..\pal\prebuilt\inc;..\..\inc;%(IncludePaths)</IncludePaths>
-    </MASM>
-    <Midl>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
-      <HeaderFileName>%(Filename).h</HeaderFileName>
-      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
-      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
-      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
-    </Midl>
-    <Lib>
-      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /IGNORE:4221</AdditionalOptions>
-    </Lib>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <AdditionalOptions>%(AdditionalOptions) /d2Zi+ /Zm200 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
-      <AssemblerListingLocation>Release/</AssemblerListingLocation>
-      <BufferSecurityCheck>true</BufferSecurityCheck>
-      <CompileAs>CompileAsCpp</CompileAs>
-      <ControlFlowGuard>Guard</ControlFlowGuard>
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <DisableSpecificWarnings>4960;4961;4603;4627;4838;4456;4457;4458;4459;4091</DisableSpecificWarnings>
-      <ExceptionHandling>Async</ExceptionHandling>
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
-      <ForcedIncludeFiles>WarningControl.h</ForcedIncludeFiles>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <MinimalRebuild>false</MinimalRebuild>
-      <MultiProcessorCompilation>true</MultiProcessorCompilation>
-      <OmitDefaultLibName>true</OmitDefaultLibName>
-      <OmitFramePointers>false</OmitFramePointers>
-      <Optimization>MinSpace</Optimization>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <RuntimeTypeInfo>false</RuntimeTypeInfo>
-      <StringPooling>true</StringPooling>
-      <StructMemberAlignment>8Bytes</StructMemberAlignment>
-      <SuppressStartupBanner>true</SuppressStartupBanner>
-      <TreatSpecificWarningsAsErrors>4640</TreatSpecificWarningsAsErrors>
-      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <UndefinePreprocessorDefinitions>_MT</UndefinePreprocessorDefinitions>
-      <UseFullPaths>true</UseFullPaths>
-      <WarningLevel>Level3</WarningLevel>
-      <WholeProgramOptimization>true</WholeProgramOptimization>
-      <PreprocessorDefinitions>NDEBUG;URTBLDENV_FRIENDLY=Retail;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR="Release";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ObjectFileName>$(IntDir)</ObjectFileName>
-    </ClCompile>
-    <ResourceCompile>
-      <PreprocessorDefinitions>WIN32;NDEBUG;URTBLDENV_FRIENDLY=Retail;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-    </ResourceCompile>
-    <MASM>
-      <PreprocessorDefinitions>NDEBUG;URTBLDENV_FRIENDLY=Retail;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR="Release";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalOptions>%(AdditionalOptions) /ZH:SHA_256</AdditionalOptions>
-      <IncludePaths>..\..\pal\prebuilt\inc;..\..\inc;%(IncludePaths)</IncludePaths>
-    </MASM>
-    <Midl>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
-      <HeaderFileName>%(Filename).h</HeaderFileName>
-      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
-      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
-      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
-    </Midl>
-    <Lib>
-      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /IGNORE:4221</AdditionalOptions>
-      <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
-    </Lib>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">
-    <ClCompile>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <AdditionalOptions>%(AdditionalOptions) /d2Zi+ /Zm200 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
-      <AssemblerListingLocation>RelWithDebInfo/</AssemblerListingLocation>
-      <BufferSecurityCheck>true</BufferSecurityCheck>
-      <CompileAs>CompileAsCpp</CompileAs>
-      <ControlFlowGuard>Guard</ControlFlowGuard>
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <DisableSpecificWarnings>4960;4961;4603;4627;4838;4456;4457;4458;4459;4091</DisableSpecificWarnings>
-      <ExceptionHandling>Async</ExceptionHandling>
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
-      <ForcedIncludeFiles>WarningControl.h</ForcedIncludeFiles>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <MinimalRebuild>false</MinimalRebuild>
-      <MultiProcessorCompilation>true</MultiProcessorCompilation>
-      <OmitDefaultLibName>true</OmitDefaultLibName>
-      <OmitFramePointers>false</OmitFramePointers>
-      <Optimization>MinSpace</Optimization>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <RuntimeTypeInfo>false</RuntimeTypeInfo>
-      <StringPooling>true</StringPooling>
-      <StructMemberAlignment>8Bytes</StructMemberAlignment>
-      <SuppressStartupBanner>true</SuppressStartupBanner>
-      <TreatSpecificWarningsAsErrors>4640</TreatSpecificWarningsAsErrors>
-      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <UndefinePreprocessorDefinitions>_MT</UndefinePreprocessorDefinitions>
-      <UseFullPaths>true</UseFullPaths>
-      <WarningLevel>Level3</WarningLevel>
-      <WholeProgramOptimization>true</WholeProgramOptimization>
-      <PreprocessorDefinitions>NDEBUG;URTBLDENV_FRIENDLY=Retail;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ObjectFileName>$(IntDir)</ObjectFileName>
-    </ClCompile>
-    <ResourceCompile>
-      <PreprocessorDefinitions>WIN32;NDEBUG;URTBLDENV_FRIENDLY=Retail;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-    </ResourceCompile>
-    <MASM>
-      <PreprocessorDefinitions>NDEBUG;URTBLDENV_FRIENDLY=Retail;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;HOST_IS_WINDOWS_OS;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalOptions>%(AdditionalOptions) /ZH:SHA_256</AdditionalOptions>
-      <IncludePaths>..\..\pal\prebuilt\inc;..\..\inc;%(IncludePaths)</IncludePaths>
-    </MASM>
-    <Midl>
-      <AdditionalIncludeDirectories>..\..\pal\prebuilt\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
-      <HeaderFileName>%(Filename).h</HeaderFileName>
-      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
-      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
-      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
-    </Midl>
-    <Lib>
-      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /IGNORE:4221</AdditionalOptions>
-      <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
-    </Lib>
-  </ItemDefinitionGroup>
-  <ItemGroup>
-    <ClCompile Include="debugshim.cpp" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="debugshim.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <Text Include="CMakeLists.txt" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
-  </ImportGroup>
-</Project>
\ No newline at end of file
index b7ab844b067a1d8b87b5fda5804de9d53fd43905..1ffba4df6612a1bdf3a9296d49974b012b2eafa3 100644 (file)
@@ -23,7 +23,6 @@ endif(WIN32 AND NOT CLR_CMAKE_HOST_ARCH_ARM64)
 
 if(CLR_CMAKE_HOST_UNIX)
     add_definitions(-DHOST_UNIX)
-    add_compile_options(-fPIC)
 else(CLR_CMAKE_HOST_UNIX)
     add_definitions(-DHOST_WINDOWS)
 endif(CLR_CMAKE_HOST_UNIX)
index f694d3e5b6d5abb6a98f4263c52967b352e9dca7..757e4ad958e0c9359895ea1e4d0a93fda6394dd1 100644 (file)
@@ -294,7 +294,7 @@ static bool FindDotNetVersion(int majorFilter, int minorFilter, std::string& hos
 static bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable)
 {
     ArrayHolder<char> hostPath = new char[MAX_LONGPATH+1];
-    if (::GetModuleFileName(NULL, hostPath, MAX_LONGPATH) == 0)
+    if (::GetModuleFileNameA(NULL, hostPath, MAX_LONGPATH) == 0)
     {
         return false;
     }
index 84cb0beed9ccad93ba69d6b378541962f23ecc93..2ce81887f365af06bbb1501ba61f1578c0a3d36c 100644 (file)
@@ -10,9 +10,6 @@
  * to the standard code-manager spec.
  */
 
-#ifndef TARGET_UNIX
-#include "utilcode.h"           // For _ASSERTE()
-#endif //!TARGET_UNIX
 #include "gcdump.h"
 
 /*****************************************************************************/
index 1bf3e61011bd390cc922f369a320cccf9ec47c83..868235fc3cfaa1521eb44e77443db8f45e1fc5ed 100644 (file)
@@ -8,9 +8,6 @@
 #ifdef TARGET_X86
 /*****************************************************************************/
 
-#ifndef TARGET_UNIX
-#include "utilcode.h"           // For _ASSERTE()
-#endif //!TARGET_UNIX
 #include "gcdump.h"
 
 
diff --git a/src/dbgshim/CMakeLists.txt b/src/dbgshim/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1625bb2
--- /dev/null
@@ -0,0 +1,77 @@
+add_definitions(-DFEATURE_NO_HOST)
+add_definitions(-DSELF_NO_HOST)
+add_definitions(-D_BLD_CLR)
+
+set(DBGSHIM_SOURCES
+    dbgshim.cpp
+    debugshim.cpp
+)
+
+if(CLR_CMAKE_HOST_WIN32)
+    # Use static crt
+    set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
+    add_definitions(-DFX_VER_INTERNALNAME_STR=dbgshim.dll)
+endif(CLR_CMAKE_HOST_WIN32)
+
+if(CLR_CMAKE_HOST_WIN32)
+    list(APPEND DBGSHIM_SOURCES
+        dbgshim.rc
+    )
+    preprocess_file(${CMAKE_CURRENT_SOURCE_DIR}/dbgshim.ntdef ${CMAKE_CURRENT_BINARY_DIR}/dbgshim.def)
+    list(APPEND DBGSHIM_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dbgshim.def)
+else(CLR_CMAKE_HOST_WIN32)
+    set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/dbgshim_unixexports.src)
+    set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/dbgshim.exports)
+    generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE})
+
+    if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS)
+        # This option is necessary to ensure that the overloaded delete operator defined inside
+        # of the utilcode will be used instead of the standard library delete operator.
+        set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic")
+    endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS)
+
+    set_exports_linker_option(${EXPORTS_FILE})
+
+endif(CLR_CMAKE_HOST_WIN32)
+
+add_library_clr(dbgshim SHARED ${DBGSHIM_SOURCES})
+
+if(CLR_CMAKE_HOST_UNIX)
+    add_custom_target(dbgshim_exports DEPENDS ${EXPORTS_FILE})
+    add_dependencies(dbgshim dbgshim_exports)
+
+    set_property(TARGET dbgshim APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION})
+    set_property(TARGET dbgshim APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE})
+endif(CLR_CMAKE_HOST_UNIX)
+
+set(DBGSHIM_LIBRARIES
+    corguids
+    dbgutil
+    utilcodestaticnohost
+)
+
+if(CLR_CMAKE_HOST_WIN32)
+    list(APPEND DBGSHIM_LIBRARIES
+        kernel32.lib
+        ${STATIC_MT_CRT_LIB}
+        ${STATIC_MT_VCRT_LIB}
+        uuid.lib
+        user32.lib
+        advapi32.lib
+        ole32.lib
+        oleaut32.lib
+        WtsApi32.lib
+        version.lib
+        psapi.lib
+    )
+else()
+    list(APPEND DBGSHIM_LIBRARIES
+        coreclrpal
+        palrt
+    )
+endif(CLR_CMAKE_HOST_WIN32)
+
+target_link_libraries(dbgshim ${DBGSHIM_LIBRARIES})
+
+# add the install targets
+install_clr(TARGETS dbgshim DESTINATIONS . )
diff --git a/src/dbgshim/dbgshim.cpp b/src/dbgshim/dbgshim.cpp
new file mode 100644 (file)
index 0000000..40e4d7d
--- /dev/null
@@ -0,0 +1,2005 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// DbgShim.cpp
+//
+// This contains the APIs for creating a telesto managed-debugging session. These APIs serve to locate an
+// mscordbi.dll for a given telesto dll and then instantiate the ICorDebug object.
+//
+//*****************************************************************************
+
+#include <winwrap.h>
+#include <utilcode.h>
+#include <log.h>
+#include <tlhelp32.h>
+#include <cor.h>
+#include <sstring.h>
+#ifndef TARGET_UNIX
+#include <securityutil.h>
+#endif
+
+#include <ex.h>
+#include <cordebug.h> // for Version nunmbers
+#include <pedecoder.h>
+#include <getproductversionnumber.h>
+#include <dbgenginemetrics.h>
+#include <arrayholder.h>
+
+#ifndef TARGET_UNIX
+#define PSAPI_VERSION 2
+#include <psapi.h>
+#endif
+
+#include "dbgshim.h"
+
+/*
+
+// Here's a High-level overview of the API usage
+
+From the debugger:
+A debugger calls GetStartupNotificationEvent(pid of debuggee) to get an event, which is signalled when
+that process loads a Telesto.  The debugger thus waits on that event, and when it's signalled, it can call
+EnumerateCLRs / CloseCLREnumeration to get an array of Telestos in the target process (including the one
+that was just loaded). It can then call CreateVersionStringFromModule, CreateDebuggingInterfaceFromVersion
+to attach to any or all Telestos of interest.
+
+From the debuggee:
+When a new Telesto spins up, it checks for the startup event (created via GetStartupNotificationEvent), and
+if it exists, it will:
+- signal it
+- wait on the "Continue" event, thus giving a debugger a chance to attach to the telesto
+
+Notes:
+- There is no CreateProcess (Launch) case. All Launching is really an "Early-attach case".
+
+*/
+
+#ifdef HOST_UNIX
+#define INITIALIZE_SHIM { if (PAL_InitializeDLL() != 0) return E_FAIL; }
+#else
+#define INITIALIZE_SHIM
+#endif
+
+// Contract for public APIs. These must be NOTHROW.
+#define PUBLIC_CONTRACT \
+    INITIALIZE_SHIM \
+    CONTRACTL \
+    { \
+        NOTHROW; \
+    } \
+    CONTRACTL_END;
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// CreateProcessForLaunch - a stripped down version of the Windows CreateProcess
+// that can be supported cross-platform.
+//
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+CreateProcessForLaunch(
+    _In_ LPWSTR lpCommandLine,
+    _In_ BOOL bSuspendProcess,
+    _In_ LPVOID lpEnvironment,
+    _In_ LPCWSTR lpCurrentDirectory,
+    _Out_ PDWORD pProcessId,
+    _Out_ HANDLE *pResumeHandle)
+{
+    PUBLIC_CONTRACT;
+
+    PROCESS_INFORMATION processInfo;
+    STARTUPINFOW startupInfo;
+    DWORD dwCreationFlags = 0;
+
+    ZeroMemory(&processInfo, sizeof(processInfo));
+    ZeroMemory(&startupInfo, sizeof(startupInfo));
+
+    startupInfo.cb = sizeof(startupInfo);
+
+    if (bSuspendProcess)
+    {
+        dwCreationFlags = CREATE_SUSPENDED;
+    }
+
+    BOOL result = CreateProcessW(
+        NULL,
+        lpCommandLine,
+        NULL,
+        NULL,
+        FALSE,
+        dwCreationFlags,
+        lpEnvironment,
+        lpCurrentDirectory,
+        &startupInfo,
+        &processInfo);
+
+    if (!result) {
+        *pProcessId = 0;
+        *pResumeHandle = NULL;
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    if (processInfo.hProcess != NULL)
+    {
+        CloseHandle(processInfo.hProcess);
+    }
+
+    *pProcessId = processInfo.dwProcessId;
+    *pResumeHandle = processInfo.hThread;
+
+    return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// ResumeProcess - to be used with the CreateProcessForLaunch resume handle
+//
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+ResumeProcess(
+    _In_ HANDLE hResumeHandle)
+{
+    PUBLIC_CONTRACT;
+    if (ResumeThread(hResumeHandle) == (DWORD)-1)
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+    return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// CloseResumeHandle - to be used with the CreateProcessForLaunch resume handle
+//
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+CloseResumeHandle(
+    _In_ HANDLE hResumeHandle)
+{
+    PUBLIC_CONTRACT;
+    if (!CloseHandle(hResumeHandle))
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+    return S_OK;
+}
+
+#ifdef TARGET_UNIX
+
+static
+void
+RuntimeStartupHandler(
+    char *pszModulePath,
+    HMODULE hModule,
+    PVOID parameter);
+
+#else // TARGET_UNIX
+
+static
+DWORD
+StartupHelperThread(
+    LPVOID p);
+
+static
+HRESULT
+GetContinueStartupEvent(
+    DWORD debuggeePID,
+    LPCWSTR szTelestoFullPath,
+    _Out_ HANDLE *phContinueStartupEvent);
+
+#endif // TARGET_UNIX
+
+// Functions that we'll look for in the loaded Mscordbi module.
+typedef HRESULT (STDAPICALLTYPE *FPCoreCLRCreateCordbObject)(
+    int iDebuggerVersion,
+    DWORD pid,
+    HMODULE hmodTargetCLR,
+    IUnknown **ppCordb);
+
+typedef HRESULT (STDAPICALLTYPE *FPCoreCLRCreateCordbObjectEx)(
+    int iDebuggerVersion,
+    DWORD pid,
+    LPCWSTR lpApplicationGroupId,
+    HMODULE hmodTargetCLR,
+    IUnknown **ppCordb);
+
+HRESULT CreateCoreDbgWithSandboxSupport(
+    HMODULE hCLRModule, HMODULE hDBIModule, DWORD processId, LPCWSTR lpApplicationGroupId, int iDebuggerVersion, IUnknown **ppCordb)
+{
+    FPCoreCLRCreateCordbObjectEx fpCreate =
+        (FPCoreCLRCreateCordbObjectEx)GetProcAddress(hDBIModule, "CoreCLRCreateCordbObjectEx");
+    if (fpCreate == NULL)
+    {
+        return CORDBG_E_INCOMPATIBLE_PROTOCOL;
+    }
+
+    return fpCreate(iDebuggerVersion, processId, lpApplicationGroupId, hCLRModule, ppCordb);
+}
+
+HRESULT CreateCoreDbgWithoutSandboxSupport(
+    HMODULE hCLRModule, HMODULE hDBIModule, DWORD processId, int iDebuggerVersion, IUnknown **ppCordb)
+{
+    FPCoreCLRCreateCordbObject fpCreate =
+        (FPCoreCLRCreateCordbObject)GetProcAddress(hDBIModule, "CoreCLRCreateCordbObject");
+    if (fpCreate == NULL)
+    {
+        return CORDBG_E_INCOMPATIBLE_PROTOCOL;
+    }
+
+    return fpCreate(iDebuggerVersion, processId, hCLRModule, ppCordb);
+}
+
+HRESULT CreateCoreDbg(
+    HMODULE hCLRModule, HMODULE hDBIModule, DWORD processId, LPCWSTR lpApplicationGroupId, int iDebuggerVersion, IUnknown **ppCordb)
+{
+    HRESULT hr = S_OK;
+
+    if (lpApplicationGroupId != NULL)
+    {
+        hr = CreateCoreDbgWithSandboxSupport(hCLRModule, hDBIModule, processId, lpApplicationGroupId, iDebuggerVersion, ppCordb);
+    }
+    else
+    {
+        hr = CreateCoreDbgWithoutSandboxSupport(hCLRModule, hDBIModule, processId, iDebuggerVersion, ppCordb);
+    }
+
+    return hr;
+}
+
+//
+// Helper class for RegisterForRuntimeStartup
+//
+class RuntimeStartupHelper
+{
+    LONG m_ref;
+    DWORD m_processId;
+    PSTARTUP_CALLBACK m_callback;
+    PVOID m_parameter;
+#ifdef TARGET_UNIX
+    PVOID m_unregisterToken;
+    LPWSTR m_applicationGroupId;
+#else
+    bool m_canceled;
+    HANDLE m_startupEvent;
+    DWORD m_threadId;
+    HANDLE m_threadHandle;
+#endif // TARGET_UNIX
+
+public:
+    RuntimeStartupHelper(DWORD dwProcessId, PSTARTUP_CALLBACK pfnCallback, PVOID parameter) :
+        m_ref(1),
+        m_processId(dwProcessId),
+        m_callback(pfnCallback),
+        m_parameter(parameter),
+#ifdef TARGET_UNIX
+        m_unregisterToken(NULL),
+        m_applicationGroupId(NULL)
+#else
+        m_canceled(false),
+        m_startupEvent(NULL),
+        m_threadId(0),
+        m_threadHandle(NULL)
+#endif // TARGET_UNIX
+    {
+    }
+
+    ~RuntimeStartupHelper()
+    {
+#ifdef TARGET_UNIX
+        if (m_applicationGroupId != NULL)
+        {
+            delete m_applicationGroupId;
+        }
+#else // TARGET_UNIX
+        if (m_startupEvent != NULL)
+        {
+            CloseHandle(m_startupEvent);
+        }
+        if (m_threadHandle != NULL)
+        {
+            CloseHandle(m_threadHandle);
+        }
+#endif // TARGET_UNIX
+    }
+
+    LONG AddRef()
+    {
+        LONG ref = InterlockedIncrement(&m_ref);
+        return ref;
+    }
+
+    LONG Release()
+    {
+        LONG ref = InterlockedDecrement(&m_ref);
+        if (ref == 0)
+        {
+            delete this;
+        }
+        return ref;
+    }
+
+#ifdef TARGET_UNIX
+
+    HRESULT Register(LPCWSTR lpApplicationGroupId)
+    {
+        if (lpApplicationGroupId != NULL)
+        {
+            int size = wcslen(lpApplicationGroupId) + 1;
+            m_applicationGroupId = new (nothrow) WCHAR[size];
+            if (m_applicationGroupId == NULL)
+            {
+                return E_OUTOFMEMORY;
+            }
+            wcscpy_s(m_applicationGroupId, size, lpApplicationGroupId);
+        }
+
+        DWORD pe = PAL_RegisterForRuntimeStartup(m_processId, m_applicationGroupId, RuntimeStartupHandler, this, &m_unregisterToken);
+        if (pe != NO_ERROR)
+        {
+            return HRESULT_FROM_WIN32(pe);
+        }
+        return S_OK;
+    }
+
+    void Unregister()
+    {
+        PAL_UnregisterForRuntimeStartup(m_unregisterToken);
+    }
+
+    void InvokeStartupCallback(char *pszModulePath, HMODULE hModule)
+    {
+        IUnknown *pCordb = NULL;
+        HMODULE hMod = NULL;
+        HRESULT hr = S_OK;
+
+        // If either of these are NULL, there was an error from the PAL
+        // callback. GetLastError returns the error code from the PAL.
+        if (pszModulePath == NULL || hModule == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto exit;
+        }
+
+        PAL_CPP_TRY
+        {
+            char dbiPath[MAX_LONGPATH];
+
+            char *pszLast = strrchr(pszModulePath, DIRECTORY_SEPARATOR_CHAR_A);
+            if (pszLast == NULL)
+            {
+                _ASSERT(!"InvokeStartupCallback: can find separator in coreclr path\n");
+                hr = E_INVALIDARG;
+                goto exit;
+            }
+
+            strncpy_s(dbiPath, ARRAY_SIZE(dbiPath), pszModulePath, pszLast - pszModulePath);
+            strcat_s(dbiPath, ARRAY_SIZE(dbiPath), DIRECTORY_SEPARATOR_STR_A MAKEDLLNAME_A("mscordbi"));
+
+            hMod = LoadLibraryA(dbiPath);
+            if (hMod == NULL)
+            {
+                hr = CORDBG_E_DEBUG_COMPONENT_MISSING;
+                goto exit;
+            }
+
+            HRESULT hr = CreateCoreDbg(hModule, hMod, m_processId, m_applicationGroupId, CorDebugVersion_2_0, &pCordb);
+            _ASSERTE((pCordb == NULL) == FAILED(hr));
+            if (FAILED(hr))
+            {
+                goto exit;
+            }
+
+            m_callback(pCordb, m_parameter, S_OK);
+        }
+        PAL_CPP_CATCH_ALL
+        {
+            hr = E_FAIL;
+            goto exit;
+        }
+        PAL_CPP_ENDTRY
+
+    exit:
+        if (FAILED(hr))
+        {
+            _ASSERTE(pCordb == NULL);
+
+            if (hMod != NULL)
+            {
+                FreeLibrary(hMod);
+            }
+
+            // Invoke the callback on error
+            m_callback(NULL, m_parameter, hr);
+        }
+    }
+
+#else // TARGET_UNIX
+
+    HRESULT Register(LPCWSTR lpApplicationGroupId)
+    {
+        HRESULT hr = GetStartupNotificationEvent(m_processId, &m_startupEvent);
+        if (FAILED(hr))
+        {
+            goto exit;
+        }
+
+        // Add a reference for the thread handler
+        AddRef();
+
+        m_threadHandle = CreateThread(
+            NULL,
+            0,
+            ::StartupHelperThread,
+            this,
+            0,
+            &m_threadId);
+
+        if (m_threadHandle == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            Release();
+            goto exit;
+        }
+
+    exit:
+        return hr;
+    }
+
+    bool AreAllHandlesValid(HANDLE *handleArray, DWORD arrayLength)
+    {
+        for (int i = 0; i < (int)arrayLength; i++)
+        {
+            HANDLE h = handleArray[i];
+            if (h == INVALID_HANDLE_VALUE)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    HRESULT InternalEnumerateCLRs(HANDLE** ppHandleArray, _In_reads_(*pdwArrayLength) LPWSTR** ppStringArray, DWORD* pdwArrayLength)
+    {
+        int numTries = 0;
+        HRESULT hr;
+
+        while (numTries < 25)
+        {
+            hr = EnumerateCLRs(m_processId, ppHandleArray, ppStringArray, pdwArrayLength);
+
+            // EnumerateCLRs uses the OS API CreateToolhelp32Snapshot which can return ERROR_BAD_LENGTH or
+            // ERROR_PARTIAL_COPY. If we get either of those, we try wait 1/10th of a second try again (that
+            // is the recommendation of the OS API owners).
+            if ((hr != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) && (hr != HRESULT_FROM_WIN32(ERROR_BAD_LENGTH)))
+            {
+                // Just return any other error or if no handles were found (which means the coreclr module wasn't found yet).
+                if (FAILED(hr) || *ppHandleArray == NULL || *pdwArrayLength <= 0)
+                {
+                    return hr;
+                }
+                // If EnumerateCLRs succeeded but any of the handles are INVALID_HANDLE_VALUE, then sleep and retry
+                // also. This fixes a race condition where dbgshim catches the coreclr module just being loaded but
+                // before g_hContinueStartupEvent has been initialized.
+                if (AreAllHandlesValid(*ppHandleArray, *pdwArrayLength))
+                {
+                    return hr;
+                }
+                // Clean up memory allocated in EnumerateCLRs since this path it succeeded
+                CloseCLREnumeration(*ppHandleArray, *ppStringArray, *pdwArrayLength);
+
+                *ppHandleArray = NULL;
+                *ppStringArray = NULL;
+                *pdwArrayLength = 0;
+            }
+
+            // Sleep and retry enumerating the runtimes
+            Sleep(100);
+            numTries++;
+
+            if (m_canceled)
+            {
+                break;
+            }
+        }
+
+        // Indicate a timeout
+        hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+
+        return hr;
+    }
+
+    void WakeRuntimes(HANDLE *handleArray, DWORD arrayLength)
+    {
+        if (handleArray != NULL)
+        {
+            for (int i = 0; i < (int)arrayLength; i++)
+            {
+                HANDLE h = handleArray[i];
+                if (h != NULL && h != INVALID_HANDLE_VALUE)
+                {
+                    SetEvent(h);
+                }
+            }
+        }
+    }
+
+    void Unregister()
+    {
+        m_canceled = true;
+
+        HANDLE *handleArray = NULL;
+        LPWSTR *stringArray = NULL;
+        DWORD arrayLength = 0;
+
+        // Wake up runtime(s)
+        HRESULT hr = EnumerateCLRs(m_processId, &handleArray, &stringArray, &arrayLength);
+        if (SUCCEEDED(hr))
+        {
+            WakeRuntimes(handleArray, arrayLength);
+            CloseCLREnumeration(handleArray, stringArray, arrayLength);
+        }
+
+        // Wake up worker thread
+        SetEvent(m_startupEvent);
+
+        // Don't need to wake up and wait for the worker thread if called on it
+        if (m_threadId != GetCurrentThreadId())
+        {
+            // Wait for work thread to exit
+            WaitForSingleObject(m_threadHandle, INFINITE);
+        }
+    }
+
+    HRESULT InvokeStartupCallback(bool *pCoreClrExists)
+    {
+        HANDLE *handleArray = NULL;
+        LPWSTR *stringArray = NULL;
+        DWORD arrayLength = 0;
+        HRESULT hr = S_OK;
+
+        PAL_CPP_TRY
+        {
+            IUnknown *pCordb = NULL;
+            WCHAR verStr[MAX_LONGPATH];
+            DWORD verLen;
+
+            *pCoreClrExists = FALSE;
+
+            hr = InternalEnumerateCLRs(&handleArray, &stringArray, &arrayLength);
+            if (FAILED(hr))
+            {
+                goto exit;
+            }
+
+            for (int i = 0; i < (int)arrayLength; i++)
+            {
+                *pCoreClrExists = TRUE;
+
+                hr = CreateVersionStringFromModule(m_processId, stringArray[i], verStr, ARRAY_SIZE(verStr), &verLen);
+                if (FAILED(hr))
+                {
+                    goto exit;
+                }
+
+                hr = CreateDebuggingInterfaceFromVersion(verStr, &pCordb);
+                if (FAILED(hr))
+                {
+                    goto exit;
+                }
+
+                m_callback(pCordb, m_parameter, S_OK);
+
+                // Currently only the first coreclr module in a process is supported
+                break;
+            }
+        }
+        PAL_CPP_CATCH_ALL
+        {
+            hr = E_FAIL;
+            goto exit;
+        }
+        PAL_CPP_ENDTRY
+
+    exit:
+        if (*pCoreClrExists)
+        {
+            // Wake up all the runtimes
+            WakeRuntimes(handleArray, arrayLength);
+        }
+        CloseCLREnumeration(handleArray, stringArray, arrayLength);
+
+        return hr;
+    }
+
+    void StartupHelperThread()
+    {
+        bool coreclrExists = false;
+
+        HRESULT hr = InvokeStartupCallback(&coreclrExists);
+        // The retry logic in InternalEnumerateCLRs failed if ERROR_TIMEOUT was returned.
+        if (SUCCEEDED(hr) || (hr == HRESULT_FROM_WIN32(ERROR_TIMEOUT)))
+        {
+            if (!coreclrExists && !m_canceled)
+            {
+                // Wait until the coreclr runtime (debuggee) starts up
+                if (WaitForSingleObject(m_startupEvent, INFINITE) == WAIT_OBJECT_0)
+                {
+                    if (!m_canceled)
+                    {
+                        hr = InvokeStartupCallback(&coreclrExists);
+                        if (SUCCEEDED(hr))
+                        {
+                            // We should always find a coreclr module so fail if we don't
+                            if (!coreclrExists)
+                            {
+                                hr = E_FAIL;
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                }
+            }
+        }
+
+        if (FAILED(hr) && !m_canceled)
+        {
+            m_callback(NULL, m_parameter, hr);
+        }
+    }
+
+#endif // TARGET_UNIX
+};
+
+#ifdef TARGET_UNIX
+
+static
+void
+RuntimeStartupHandler(char *pszModulePath, HMODULE hModule, PVOID parameter)
+{
+    RuntimeStartupHelper *helper = (RuntimeStartupHelper *)parameter;
+    helper->InvokeStartupCallback(pszModulePath, hModule);
+}
+
+#else // TARGET_UNIX
+
+static
+DWORD
+StartupHelperThread(LPVOID p)
+{
+    RuntimeStartupHelper *helper = (RuntimeStartupHelper *)p;
+    helper->StartupHelperThread();
+    helper->Release();
+    return 0;
+}
+
+#endif // TARGET_UNIX
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// RegisterForRuntimeStartup -- Refer to RegisterForRuntimeStartupEx.
+//      This method calls RegisterForRuntimeStartupEx with null application group ID value
+//
+// dwProcessId -- process id of the target process
+// pfnCallback -- invoked when coreclr runtime starts
+// parameter -- data to pass to callback
+// ppUnregisterToken -- pointer to put the UnregisterForRuntimeStartup token.
+//
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+RegisterForRuntimeStartup(
+    _In_ DWORD dwProcessId,
+    _In_ PSTARTUP_CALLBACK pfnCallback,
+    _In_ PVOID parameter,
+    _Out_ PVOID *ppUnregisterToken)
+{
+    return RegisterForRuntimeStartupEx(dwProcessId, NULL, pfnCallback, parameter, ppUnregisterToken);
+}
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// RegisterForRuntimeStartupEx -- executes the callback when the coreclr runtime
+//      starts in the specified process. The callback is passed the proper ICorDebug
+//      instance for the version of the runtime or an error if something fails. This
+//      API works for launch and attach (and even the attach scenario if the runtime
+//      hasn't been loaded yet) equally on both xplat and Windows. The callback is
+//      always called on a separate thread. This API returns immediately.
+//
+//      The callback is invoked when the coreclr runtime module is loaded during early
+//      initialization. The runtime is blocked during initialization until the callback
+//      returns.
+//
+//      If the runtime is already loaded in the process (as in the normal attach case),
+//      the callback is executed and the runtime is not blocked.
+//
+//      The callback is always invoked on a separate thread and this API returns immediately.
+//
+//      Only the first coreclr module instance found in the target process is currently
+//      supported.
+//
+// dwProcessId -- process id of the target process
+// lpApplicationGroupId - A string representing the application group ID of a sandboxed
+//                        process running in Mac. Pass NULL if the process is not
+//                        running in a sandbox and other platforms.
+// pfnCallback -- invoked when coreclr runtime starts
+// parameter -- data to pass to callback
+// ppUnregisterToken -- pointer to put the UnregisterForRuntimeStartup token.
+//
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+RegisterForRuntimeStartupEx(
+    _In_ DWORD dwProcessId,
+    _In_ LPCWSTR lpApplicationGroupId,
+    _In_ PSTARTUP_CALLBACK pfnCallback,
+    _In_ PVOID parameter,
+    _Out_ PVOID *ppUnregisterToken)
+{
+    PUBLIC_CONTRACT;
+
+    if (pfnCallback == NULL || ppUnregisterToken == NULL)
+    {
+        return E_INVALIDARG;
+    }
+
+    HRESULT hr = S_OK;
+
+    RuntimeStartupHelper *helper = new (nothrow) RuntimeStartupHelper(dwProcessId, pfnCallback, parameter);
+    if (helper == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+    }
+    else
+    {
+        hr = helper->Register(lpApplicationGroupId);
+        if (FAILED(hr))
+        {
+            helper->Release();
+            helper = NULL;
+        }
+    }
+
+    *ppUnregisterToken = helper;
+    return hr;
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// UnregisterForRuntimeStartup -- stops/cancels runtime startup notification. Needs
+//      to be called during the debugger's shutdown to cleanup the internal data.
+//
+//    This API can be called in the startup callback. Otherwise, it will block until
+//    the callback thread finishes and no more callbacks will be initiated after this
+//    API returns.
+//
+// pUnregisterToken -- unregister token from RegisterForRuntimeStartup or NULL.
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+UnregisterForRuntimeStartup(
+    _In_ PVOID pUnregisterToken)
+{
+    PUBLIC_CONTRACT;
+
+    if (pUnregisterToken != NULL)
+    {
+        RuntimeStartupHelper *helper = (RuntimeStartupHelper *)pUnregisterToken;
+        helper->Unregister();
+        helper->Release();
+    }
+
+    return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// GetStartupNotificationEvent -- creates a global, named event that is PID-
+//      qualified (i.e. process global) that is used to notify the debugger of
+//      any CLR instance startup in the process.
+//
+// debuggeePID -- process ID of the target process
+// phStartupEvent -- out param for the returned event handle
+//
+//-----------------------------------------------------------------------------
+#define StartupNotifyEventNamePrefix W("TelestoStartupEvent_")
+#define SessionIdPrefix W("Session\\")
+
+// NULL terminator is included in sizeof(StartupNotifyEventNamePrefix)
+const int cchEventNameBufferSize = (sizeof(StartupNotifyEventNamePrefix) + sizeof(SessionIdPrefix)) / sizeof(WCHAR)
+                                    + 8  // + hex process id DWORD
+                                    + 10 // + decimal session id DWORD
+                                    + 1;  // '\' after session id
+
+DLLEXPORT
+HRESULT
+GetStartupNotificationEvent(
+    _In_ DWORD debuggeePID,
+    _Out_ HANDLE* phStartupEvent)
+{
+    PUBLIC_CONTRACT;
+
+    if (phStartupEvent == NULL)
+        return E_INVALIDARG;
+
+#ifndef TARGET_UNIX
+    HRESULT hr;
+    DWORD currentSessionId = 0, debuggeeSessionId = 0;
+    if (!ProcessIdToSessionId(GetCurrentProcessId(), &currentSessionId))
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    if (!ProcessIdToSessionId(debuggeePID, &debuggeeSessionId))
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    // Here we could just add "Global\" to the event name and this would solve cross-session debugging scenario, but that would require event name change
+    // in CoreCLR, and break backward compatibility. Instead if we see that debugee is in a different session, we explicitly create startup event
+    // in that session (by adding "Session\#\"). We could do it even for our own session, but that's vaguely documented behavior and we'd
+    // like to use it as little as possible.
+    WCHAR szEventName[cchEventNameBufferSize];
+    if (currentSessionId == debuggeeSessionId)
+    {
+        swprintf_s(szEventName, cchEventNameBufferSize, StartupNotifyEventNamePrefix W("%08x"), debuggeePID);
+    }
+    else
+    {
+        swprintf_s(szEventName, cchEventNameBufferSize, SessionIdPrefix W("%u\\") StartupNotifyEventNamePrefix W("%08x"), debuggeeSessionId, debuggeePID);
+    }
+
+    // Determine an appropriate ACL and SECURITY_ATTRIBUTES to apply to this event.  We use the same logic
+    // here as the debugger uses for other events (like the setup-sync-event).  Specifically, this does
+    // the work to ensure a debuggee running as another user, or with a low integrity level can signal
+    // this event.
+    PACL pACL = NULL;
+    SECURITY_ATTRIBUTES * pSA = NULL;
+    IfFailRet(SecurityUtil::GetACLOfPid(debuggeePID, &pACL));
+    SecurityUtil secUtil(pACL);
+
+    HandleHolder hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, debuggeePID);
+    if (hProcess == NULL)
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    IfFailRet(secUtil.Init(hProcess));
+    IfFailRet(secUtil.GetSA(&pSA));
+
+    HANDLE startupEvent = WszCreateEvent(pSA,
+                                FALSE,  // false -> auto-reset
+                                FALSE,  // false -> initially non-signaled
+                                szEventName);
+    DWORD dwStatus = GetLastError();
+    if (NULL == startupEvent)
+    {
+        // if the event already exists, try to open it, otherwise we fail.
+
+        if (ERROR_ALREADY_EXISTS != dwStatus)
+            return E_FAIL;
+
+        startupEvent = WszOpenEvent(SYNCHRONIZE, FALSE, szEventName);
+
+        if (NULL == startupEvent)
+            return E_FAIL;
+    }
+
+    *phStartupEvent = startupEvent;
+    return S_OK;
+#else
+    *phStartupEvent = NULL;
+    return E_NOTIMPL;
+#endif // TARGET_UNIX
+}
+// Refer to clr\src\mscoree\mscorwks_ntdef.src.
+const WORD kOrdinalForMetrics = 2;
+
+//-----------------------------------------------------------------------------
+// The CLR_ENGINE_METRICS is a static struct in coreclr.dll.  It's exported by coreclr.dll at ordinal 2 in
+// the export address table.  This function returns the CLR_ENGINE_METRICS and the RVA to the continue
+// startup event for a coreclr.dll specified by its full path.
+//
+// Arguments:
+//   szTelestoFullPath - (in) full path of telesto
+//   pEngineMetricsOut - (out) filled in based on metrics from target telesto.
+//   pdwRVAContinueStartupEvent - (out; optional) return the RVA to the continue startup event
+//
+// Returns:
+//   Throwss on error.
+//
+// Notes:
+//     When VS pops up the attach dialog box, it is actually enumerating all the processes on the machine
+//     (if the appropiate checkbox is checked) and checking each process to see if a DLL named "coreclr.dll"
+//     is loaded.  If there is one, we will go down this code path, but there is no guarantee that the
+//     coreclr.dll is ours.  A malicious user can be running a process with a bogus coreclr.dll loaded.
+//     That's why we need to be extra careful reading coreclr.dll in this function.
+//-----------------------------------------------------------------------------
+static
+void
+GetTargetCLRMetrics(
+    LPCWSTR szTelestoFullPath,
+    CLR_ENGINE_METRICS *pEngineMetricsOut,
+    DWORD *pdwRVAContinueStartupEvent = NULL)
+{
+    CONTRACTL
+    {
+        THROWS;
+    }
+    CONTRACTL_END;
+
+    CONSISTENCY_CHECK(szTelestoFullPath != NULL);
+    CONSISTENCY_CHECK(pEngineMetricsOut != NULL);
+
+#ifndef TARGET_UNIX
+    HRESULT hr = S_OK;
+
+    HandleHolder hCoreClrFile = WszCreateFile(szTelestoFullPath,
+                                              GENERIC_READ,
+                                              FILE_SHARE_READ,
+                                              NULL,                 // default security descriptor
+                                              OPEN_EXISTING,
+                                              FILE_ATTRIBUTE_NORMAL,
+                                              NULL);
+    if (hCoreClrFile == INVALID_HANDLE_VALUE)
+    {
+        ThrowLastError();
+    }
+
+    DWORD cbFileHigh = 0;
+    DWORD cbFileLow = GetFileSize(hCoreClrFile, &cbFileHigh);
+    if (cbFileLow == INVALID_FILE_SIZE)
+    {
+        ThrowLastError();
+    }
+
+    // A maximum size of 100 MB should be more than enough for coreclr.dll.
+    if ((cbFileHigh != 0) || (cbFileLow > 0x6400000) || (cbFileLow == 0))
+    {
+        ThrowHR(E_FAIL);
+    }
+
+    HandleHolder hCoreClrMap = WszCreateFileMapping(hCoreClrFile, NULL, PAGE_READONLY, cbFileHigh, cbFileLow, NULL);
+    if (hCoreClrMap == NULL)
+    {
+        ThrowLastError();
+    }
+
+    MapViewHolder hCoreClrMapView = MapViewOfFile(hCoreClrMap, FILE_MAP_READ, 0, 0, 0);
+    if (hCoreClrMapView == NULL)
+    {
+        ThrowLastError();
+    }
+
+    // At this point we have read the file into the process, but be careful because it is flat, i.e. not mapped.
+    // We need to translate RVAs into file offsets, but fortunately PEDecoder can do all of that for us.
+    PEDecoder pedecoder(hCoreClrMapView, (COUNT_T)cbFileLow);
+
+    // Check the NT headers.
+    if (!pedecoder.CheckNTFormat())
+    {
+        ThrowHR(E_FAIL);
+    }
+
+    // At this point we can safely read anything in the NT headers.
+
+    if (!pedecoder.HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_EXPORT) ||
+        !pedecoder.CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_EXPORT))
+    {
+        ThrowHR(E_FAIL);
+    }
+    IMAGE_DATA_DIRECTORY * pExportDirectoryEntry = pedecoder.GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_EXPORT);
+
+    // At this point we can safely read the IMAGE_DATA_DIRECTORY of the export directory.
+
+    if (!pedecoder.CheckDirectory(pExportDirectoryEntry))
+    {
+        ThrowHR(E_FAIL);
+    }
+    IMAGE_EXPORT_DIRECTORY * pExportDir =
+        reinterpret_cast<IMAGE_EXPORT_DIRECTORY *>(pedecoder.GetDirectoryData(pExportDirectoryEntry));
+
+    // At this point we have checked that everything in the export directory is readable.
+
+    // Check to make sure the ordinal we have fits in the table in the export directory.
+    // The "base" here is like the starting index of the arrays in the export directory.
+    if ((pExportDir->Base > kOrdinalForMetrics) ||
+        (pExportDir->NumberOfFunctions < (kOrdinalForMetrics - pExportDir->Base)))
+    {
+        ThrowHR(E_FAIL);
+    }
+    DWORD dwRealIndex = kOrdinalForMetrics - pExportDir->Base;
+
+    // Check that we can read the RVA at the element (specified by the ordinal) in the export address table.
+    // Then read the RVA to the CLR_ENGINE_METRICS.
+    if (!pedecoder.CheckRva(pExportDir->AddressOfFunctions, (dwRealIndex + 1) * sizeof(DWORD)))
+    {
+        ThrowHR(E_FAIL);
+    }
+    DWORD rvaMetrics = *reinterpret_cast<DWORD *>(
+        pedecoder.GetRvaData(pExportDir->AddressOfFunctions + dwRealIndex * sizeof(DWORD)));
+
+    // Make sure we can safely read the CLR_ENGINE_METRICS at the RVA we have retrieved.
+    if (!pedecoder.CheckRva(rvaMetrics, sizeof(*pEngineMetricsOut)))
+    {
+        ThrowHR(E_FAIL);
+    }
+
+    // Finally, copy the CLR_ENGINE_METRICS into the output buffer.
+    CLR_ENGINE_METRICS * pMetricsInFile = reinterpret_cast<CLR_ENGINE_METRICS *>(pedecoder.GetRvaData(rvaMetrics));
+    *pEngineMetricsOut = *pMetricsInFile;
+
+    // At this point, we have retrieved the CLR_ENGINE_METRICS from the target process and
+    // stored it in output buffer.
+    if (pEngineMetricsOut->cbSize != sizeof(*pEngineMetricsOut))
+    {
+        ThrowHR(E_INVALIDARG);
+    }
+
+    if (pdwRVAContinueStartupEvent != NULL)
+    {
+        // Note that the pointer stored in the CLR_ENGINE_METRICS is assuming that the DLL is loaded at its
+        // preferred base address.  We need to translate that to an RVA.
+        if (((SIZE_T)pEngineMetricsOut->phContinueStartupEvent < (SIZE_T)pedecoder.GetPreferredBase()) ||
+            ((SIZE_T)pEngineMetricsOut->phContinueStartupEvent >
+                ((SIZE_T)pedecoder.GetPreferredBase() + pedecoder.GetVirtualSize())))
+        {
+            ThrowHR(E_FAIL);
+        }
+
+        DWORD rvaContinueStartupEvent =
+            (DWORD)((SIZE_T)pEngineMetricsOut->phContinueStartupEvent - (SIZE_T)pedecoder.GetPreferredBase());
+
+        // We can't use CheckRva() here because for unmapped files it actually checks the RVA against the file
+        // size as well.  We have already checked the RVA above.  Now just check that the entire HANDLE
+        // falls in the loaded image.
+        if ((rvaContinueStartupEvent + sizeof(HANDLE)) > pedecoder.GetVirtualSize())
+        {
+            ThrowHR(E_FAIL);
+        }
+
+        *pdwRVAContinueStartupEvent = rvaContinueStartupEvent;
+    }
+
+    // Holder will call FreeLibrary()
+#else
+    //TODO: So far on POSIX systems we only support one version of debugging interface
+    // in future we might want to detect it the same way we do it on Windows.
+    pEngineMetricsOut->cbSize = sizeof(*pEngineMetricsOut);
+    pEngineMetricsOut->dwDbiVersion = CorDebugLatestVersion;
+    pEngineMetricsOut->phContinueStartupEvent = NULL;
+
+    if (pdwRVAContinueStartupEvent != NULL)
+    {
+        *pdwRVAContinueStartupEvent = NULL;
+    }
+#endif // TARGET_UNIX
+}
+
+// Returns true iff the module represents CoreClr.
+static
+bool
+IsCoreClr(
+    const WCHAR* pModulePath)
+{
+    _ASSERTE(pModulePath != NULL);
+
+    //strip off everything up to and including the last slash in the path to get name
+    const WCHAR* pModuleName = pModulePath;
+    while(wcschr(pModuleName, DIRECTORY_SEPARATOR_CHAR_W) != NULL)
+    {
+        pModuleName = wcschr(pModuleName, DIRECTORY_SEPARATOR_CHAR_W);
+        pModuleName++; // pass the slash
+    }
+
+    // MAIN_CLR_MODULE_NAME_W gets changed for desktop builds, so we directly code against the CoreClr name.
+    return _wcsicmp(pModuleName, MAKEDLLNAME_W(W("coreclr"))) == 0;
+}
+
+// Returns true iff the module sent is named CoreClr.dll and has the metrics expected in it's PE header.
+static
+bool
+IsCoreClrWithGoodHeader(
+    HANDLE hProcess,
+    HMODULE hModule)
+{
+    HRESULT hr = S_OK;
+
+    WCHAR modulePath[MAX_LONGPATH];
+    modulePath[0] = W('\0');
+    if(0 == GetModuleFileNameEx(hProcess, hModule, modulePath, MAX_LONGPATH))
+    {
+        return false;
+    }
+    else
+    {
+        modulePath[MAX_LONGPATH-1] = 0; // on older OS'es this doesn't get null terminated automatically on truncation
+    }
+
+    if (IsCoreClr(modulePath))
+    {
+        // We don't care about the particular error returned, only that
+        // what we tried wasn't a 'real' coreclr.dll.
+        EX_TRY
+        {
+            CLR_ENGINE_METRICS metricsStruct;
+            GetTargetCLRMetrics(modulePath, &metricsStruct); // throws
+
+            // If we got this far, then we think it's a good one.
+        }
+        EX_CATCH_HRESULT(hr);
+        return (hr == S_OK);
+    }
+
+    return false;
+}
+
+static
+HRESULT
+EnumProcessModulesInternal(
+    HANDLE hProcess,
+    DWORD *pCountModules,
+    HMODULE** ppModules)
+{
+    *pCountModules = 0;
+    *ppModules = nullptr;
+
+    // Start with 1024 modules
+    DWORD cbNeeded = sizeof(HMODULE) * 1024;
+
+    ArrayHolder<HMODULE> modules = new (nothrow) HMODULE[cbNeeded / sizeof(HMODULE)];
+    if (modules == nullptr)
+    {
+        return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
+    }
+
+    if(!EnumProcessModules(hProcess, modules, cbNeeded, &cbNeeded))
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    // If 1024 isn't enough, try the modules array size returned (cbNeeded)
+    if (cbNeeded > (sizeof(HMODULE) * 1024))
+    {
+        modules = new (nothrow) HMODULE[cbNeeded / sizeof(HMODULE)];
+        if (modules == nullptr)
+        {
+            return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
+        }
+
+        DWORD cbNeeded2;
+        if(!EnumProcessModules(hProcess, modules, cbNeeded, &cbNeeded2))
+        {
+            return HRESULT_FROM_WIN32(GetLastError());
+        }
+
+        // The only way cbNeeded2 could change on the second call is if number of
+        // modules loaded by the process changed in the small window between the
+        // above EnumProcessModules calls. If this actually happens, then give
+        // up on trying to get the whole module list and risk missing the coreclr
+        // module.
+        cbNeeded = min(cbNeeded, cbNeeded2);
+    }
+
+    *pCountModules = cbNeeded / sizeof(HMODULE);
+    *ppModules = modules.Detach();
+    return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// EnumerateCLRs -- returns an array of full paths to each coreclr.dll in the
+//      target process.  Also returns a corresponding array of continue events
+//      that *MUST* be signaled by the caller in order to allow the CLRs in the
+//      target process to proceed.
+//
+// debuggeePID -- process ID of the target process
+// ppHandleArrayOut -- out parameter in which an array of handles is returned.
+//      the length of this array is returned by the pdwArrayLengthOut out param
+// ppStringArrayOut -- out parameter in which an array of full paths to each
+//      coreclr.dll in the process is returned.  The length of this array is the
+//      same as the handle array and is returned by the pdwArrayLengthOut param
+// pdwArrayLengthOut -- out param in which the length of the two returned arrays
+//      are returned.
+//
+// Notes:
+//   Callers use  code:CloseCLREnumeration to free the returned arrays.
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+EnumerateCLRs(
+    DWORD debuggeePID,
+    _Out_ HANDLE** ppHandleArrayOut,
+    _Out_ LPWSTR** ppStringArrayOut,
+    _Out_ DWORD* pdwArrayLengthOut)
+{
+    PUBLIC_CONTRACT;
+
+    // All out params must be non-NULL.
+    if ((ppHandleArrayOut == NULL) || (ppStringArrayOut == NULL) || (pdwArrayLengthOut == NULL))
+        return E_INVALIDARG;
+
+    HandleHolder hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, debuggeePID);
+    if (NULL == hProcess)
+        return E_FAIL;
+
+    // The modules in the array returned don't need to be closed
+    DWORD countModules;
+    ArrayHolder<HMODULE> modules = nullptr;
+    HRESULT hr = EnumProcessModulesInternal(hProcess, &countModules, &modules);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    //
+    // count the number of coreclr.dll entries
+    //
+    DWORD count = 0;
+    for(DWORD i = 0; i < countModules; i++)
+    {
+        if (IsCoreClrWithGoodHeader(hProcess, modules[i]))
+        {
+            count++;
+        }
+    }
+
+    // If we didn't find anything, no point in continuing.
+    if (count == 0)
+    {
+        *ppHandleArrayOut = NULL;
+        *ppStringArrayOut = NULL;
+        *pdwArrayLengthOut = 0;
+
+        return S_OK;
+    }
+
+    size_t cbEventArrayData     = sizeof(HANDLE) * count;               // event array data
+    size_t cbStringArrayData    = sizeof(LPWSTR) * count;               // string array data
+    size_t cbStringData         = sizeof(WCHAR)  * count * MAX_LONGPATH;    // strings data
+    size_t cbBuffer             = cbEventArrayData + cbStringArrayData + cbStringData;
+
+    BYTE* pOutBuffer = new (nothrow) BYTE[cbBuffer];
+    if (NULL == pOutBuffer)
+        return E_OUTOFMEMORY;
+
+    ZeroMemory(pOutBuffer, cbBuffer);
+
+    HANDLE* pEventArray     = (HANDLE*) &pOutBuffer[0];
+    LPWSTR* pStringArray    = (LPWSTR*) &pOutBuffer[cbEventArrayData];
+    WCHAR*  pStringData     = (WCHAR*)  &pOutBuffer[cbEventArrayData + cbStringArrayData];
+    DWORD idx = 0;
+
+    // There's no guarantee that another coreclr hasn't loaded already anyhow,
+    // so if we get the corner case that the second time through we enumerate
+    // more coreclrs, just ignore the extras.
+    // This mismatch could happen when
+    // a) take module shapshot
+    // b) underlying file is opened for exclusive access/deleted/moved/ACL'd etc so we can't open it
+    // c) count is determined
+    // d) file is closed/copied/moved/ACL'd etc so we can find/open it again
+    // e) this loop runs
+    // Thus the loop checks idx < count
+
+    for(DWORD i = 0; i < countModules && idx < count; i++)
+    {
+        if (IsCoreClrWithGoodHeader(hProcess, modules[i]))
+        {
+            // fill in path
+            pStringArray[idx] = &pStringData[idx * MAX_LONGPATH];
+            GetModuleFileNameEx(hProcess, modules[i], pStringArray[idx], MAX_LONGPATH);
+
+#ifndef TARGET_UNIX
+            // fill in event handle -- if GetContinueStartupEvent fails, it will still return
+            // INVALID_HANDLE_VALUE in hContinueStartupEvent, which is what we want.  we don't
+            // want to bail out of the enumeration altogether if we can't get an event from
+            // one telesto.
+
+            HANDLE hContinueStartupEvent = INVALID_HANDLE_VALUE;
+            HRESULT hr = GetContinueStartupEvent(debuggeePID, pStringArray[idx], &hContinueStartupEvent);
+            pEventArray[idx] = hContinueStartupEvent;
+#else
+            pEventArray[idx] = NULL;
+#endif // TARGET_UNIX
+
+            idx++;
+        }
+    }
+
+    // Patch things up so CloseCLREnumeration() can still have it's
+    // pointer arithmatic checks succeed, and the user doesn't see a 'dead' entry.
+    // Specifically, it's expected that pEventArray and pStringArray point to the
+    // same contiguous chunk of memory so that pStringArray == pEventArray[*pdwArrayLengthOut].
+    // This is expected to be a very rare case.
+    if (idx < count)
+    {
+        // Move the string pointers back.
+        LPWSTR* pSATemp = (LPWSTR*)&pOutBuffer[sizeof(HANDLE)*idx];
+        for (DWORD i = 0; i < idx; i++)
+        {
+            pSATemp[i] = pStringArray[i];
+        }
+
+        // Fix up string array pointer.
+        pStringArray = (LPWSTR*)&pOutBuffer[sizeof(HANDLE)*idx];
+
+        // Strings themselves don't need moved.
+    }
+
+    *ppHandleArrayOut = pEventArray;
+    *ppStringArrayOut = pStringArray;
+    *pdwArrayLengthOut = idx;
+
+    return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// CloseCLREnumeration -- used to free resources allocated by EnumerateCLRs
+//
+// pHandleArray -- handle array originally returned by EnumerateCLRs
+// pStringArray -- string array originally returned by EnumerateCLRs
+// dwArrayLength -- array length originally returned by EnumerateCLRs
+//
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+CloseCLREnumeration(
+    _In_ HANDLE* pHandleArray,
+    _In_ LPWSTR* pStringArray,
+    _In_ DWORD dwArrayLength)
+{
+    PUBLIC_CONTRACT;
+
+    // It's possible that EnumerateCLRs found nothing to enumerate, in which case
+    // pointers and count are zeroed.  If a debugger calls this function in that
+    // case, let's not try to delete [] on NULL.
+    if (pHandleArray == NULL)
+        return S_OK;
+
+    if ((pHandleArray + dwArrayLength) != (HANDLE*)pStringArray)
+        return E_INVALIDARG;
+
+#ifndef TARGET_UNIX
+    for (DWORD i = 0; i < dwArrayLength; i++)
+    {
+        HANDLE hTemp = pHandleArray[i];
+        if (   (NULL != hTemp)
+            && (INVALID_HANDLE_VALUE != hTemp))
+        {
+            CloseHandle(hTemp);
+        }
+    }
+#endif // TARGET_UNIX
+
+    delete[] pHandleArray;
+    return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Get the base address of a module from the remote process.
+//
+// Returns:
+//  - On success, base address (in remote process) of mscoree,
+//  - NULL  if the module is not loaded.
+//  - else Throws. *ppBaseAddress = NULL
+//-----------------------------------------------------------------------------
+static
+BYTE*
+GetRemoteModuleBaseAddress(
+    DWORD dwPID,
+    LPCWSTR szFullModulePath)
+{
+    CONTRACTL
+    {
+        THROWS;
+    }
+    CONTRACTL_END;
+
+    HandleHolder hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
+    if (NULL == hProcess)
+    {
+        ThrowHR(E_FAIL);
+    }
+
+    // The modules in the array returned don't need to be closed
+    DWORD countModules;
+    ArrayHolder<HMODULE> modules = nullptr;
+    HRESULT hr = EnumProcessModulesInternal(hProcess, &countModules, &modules);
+    if (FAILED(hr))
+    {
+        ThrowHR(hr);
+    }
+
+    for(DWORD i = 0; i < countModules; i++)
+    {
+        WCHAR modulePath[MAX_LONGPATH];
+        if(0 == GetModuleFileNameEx(hProcess, modules[i], modulePath, MAX_LONGPATH))
+        {
+            continue;
+        }
+        else
+        {
+            modulePath[MAX_LONGPATH-1] = 0; // on older OS'es this doesn't get null terminated automatically
+            if (_wcsicmp(modulePath, szFullModulePath) == 0)
+            {
+                return (BYTE*) modules[i];
+            }
+        }
+    }
+
+    // Successfully enumerated modules but couldn't find the requested one.
+    return NULL;
+}
+
+// DBI version: max 8 hex chars
+// SEMICOLON: 1
+// PID: max 8 hex chars
+// SEMICOLON: 1
+// HMODULE: max 16 hex chars (64-bit)
+// SEMICOLON: 1
+// PROTOCOL STRING: (variable length)
+const int c_iMaxVersionStringLen = 8 + 1 + 8 + 1 + 16; // 64-bit hmodule
+const int c_iMinVersionStringLen = 8 + 1 + 8 + 1 + 8; // 32-bit hmodule
+const int c_idxFirstSemi = 8;
+const int c_idxSecondSemi = 17;
+const WCHAR *c_versionStrFormat = W("%08x;%08x;%p");
+
+//-----------------------------------------------------------------------------
+// Public API.
+// Given a path to a coreclr.dll, get the Version string.
+//
+// Arguments:
+//   pidDebuggee - OS process ID of debuggee.
+//   szModuleName - a full or relative path to a valid coreclr.dll in the debuggee.
+//   pBuffer - the buffer to fill the version string into
+//     if pdwLength != NULL, we set *pdwLength to the length of the version string on
+//     output (including the null terminator).
+//   cchBuffer - length of pBuffer on input in characters
+//
+// Returns:
+//  S_OK - on success.
+//  E_INVALIDARG -
+//  HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) if the buffer is too small.
+//  COR_E_FILENOTFOUND - module is not found in a given debugee process
+//
+// Notes:
+//   The null-terminated version string including null, is
+//   copied to pVersion on output. Thus *pdwLength == wcslen(pBuffer)+1.
+//   The version string is an opaque string that can only be passed back to other
+//   DbgShim APIs.
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+CreateVersionStringFromModule(
+    _In_ DWORD pidDebuggee,
+    _In_ LPCWSTR szModuleName,
+    _Out_writes_to_opt_(cchBuffer, *pdwLength) LPWSTR pBuffer,
+    _In_ DWORD cchBuffer,
+    _Out_ DWORD* pdwLength)
+{
+    PUBLIC_CONTRACT;
+
+    if (szModuleName == NULL)
+    {
+        return E_INVALIDARG;
+    }
+
+    // it is ok for both to be null (to query the required buffer size) or both to be non-null.
+    if ((pBuffer == NULL) != (cchBuffer == 0))
+    {
+        return E_INVALIDARG;
+    }
+
+    SIZE_T nLengthWithNull = c_iMaxVersionStringLen + 1;
+    _ASSERTE(nLengthWithNull > 0);
+
+    if (pdwLength != NULL)
+    {
+        *pdwLength = (DWORD) nLengthWithNull;
+    }
+
+    if (nLengthWithNull > cchBuffer)
+    {
+        return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+    }
+    else if (pBuffer != NULL)
+    {
+
+        HRESULT hr = S_OK;
+        EX_TRY
+        {
+            CorDebugInterfaceVersion dbiVersion = CorDebugInvalidVersion;
+            BYTE* hmodTargetCLR = NULL;
+            CLR_ENGINE_METRICS metricsStruct;
+
+            GetTargetCLRMetrics(szModuleName, &metricsStruct); // throws
+            dbiVersion = (CorDebugInterfaceVersion) metricsStruct.dwDbiVersion;
+
+            hmodTargetCLR = GetRemoteModuleBaseAddress(pidDebuggee, szModuleName); // throws
+            if (hmodTargetCLR == NULL)
+            {
+                hr = COR_E_FILENOTFOUND;
+            }
+            else
+            {
+                swprintf_s(pBuffer, cchBuffer, c_versionStrFormat, dbiVersion, pidDebuggee, hmodTargetCLR);
+            }
+        }
+        EX_CATCH_HRESULT(hr);
+        return hr;
+    }
+
+    return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Parse a version string into useful data.
+//
+// Arguments:
+//    szDebuggeeVersion - (in) null terminated version string
+//    piDebuggerVersion - (out) interface number that the debugger expects to use.
+//    pdwPidDebuggee    - (out) OS process ID of debuggee
+//    phmodTargetCLR    - (out) module handle of CoreClr within the debuggee.
+//
+// Returns:
+//    S_OK on success. Else failures.
+//
+// Notes:
+//    The version string is coming from the target CoreClr and in the case of a corrupted target, could be
+//    an arbitrary string. It should be treated as untrusted public input.
+//-----------------------------------------------------------------------------
+static
+HRESULT
+ParseVersionString(
+    LPCWSTR szDebuggeeVersion,
+    CorDebugInterfaceVersion *piDebuggerVersion,
+    DWORD *pdwPidDebuggee,
+    HMODULE *phmodTargetCLR)
+{
+    if ((piDebuggerVersion == NULL) ||
+        (pdwPidDebuggee == NULL) ||
+        (phmodTargetCLR == NULL) ||
+        (wcslen(szDebuggeeVersion) < c_iMinVersionStringLen) ||
+        (W(';') != szDebuggeeVersion[c_idxFirstSemi]) ||
+        (W(';') != szDebuggeeVersion[c_idxSecondSemi]))
+    {
+        return E_INVALIDARG;
+    }
+
+    int numFieldsAssigned = swscanf_s(szDebuggeeVersion, c_versionStrFormat, piDebuggerVersion, pdwPidDebuggee, phmodTargetCLR);
+    if (numFieldsAssigned != 3)
+    {
+        return E_FAIL;
+    }
+
+    return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Appends "\mscordbi.dll" to the path. This converts a directory name into the full path to mscordbi.dll.
+//
+// Arguments:
+//    szFullDbiPath - (in/out): on input, the directory containing dbi. On output, the full path to dbi.dll.
+//-----------------------------------------------------------------------------
+static
+void
+AppendDbiDllName(SString & szFullDbiPath)
+{
+    const WCHAR * pDbiDllName = DIRECTORY_SEPARATOR_STR_W MAKEDLLNAME_W(W("mscordbi"));
+    szFullDbiPath.Append(pDbiDllName);
+}
+
+//-----------------------------------------------------------------------------
+// Return a path to the dbi next to the runtime, if present.
+//
+// Arguments:
+//    pidDebuggee - OS process ID of debuggee
+//    hmodTargetCLR - handle to CoreClr within debuggee process
+//    szFullDbiPath - (out) the full path of Mscordbi.dll next to the debuggee's CoreClr.dll.
+//
+// Notes:
+//    This just calculates a filename and does not determine if the file actually exists.
+//-----------------------------------------------------------------------------
+static
+void
+GetDbiFilenameNextToRuntime(
+    DWORD pidDebuggee,
+    HMODULE hmodTargetCLR,
+    SString & szFullDbiPath,
+    SString & szFullCoreClrPath)
+{
+    szFullDbiPath.Clear();
+
+    //
+    // Step 1: (pid, hmodule) --> full path
+    //
+    HandleHolder hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pidDebuggee);
+    WCHAR modulePath[MAX_LONGPATH];
+    if(0 == GetModuleFileNameEx(hProcess, hmodTargetCLR, modulePath, MAX_LONGPATH))
+    {
+        ThrowHR(E_FAIL);
+    }
+
+    //
+    // Step 2: 'Coreclr.dll' --> 'mscordbi.dll'
+    //
+    WCHAR * pCoreClrPath = modulePath;
+    WCHAR * pLast = wcsrchr(pCoreClrPath, DIRECTORY_SEPARATOR_CHAR_W);
+    if (pLast == NULL)
+    {
+        ThrowHR(E_FAIL);
+    }
+
+    //   c:\abc\coreclr.dll
+    //   01234567890
+    //   c:\abc\mscordbi.dll
+
+    // Copy everything up to but not including the last '\', thus excluding '\coreclr.dll'
+    // Then append '\mscordbi.dll' to get a full path to dbi.
+    COUNT_T len = (COUNT_T) (pLast - pCoreClrPath); // length not including final '\'
+    szFullDbiPath.Set(pCoreClrPath, len);
+
+    AppendDbiDllName(szFullDbiPath);
+
+    szFullCoreClrPath.Set(pCoreClrPath, (COUNT_T)wcslen(pCoreClrPath));
+}
+
+
+//---------------------------------------------------------------------------------------
+//
+// The current policy is that the DBI DLL must live right next to the coreclr DLL.  We check the product
+// version number of both of them to make sure they match.
+//
+// Arguments:
+//    szFullDbiPath     - full path to mscordbi.dll
+//    szFullCoreClrPath - full path to coreclr.dll
+//
+// Return Value:
+//    true if the versions match
+//
+static
+bool
+CheckDbiAndRuntimeVersion(
+    SString & szFullDbiPath,
+    SString & szFullCoreClrPath)
+{
+#ifndef TARGET_UNIX
+    DWORD dwDbiVersionMS = 0;
+    DWORD dwDbiVersionLS = 0;
+    DWORD dwCoreClrVersionMS = 0;
+    DWORD dwCoreClrVersionLS = 0;
+
+    // The version numbers follow the convention used by VS_FIXEDFILEINFO.
+    GetProductVersionNumber(szFullDbiPath, &dwDbiVersionMS, &dwDbiVersionLS);
+    GetProductVersionNumber(szFullCoreClrPath, &dwCoreClrVersionMS, &dwCoreClrVersionLS);
+
+    if ((dwDbiVersionMS == dwCoreClrVersionMS) &&
+        (dwDbiVersionLS == dwCoreClrVersionLS))
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+#else
+    return true;
+#endif // TARGET_UNIX
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+// Given a version string, create the matching mscordbi.dll for it.
+// Create a managed debugging interface for the specified version.
+//
+// Parameters:
+//    iDebuggerVersion - the version of interface the debugger (eg, Cordbg) expects.
+//    szDebuggeeVersion - the version of the debuggee. This will map to a version of mscordbi.dll
+//    ppCordb - the outparameter used to return the debugging interface object.
+//
+// Return:
+//  S_OK on success. *ppCordb will be non-null.
+//  CORDBG_E_INCOMPATIBLE_PROTOCOL - if the proper DBI is not available. This can be a very common error if
+//    the right debug pack is not installed.
+//  else Error. (*ppCordb will be null)
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+CreateDebuggingInterfaceFromVersionEx(
+    _In_ int iDebuggerVersion,
+    _In_ LPCWSTR szDebuggeeVersion,
+    _Out_ IUnknown ** ppCordb)
+{
+    return CreateDebuggingInterfaceFromVersion2(iDebuggerVersion, szDebuggeeVersion, NULL, ppCordb);
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+// Given a version string, create the matching mscordbi.dll for it.
+// Create a managed debugging interface for the specified version.
+//
+// Parameters:
+//    iDebuggerVersion - the version of interface the debugger (eg, Cordbg) expects.
+//    szDebuggeeVersion - the version of the debuggee. This will map to a version of mscordbi.dll
+//    lpApplicationGroupId - A string representing the application group ID of a sandboxed
+//                           process running in Mac. Pass NULL if the process is not
+//                           running in a sandbox and other platforms.
+//    ppCordb - the outparameter used to return the debugging interface object.
+//
+// Return:
+//  S_OK on success. *ppCordb will be non-null.
+//  CORDBG_E_INCOMPATIBLE_PROTOCOL - if the proper DBI is not available. This can be a very common error if
+//    the right debug pack is not installed.
+//  else Error. (*ppCordb will be null)
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+CreateDebuggingInterfaceFromVersion2(
+    _In_ int iDebuggerVersion,
+    _In_ LPCWSTR szDebuggeeVersion,
+    _In_ LPCWSTR szApplicationGroupId,
+    _Out_ IUnknown ** ppCordb)
+{
+    PUBLIC_CONTRACT;
+
+    HRESULT hrIgnore = S_OK; // ignored HResult
+    HRESULT hr = S_OK;
+    HMODULE hMod = NULL;
+    IUnknown * pCordb = NULL;
+
+    LOG((LF_CORDB, LL_EVERYTHING, "Calling CreateDebuggerInterfaceFromVersion, ver=%S\n", szDebuggeeVersion));
+
+    if ((szDebuggeeVersion == NULL) || (ppCordb == NULL))
+    {
+        hr = E_INVALIDARG;
+        goto Exit;
+    }
+
+    //
+    // Step 1: Parse version information into internal data structures
+    //
+
+    CorDebugInterfaceVersion iTargetVersion;  // the CorDebugInterfaceVersion (CorDebugVersion_2_0)
+    DWORD pidDebuggee;     // OS process ID of the debuggee
+    HMODULE hmodTargetCLR; // module of Telesto in target (the clrInstanceId)
+
+    hr = ParseVersionString(szDebuggeeVersion, &iTargetVersion, &pidDebuggee, &hmodTargetCLR);
+    if (FAILED(hr))
+        goto Exit;
+
+    //
+    // Step 2:  Find the proper dbi module (mscordbi) and load it.
+    //
+
+    // Check for dbi next to target CLR.
+    // This will be very common for internal developer setups, but not common in end-user setups.
+    EX_TRY
+    {
+        SString szFullDbiPath;
+        SString szFullCoreClrPath;
+
+        GetDbiFilenameNextToRuntime(pidDebuggee, hmodTargetCLR, szFullDbiPath, szFullCoreClrPath);
+
+        if (!CheckDbiAndRuntimeVersion(szFullDbiPath, szFullCoreClrPath))
+        {
+            hr = CORDBG_E_INCOMPATIBLE_PROTOCOL;
+            goto Exit;
+        }
+
+        // We calculated where dbi would be, but haven't yet verified if it's there.
+        // Try to load it. We're using this to check for file existence.
+
+        // Issue:951525: coreclr mscordbi load fails on downlevel OS since LoadLibraryEx can't find
+        // dependent forwarder DLLs. Force LoadLibrary to look for dependencies in szFullDbiPath plus the default
+        // search paths.
+#ifndef TARGET_UNIX
+        hMod = WszLoadLibraryEx(szFullDbiPath, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
+#else
+        hMod = LoadLibraryExW(szFullDbiPath, NULL, 0);
+#endif
+    }
+    EX_CATCH_HRESULT(hrIgnore); // failure leaves hMod null
+
+    // Couldn't find Dbi, likely because the right debug pack is not installed. Failure.
+    if (NULL == hMod)
+    {
+        // Check for the following two HRESULTs and return them specifically.  These are returned by
+        // CreateToolhelp32Snapshot() and could be transient errors.  The debugger may choose to retry.
+        if ((hrIgnore == HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) || (hrIgnore == HRESULT_FROM_WIN32(ERROR_BAD_LENGTH)))
+        {
+            hr = hrIgnore;
+        }
+        else
+        {
+            hr = CORDBG_E_DEBUG_COMPONENT_MISSING;
+        }
+        goto Exit;
+    }
+
+    //
+    // Step 3: Now that module is loaded, instantiate an ICorDebug.
+    //
+    hr = CreateCoreDbg(hmodTargetCLR, hMod, pidDebuggee, szApplicationGroupId, iDebuggerVersion, &pCordb);
+    _ASSERTE((pCordb == NULL) == FAILED(hr));
+
+Exit:
+    if (FAILED(hr))
+    {
+        if (pCordb != NULL)
+        {
+            pCordb->Release();
+            pCordb = NULL;
+        }
+
+        if (hMod != NULL)
+        {
+            _ASSERTE(pCordb == NULL);
+            FreeLibrary(hMod);
+        }
+    }
+
+    // Set our outparam.
+    *ppCordb = pCordb;
+
+    // On success case, mscordbi.dll is leaked.
+    // - We never give the caller back the module handle, so our caller can't do FreeLibrary().
+    // - ICorDebug can't unload itself.
+
+    return hr;
+}
+
+//-----------------------------------------------------------------------------
+// Public API.
+// Superceded by CreateDebuggingInterfaceFromVersionEx in SLv4.
+// Given a version string, create the matching mscordbi.dll for it.
+// Create a managed debugging interface for the specified version.
+//
+// Parameters:
+//    szDebuggeeVersion - the version of the debuggee. This will map to a version of mscordbi.dll
+//    ppCordb - the outparameter used to return the debugging interface object.
+//
+// Return:
+//  S_OK on success. *ppCordb will be non-null.
+//  CORDBG_E_INCOMPATIBLE_PROTOCOL - if the proper DBI is not available. This can be a very common error if
+//    the right debug pack is not installed.
+//  else Error. (*ppCordb will be null)
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+CreateDebuggingInterfaceFromVersion(
+    _In_ LPCWSTR szDebuggeeVersion,
+    _Out_ IUnknown ** ppCordb
+)
+{
+    PUBLIC_CONTRACT;
+
+    return CreateDebuggingInterfaceFromVersionEx(CorDebugVersion_2_0, szDebuggeeVersion, ppCordb);
+}
+
+#ifndef TARGET_UNIX
+
+//------------------------------------------------------------------------------
+// Manually retrieves the "continue startup" event from the correct CLR instance
+// in the target process.
+//
+// Arguments:
+//    debuggeePID - (in) OS Process ID of debuggee
+//    szTelestoFullPath - (in) full path to telesto within the process.
+//    phContinueStartupEvent - (out)
+//
+// Returns:
+//   S_OK on success.
+//------------------------------------------------------------------------------
+HRESULT
+GetContinueStartupEvent(
+    DWORD debuggeePID,
+    LPCWSTR szTelestoFullPath,
+    _Out_ HANDLE* phContinueStartupEvent)
+{
+    if ((phContinueStartupEvent == NULL) || (szTelestoFullPath == NULL))
+        return E_INVALIDARG;
+
+    HRESULT hr = S_OK;
+    EX_TRY
+    {
+        *phContinueStartupEvent = INVALID_HANDLE_VALUE;
+
+        DWORD  dwCoreClrContinueEventOffset = 0;
+        CLR_ENGINE_METRICS metricsStruct;
+
+        GetTargetCLRMetrics(szTelestoFullPath, &metricsStruct, &dwCoreClrContinueEventOffset); // throws
+
+
+        BYTE* pbBaseAddress = GetRemoteModuleBaseAddress(debuggeePID, szTelestoFullPath); // throws
+
+
+        HandleHolder hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, debuggeePID);
+        if (NULL == hProcess)
+            ThrowHR(E_FAIL);
+
+        HANDLE continueEvent = NULL;
+
+        SIZE_T nBytesRead;
+        if (!ReadProcessMemory(hProcess, pbBaseAddress + dwCoreClrContinueEventOffset, &continueEvent,
+            sizeof(continueEvent), &nBytesRead))
+        {
+            ThrowHR(E_FAIL);
+        }
+
+        if (NULL != continueEvent && INVALID_HANDLE_VALUE != continueEvent)
+        {
+            if (!DuplicateHandle(hProcess, continueEvent, GetCurrentProcess(), &continueEvent,
+                EVENT_MODIFY_STATE, FALSE, 0))
+            {
+                ThrowHR(E_FAIL);
+            }
+        }
+
+        *phContinueStartupEvent = continueEvent;
+    }
+    EX_CATCH_HRESULT(hr)
+    return hr;
+}
+
+#endif // !TARGET_UNIX
+
+#if defined(FEATURE_CORESYSTEM)
+#include "debugshim.h"
+#endif
+
+//-----------------------------------------------------------------------------
+// Public API.
+//
+// Parameters:
+//  clsid
+//  riid
+//  ppInterface
+//
+// Return:
+//  S_OK on success.
+//-----------------------------------------------------------------------------
+DLLEXPORT
+HRESULT
+CLRCreateInstance(
+    REFCLSID clsid,
+    REFIID riid,
+    LPVOID *ppInterface)
+{
+    PUBLIC_CONTRACT;
+
+#if defined(FEATURE_CORESYSTEM)
+
+    if (ppInterface == NULL)
+        return E_POINTER;
+
+    if (clsid != CLSID_CLRDebugging || riid != IID_ICLRDebugging)
+        return E_NOINTERFACE;
+
+#if defined(FEATURE_CORESYSTEM)
+    GUID skuId = CLR_ID_ONECORE_CLR;
+#else
+    GUID skuId = CLR_ID_CORECLR;
+#endif
+
+    CLRDebuggingImpl *pDebuggingImpl = new (nothrow) CLRDebuggingImpl(skuId);
+    if (NULL == pDebuggingImpl)
+        return E_OUTOFMEMORY;
+
+    return pDebuggingImpl->QueryInterface(riid, ppInterface);
+#else
+    return E_NOTIMPL;
+#endif
+}
diff --git a/src/dbgshim/dbgshim.h b/src/dbgshim/dbgshim.h
new file mode 100644 (file)
index 0000000..004fd2a
--- /dev/null
@@ -0,0 +1,91 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// DbgShim.h
+//
+//*****************************************************************************
+
+#include <windows.h>
+
+typedef VOID (*PSTARTUP_CALLBACK)(IUnknown *pCordb, PVOID parameter, HRESULT hr);
+
+EXTERN_C HRESULT
+CreateProcessForLaunch(
+    _In_ LPWSTR lpCommandLine,
+    _In_ BOOL bSuspendProcess,
+    _In_ LPVOID lpEnvironment,
+    _In_ LPCWSTR lpCurrentDirectory,
+    _Out_ PDWORD pProcessId,
+    _Out_ HANDLE *pResumeHandle);
+
+EXTERN_C HRESULT
+ResumeProcess(
+    _In_ HANDLE hResumeHandle);
+
+EXTERN_C HRESULT
+CloseResumeHandle(
+    _In_ HANDLE hResumeHandle);
+
+EXTERN_C HRESULT
+RegisterForRuntimeStartup(
+    _In_ DWORD dwProcessId,
+    _In_ PSTARTUP_CALLBACK pfnCallback,
+    _In_ PVOID parameter,
+    _Out_ PVOID *ppUnregisterToken);
+
+EXTERN_C HRESULT
+RegisterForRuntimeStartupEx(
+    _In_ DWORD dwProcessId,
+    _In_ LPCWSTR szApplicationGroupId,
+    _In_ PSTARTUP_CALLBACK pfnCallback,
+    _In_ PVOID parameter,
+    _Out_ PVOID *ppUnregisterToken);
+
+EXTERN_C HRESULT
+UnregisterForRuntimeStartup(
+    _In_ PVOID pUnregisterToken);
+
+EXTERN_C HRESULT
+GetStartupNotificationEvent(
+    _In_ DWORD debuggeePID,
+    _Out_ HANDLE* phStartupEvent);
+
+EXTERN_C HRESULT
+EnumerateCLRs(DWORD debuggeePID,
+    _Out_ HANDLE** ppHandleArrayOut,
+    _Out_ LPWSTR** ppStringArrayOut,
+    _Out_ DWORD* pdwArrayLengthOut);
+
+EXTERN_C HRESULT
+CloseCLREnumeration(
+    _In_ HANDLE* pHandleArray,
+    _In_ LPWSTR* pStringArray,
+    _In_ DWORD dwArrayLength);
+
+EXTERN_C HRESULT
+CreateVersionStringFromModule(
+    _In_ DWORD pidDebuggee,
+    _In_ LPCWSTR szModuleName,
+    _Out_writes_to_opt_(cchBuffer, *pdwLength) LPWSTR pBuffer,
+    _In_ DWORD cchBuffer,
+    _Out_ DWORD* pdwLength);
+
+EXTERN_C HRESULT
+CreateDebuggingInterfaceFromVersionEx(
+    _In_ int iDebuggerVersion,
+    _In_ LPCWSTR szDebuggeeVersion,
+    _Out_ IUnknown ** ppCordb);
+
+EXTERN_C
+DLLEXPORT
+HRESULT
+CreateDebuggingInterfaceFromVersion2(
+    _In_ int iDebuggerVersion,
+    _In_ LPCWSTR szDebuggeeVersion,
+    _In_ LPCWSTR szApplicationGroupId,
+    _Out_ IUnknown ** ppCordb);
+
+EXTERN_C HRESULT
+CreateDebuggingInterfaceFromVersion(
+    _In_ LPCWSTR szDebuggeeVersion,
+    _Out_ IUnknown ** ppCordb);
diff --git a/src/dbgshim/dbgshim.ntdef b/src/dbgshim/dbgshim.ntdef
new file mode 100644 (file)
index 0000000..2e254ab
--- /dev/null
@@ -0,0 +1,18 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+
+EXPORTS
+        CreateProcessForLaunch
+        ResumeProcess
+        CloseResumeHandle
+        RegisterForRuntimeStartup
+       RegisterForRuntimeStartupEx
+        UnregisterForRuntimeStartup
+       GetStartupNotificationEvent
+       EnumerateCLRs
+       CloseCLREnumeration
+       CreateVersionStringFromModule
+       CreateDebuggingInterfaceFromVersion
+       CreateDebuggingInterfaceFromVersionEx
+       CreateDebuggingInterfaceFromVersion2
+       CLRCreateInstance
diff --git a/src/dbgshim/dbgshim.rc b/src/dbgshim/dbgshim.rc
new file mode 100644 (file)
index 0000000..9b4ac3b
--- /dev/null
@@ -0,0 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#define FX_VER_FILEDESCRIPTION_STR "Microsoft .NET Runtime Multi-CLR Debugging Helper\0"
+
+#include <fxver.h>
+#include <fxver.rc>
diff --git a/src/dbgshim/dbgshim.vcxproj b/src/dbgshim/dbgshim.vcxproj
new file mode 100644 (file)
index 0000000..608c68f
--- /dev/null
@@ -0,0 +1,391 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <PreferredToolArchitecture>x64</PreferredToolArchitecture>
+  </PropertyGroup>
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Checked|x64">
+      <Configuration>Checked</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="RelWithDebInfo|x64">
+      <Configuration>RelWithDebInfo</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{BD779298-8631-3F5D-AA59-82897E5454A7}</ProjectGuid>
+    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <Keyword>Win32Proj</Keyword>
+    <Platform>x64</Platform>
+    <ProjectName>dbgshim</ProjectName>
+    <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Checked|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.20506.1</_ProjectFileVersion>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ArtifactsObjDir)Windows_NT.x64.Debug\src\dbgshim\Debug\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">dbgshim.dir\Debug\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">dbgshim</TargetName>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.dll</TargetExt>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</GenerateManifest>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">$(ArtifactsObjDir)Windows_NT.x64.Debug\src\dbgshim\Checked\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">dbgshim.dir\Checked\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">dbgshim</TargetName>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">.dll</TargetExt>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">false</LinkIncremental>
+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">false</GenerateManifest>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ArtifactsObjDir)Windows_NT.x64.Debug\src\dbgshim\Release\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dbgshim.dir\Release\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dbgshim</TargetName>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.dll</TargetExt>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</GenerateManifest>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">$(ArtifactsObjDir)Windows_NT.x64.Debug\src\dbgshim\RelWithDebInfo\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">dbgshim.dir\RelWithDebInfo\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">dbgshim</TargetName>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">.dll</TargetExt>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">true</LinkIncremental>
+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">false</GenerateManifest>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont /Zm200 /Zc:strictStrings /w34092 /w34121 /w34125 /w34130 /w34132 /w34212 /w34530 /w35038 /w44177 /ZH:SHA_256 /source-charset:utf-8 /homeparams</AdditionalOptions>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <ControlFlowGuard>Guard</ControlFlowGuard>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4065;4100;4127;4189;4200;4201;4245;4291;4456;4457;4458;4733;4838;4960;4961;5105;4603;4627;4459;4091</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <FloatingPointModel>Precise</FloatingPointModel>
+      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>Disabled</Optimization>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatSpecificWarningsAsErrors>4007;4013;4102;4551;4700;4640;4806</TreatSpecificWarningsAsErrors>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <UseFullPaths>true</UseFullPaths>
+      <WarningLevel>Level3</WarningLevel>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Debug;BUILDENV_DEBUG=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR="Debug";dbgshim_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG;_DBG;URTBLDENV_FRIENDLY=Debug;BUILDENV_DEBUG=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR=\"Debug\";dbgshim_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+    <MASM>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Debug;BUILDENV_DEBUG=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR="Debug";dbgshim_EXPORTS;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <IncludePaths>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(IncludePaths)</IncludePaths>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont</AdditionalOptions>
+    </MASM>
+    <Midl>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
+      <HeaderFileName>%(Filename).h</HeaderFileName>
+      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
+      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
+    </Midl>
+    <Link>
+      <AdditionalDependencies>..\inc\Debug\corguids.lib;..\SOS\dbgutil\Debug\dbgutil.lib;..\utilcode\Debug\utilcodestaticnohost.lib;kernel32.lib;libcmtd.lib;libvcruntimed.lib;uuid.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;WtsApi32.lib;version.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /guard:cf /PDBCOMPRESS /IGNORE:4197,4013,4254,4070,4221 /SUBSYSTEM:WINDOWS,6.01 /guard:ehcont /CETCOMPAT</AdditionalOptions>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+      <ImportLibrary>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/Debug/dbgshim.lib</ImportLibrary>
+      <LargeAddressAware>true</LargeAddressAware>
+      <ModuleDefinitionFile>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/dbgshim.def</ModuleDefinitionFile>
+      <ProgramDataBaseFile>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/Debug/dbgshim.pdb</ProgramDataBaseFile>
+      <SubSystem>Console</SubSystem>
+    </Link>
+    <ProjectReference>
+      <LinkLibraryDependencies>false</LinkLibraryDependencies>
+    </ProjectReference>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont /Zm200 /Zc:strictStrings /w34092 /w34121 /w34125 /w34130 /w34132 /w34212 /w34530 /w35038 /w44177 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <ControlFlowGuard>Guard</ControlFlowGuard>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4065;4100;4127;4189;4200;4201;4245;4291;4456;4457;4458;4733;4838;4960;4961;5105;4603;4627;4459;4091</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <FloatingPointModel>Precise</FloatingPointModel>
+      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>MaxSpeed</Optimization>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatSpecificWarningsAsErrors>4007;4013;4102;4551;4700;4640;4806</TreatSpecificWarningsAsErrors>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <UseFullPaths>true</UseFullPaths>
+      <WarningLevel>Level3</WarningLevel>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR="Checked";dbgshim_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR=\"Checked\";dbgshim_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+    <MASM>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR="Checked";dbgshim_EXPORTS;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <IncludePaths>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(IncludePaths)</IncludePaths>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont</AdditionalOptions>
+    </MASM>
+    <Midl>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
+      <HeaderFileName>%(Filename).h</HeaderFileName>
+      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
+      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
+    </Midl>
+    <Link>
+      <AdditionalDependencies>..\inc\Checked\corguids.lib;..\SOS\dbgutil\Checked\dbgutil.lib;..\utilcode\Checked\utilcodestaticnohost.lib;kernel32.lib;libcmtd.lib;libvcruntimed.lib;uuid.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;WtsApi32.lib;version.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /guard:cf /PDBCOMPRESS /IGNORE:4197,4013,4254,4070,4221 /SUBSYSTEM:WINDOWS,6.01 /guard:ehcont /CETCOMPAT</AdditionalOptions>
+      <EnableCOMDATFolding>false</EnableCOMDATFolding>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+      <ImportLibrary>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/Checked/dbgshim.lib</ImportLibrary>
+      <LargeAddressAware>true</LargeAddressAware>
+      <ModuleDefinitionFile>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/dbgshim.def</ModuleDefinitionFile>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ProgramDataBaseFile>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/Checked/dbgshim.pdb</ProgramDataBaseFile>
+      <SubSystem>Console</SubSystem>
+    </Link>
+    <ProjectReference>
+      <LinkLibraryDependencies>false</LinkLibraryDependencies>
+    </ProjectReference>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont /Zm200 /Zc:strictStrings /w34092 /w34121 /w34125 /w34130 /w34132 /w34212 /w34530 /w35038 /w44177 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <ControlFlowGuard>Guard</ControlFlowGuard>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4065;4100;4127;4189;4200;4201;4245;4291;4456;4457;4458;4733;4838;4960;4961;5105;4603;4627;4459;4091</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <FloatingPointModel>Precise</FloatingPointModel>
+      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>Full</Optimization>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatSpecificWarningsAsErrors>4007;4013;4102;4551;4700;4640;4806</TreatSpecificWarningsAsErrors>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <UseFullPaths>true</UseFullPaths>
+      <WarningLevel>Level3</WarningLevel>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR="Release";dbgshim_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR=\"Release\";dbgshim_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+    <MASM>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR="Release";dbgshim_EXPORTS;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <IncludePaths>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(IncludePaths)</IncludePaths>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont</AdditionalOptions>
+    </MASM>
+    <Midl>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
+      <HeaderFileName>%(Filename).h</HeaderFileName>
+      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
+      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
+    </Midl>
+    <Link>
+      <AdditionalDependencies>..\inc\Release\corguids.lib;..\SOS\dbgutil\Release\dbgutil.lib;..\utilcode\Release\utilcodestaticnohost.lib;kernel32.lib;libcmt.lib;libvcruntime.lib;uuid.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;WtsApi32.lib;version.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /guard:cf /PDBCOMPRESS /IGNORE:4197,4013,4254,4070,4221 /SUBSYSTEM:WINDOWS,6.01 /guard:ehcont /CETCOMPAT /DEFAULTLIB:ucrt.lib</AdditionalOptions>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <IgnoreSpecificDefaultLibraries>libucrt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+      <ImportLibrary>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/Release/dbgshim.lib</ImportLibrary>
+      <LargeAddressAware>true</LargeAddressAware>
+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+      <ModuleDefinitionFile>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/dbgshim.def</ModuleDefinitionFile>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ProgramDataBaseFile>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/Release/dbgshim.pdb</ProgramDataBaseFile>
+      <SubSystem>Console</SubSystem>
+    </Link>
+    <ProjectReference>
+      <LinkLibraryDependencies>false</LinkLibraryDependencies>
+    </ProjectReference>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont /Zm200 /Zc:strictStrings /w34092 /w34121 /w34125 /w34130 /w34132 /w34212 /w34530 /w35038 /w44177 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <ControlFlowGuard>Guard</ControlFlowGuard>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4065;4100;4127;4189;4200;4201;4245;4291;4456;4457;4458;4733;4838;4960;4961;5105;4603;4627;4459;4091</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <FloatingPointModel>Precise</FloatingPointModel>
+      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>MaxSpeed</Optimization>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatSpecificWarningsAsErrors>4007;4013;4102;4551;4700;4640;4806</TreatSpecificWarningsAsErrors>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <UseFullPaths>true</UseFullPaths>
+      <WarningLevel>Level3</WarningLevel>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR="RelWithDebInfo";dbgshim_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR=\"RelWithDebInfo\";dbgshim_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+    <MASM>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;FEATURE_NO_HOST;SELF_NO_HOST;_BLD_CLR;FX_VER_INTERNALNAME_STR=dbgshim.dll;CMAKE_INTDIR="RelWithDebInfo";dbgshim_EXPORTS;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <IncludePaths>$(RepoRoot)artifacts\obj;$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(IncludePaths)</IncludePaths>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont</AdditionalOptions>
+    </MASM>
+    <Midl>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
+      <HeaderFileName>%(Filename).h</HeaderFileName>
+      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
+      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
+    </Midl>
+    <Link>
+      <AdditionalDependencies>..\inc\RelWithDebInfo\corguids.lib;..\SOS\dbgutil\RelWithDebInfo\dbgutil.lib;..\utilcode\RelWithDebInfo\utilcodestaticnohost.lib;kernel32.lib;libcmt.lib;libvcruntime.lib;uuid.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;WtsApi32.lib;version.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /guard:cf /PDBCOMPRESS /IGNORE:4197,4013,4254,4070,4221 /SUBSYSTEM:WINDOWS,6.01 /guard:ehcont /CETCOMPAT</AdditionalOptions>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+      <ImportLibrary>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/RelWithDebInfo/dbgshim.lib</ImportLibrary>
+      <LargeAddressAware>true</LargeAddressAware>
+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+      <ModuleDefinitionFile>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/dbgshim.def</ModuleDefinitionFile>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ProgramDataBaseFile>$(ArtifactsObjDir)Windows_NT.x64.Debug/src/dbgshim/RelWithDebInfo/dbgshim.pdb</ProgramDataBaseFile>
+      <SubSystem>Console</SubSystem>
+    </Link>
+    <ProjectReference>
+      <LinkLibraryDependencies>false</LinkLibraryDependencies>
+    </ProjectReference>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="dbgshim.cpp" />
+    <ClCompile Include="debugshim.cpp" />
+    <None Include="dbgshim.ntdef" />
+    <None Include="dbgshim_unixexports.src" />
+    <None Include="pkg\Directory.Build.props" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-arm.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-arm64.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-musl-arm64.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-musl-x64.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-x64.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.osx-arm64.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.osx-x64.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.props" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.win-arm.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.win-arm64.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.win-x64.proj" />
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.win-x86.proj" />
+    <ResourceCompile Include="dbgshim.rc" />
+    <None Include="CMakeLists.txt" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="debugshim.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/dbgshim/dbgshim.vcxproj.filters b/src/dbgshim/dbgshim.vcxproj.filters
new file mode 100644 (file)
index 0000000..aa9a252
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="dbgshim.cpp" />
+    <ClCompile Include="debugshim.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="CMakeLists.txt" />
+    <None Include="pkg\Directory.Build.props">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-arm.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-arm64.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-musl-arm64.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-musl-x64.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.linux-x64.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.osx-arm64.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.osx-x64.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.props">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.win-arm.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.win-arm64.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.win-x64.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="pkg\Microsoft.Diagnostics.DbgShim.win-x86.proj">
+      <Filter>pkg</Filter>
+    </None>
+    <None Include="dbgshim.ntdef" />
+    <None Include="dbgshim_unixexports.src" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="dbgshim.rc" />
+  </ItemGroup>
+  <ItemGroup>
+    <Filter Include="pkg">
+      <UniqueIdentifier>{ac4ed0ef-d259-4eed-8152-b4c1db4df94c}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="debugshim.h" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/dbgshim/dbgshim_unixexports.src b/src/dbgshim/dbgshim_unixexports.src
new file mode 100644 (file)
index 0000000..b1daf52
--- /dev/null
@@ -0,0 +1,17 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+
+CreateProcessForLaunch
+ResumeProcess
+CloseResumeHandle
+RegisterForRuntimeStartup
+RegisterForRuntimeStartupEx
+UnregisterForRuntimeStartup
+GetStartupNotificationEvent
+EnumerateCLRs
+CloseCLREnumeration
+CreateVersionStringFromModule
+CreateDebuggingInterfaceFromVersion
+CreateDebuggingInterfaceFromVersionEx
+CreateDebuggingInterfaceFromVersion2
+CLRCreateInstance
diff --git a/src/dbgshim/debugshim.cpp b/src/dbgshim/debugshim.cpp
new file mode 100644 (file)
index 0000000..3dcfbcc
--- /dev/null
@@ -0,0 +1,785 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// debugshim.cpp
+//
+
+//
+//*****************************************************************************
+
+#include "debugshim.h"
+#include "dbgutil.h"
+#include <crtdbg.h>
+#include <clrinternal.h> //has the CLR_ID_V4_DESKTOP guid in it
+#include "palclr.h"
+
+#ifndef IMAGE_FILE_MACHINE_ARMNT
+#define IMAGE_FILE_MACHINE_ARMNT             0x01c4  // ARM Thumb-2 Little-Endian
+#endif
+
+#ifndef IMAGE_FILE_MACHINE_ARM64
+#define IMAGE_FILE_MACHINE_ARM64             0xAA64  // ARM64 Little-Endian
+#endif
+
+//*****************************************************************************
+// CLRDebuggingImpl implementation (ICLRDebugging)
+//*****************************************************************************
+
+typedef HRESULT (STDAPICALLTYPE  *OpenVirtualProcessImpl2FnPtr)(ULONG64 clrInstanceId,
+    IUnknown * pDataTarget,
+    LPCWSTR pDacModulePath,
+    CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
+    REFIID riid,
+    IUnknown ** ppInstance,
+    CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
+
+typedef HRESULT (STDAPICALLTYPE  *OpenVirtualProcessImplFnPtr)(ULONG64 clrInstanceId,
+    IUnknown * pDataTarget,
+    HMODULE hDacDll,
+    CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
+    REFIID riid,
+    IUnknown ** ppInstance,
+    CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
+
+typedef HRESULT (STDAPICALLTYPE  *OpenVirtualProcess2FnPtr)(ULONG64 clrInstanceId,
+    IUnknown * pDataTarget,
+    HMODULE hDacDll,
+    REFIID riid,
+    IUnknown ** ppInstance,
+    CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
+
+typedef HMODULE (STDAPICALLTYPE  *LoadLibraryWFnPtr)(LPCWSTR lpLibFileName);
+
+static bool IsTargetWindows(ICorDebugDataTarget* pDataTarget)
+{
+    CorDebugPlatform targetPlatform;
+
+    HRESULT result = pDataTarget->GetPlatform(&targetPlatform);
+
+    if(FAILED(result))
+    {
+        _ASSERTE(!"Unexpected error");
+        return false;
+    }
+
+    switch (targetPlatform)
+    {
+        case CORDB_PLATFORM_WINDOWS_X86:
+        case CORDB_PLATFORM_WINDOWS_AMD64:
+        case CORDB_PLATFORM_WINDOWS_IA64:
+        case CORDB_PLATFORM_WINDOWS_ARM:
+        case CORDB_PLATFORM_WINDOWS_ARM64:
+            return true;
+        default:
+            return false;
+    }
+}
+
+// Implementation of ICLRDebugging::OpenVirtualProcess
+//
+// Arguments:
+//   moduleBaseAddress - the address of the module which might be a CLR
+//   pDataTarget - the data target for inspecting the process
+//   pLibraryProvider - a callback for locating DBI and DAC
+//   pMaxDebuggerSupportedVersion - the max version of the CLR that this debugger will support debugging
+//   riidProcess - the IID of the interface that should be passed back in ppProcess
+//   ppProcess - output for the ICorDebugProcess# if this module is a CLR
+//   pVersion - the CLR version if this module is a CLR
+//   pFlags - output, see the CLR_DEBUGGING_PROCESS_FLAGS for more details. Right now this has only one possible
+//            value which indicates this runtime had an unhandled exception
+STDMETHODIMP CLRDebuggingImpl::OpenVirtualProcess(
+    ULONG64 moduleBaseAddress,
+    IUnknown * pDataTarget,
+    ICLRDebuggingLibraryProvider * pLibraryProvider,
+    CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
+    REFIID riidProcess,
+    IUnknown ** ppProcess,
+    CLR_DEBUGGING_VERSION * pVersion,
+    CLR_DEBUGGING_PROCESS_FLAGS * pFlags)
+{
+    //PRECONDITION(CheckPointer(pDataTarget));
+
+    HRESULT hr = S_OK;
+    ICorDebugDataTarget * pDt = NULL;
+    HMODULE hDbi = NULL;
+    HMODULE hDac = NULL;
+    LPWSTR pDacModulePath = NULL;
+    LPWSTR pDbiModulePath = NULL;
+    DWORD dbiTimestamp;
+    DWORD dbiSizeOfImage;
+    WCHAR dbiName[MAX_PATH_FNAME] = { 0 };
+    DWORD dacTimestamp;
+    DWORD dacSizeOfImage;
+    WCHAR dacName[MAX_PATH_FNAME] = { 0 };
+    CLR_DEBUGGING_VERSION version;
+    BOOL versionSupportedByCaller = FALSE;
+
+    // argument checking
+    if ((ppProcess != NULL || pFlags != NULL) && pLibraryProvider == NULL)
+    {
+        hr = E_POINTER; // the library provider must be specified if either
+                            // ppProcess or pFlags is non-NULL
+    }
+    else if ((ppProcess != NULL || pFlags != NULL) && pMaxDebuggerSupportedVersion == NULL)
+    {
+        hr = E_POINTER; // the max supported version must be specified if either
+                            // ppProcess or pFlags is non-NULL
+    }
+    else if (pVersion != NULL && pVersion->wStructVersion != 0)
+    {
+        hr = CORDBG_E_UNSUPPORTED_VERSION_STRUCT;
+    }
+    else if (FAILED(pDataTarget->QueryInterface(__uuidof(ICorDebugDataTarget), (void**)&pDt)))
+    {
+        hr = CORDBG_E_MISSING_DATA_TARGET_INTERFACE;
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        // get CLR version
+        // The expectation is that new versions of the CLR will continue to use the same GUID
+        // (unless there's a reason to hide them from older shims), but debuggers will tell us the
+        // CLR version they're designed for and mscordbi.dll can decide whether or not to accept it.
+        version.wStructVersion = 0;
+        hr = GetCLRInfo(pDt,
+            moduleBaseAddress,
+            &version,
+            &dbiTimestamp,
+            &dbiSizeOfImage,
+            dbiName,
+            MAX_PATH_FNAME,
+            &dacTimestamp,
+            &dacSizeOfImage,
+            dacName,
+            MAX_PATH_FNAME);
+    }
+
+    // If we need to fetch either the process info or the flags info then we need to find
+    // mscordbi and DAC and do the version specific OVP work
+    if (SUCCEEDED(hr) && (ppProcess != NULL || pFlags != NULL))
+    {
+        ICLRDebuggingLibraryProvider2* pLibraryProvider2;
+        if (SUCCEEDED(pLibraryProvider->QueryInterface(__uuidof(ICLRDebuggingLibraryProvider2), (void**)&pLibraryProvider2)))
+        {
+            if (FAILED(pLibraryProvider2->ProvideLibrary2(dbiName, dbiTimestamp, dbiSizeOfImage, &pDbiModulePath)) ||
+                pDbiModulePath == NULL)
+            {
+                hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
+            }
+
+            if (SUCCEEDED(hr))
+            {
+                hDbi = LoadLibraryW(pDbiModulePath);
+                if (hDbi == NULL)
+                {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                }
+            }
+
+            if (SUCCEEDED(hr))
+            {
+                // Adjust the timestamp and size of image if this DAC is a known buggy version and needs to be retargeted
+                RetargetDacIfNeeded(&dacTimestamp, &dacSizeOfImage);
+
+                // Ask library provider for dac
+                if (FAILED(pLibraryProvider2->ProvideLibrary2(dacName, dacTimestamp, dacSizeOfImage, &pDacModulePath)) ||
+                    pDacModulePath == NULL)
+                {
+                    hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
+                }
+
+                if (SUCCEEDED(hr))
+                {
+                    hDac = LoadLibraryW(pDacModulePath);
+                    if (hDac == NULL)
+                    {
+                        hr = HRESULT_FROM_WIN32(GetLastError());
+                    }
+                }
+            }
+
+            pLibraryProvider2->Release();
+        }
+        else {
+            // Ask library provider for dbi
+            if (FAILED(pLibraryProvider->ProvideLibrary(dbiName, dbiTimestamp, dbiSizeOfImage, &hDbi)) ||
+                hDbi == NULL)
+            {
+                hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
+            }
+
+            if (SUCCEEDED(hr))
+            {
+                // Adjust the timestamp and size of image if this DAC is a known buggy version and needs to be retargeted
+                RetargetDacIfNeeded(&dacTimestamp, &dacSizeOfImage);
+
+                // ask library provider for dac
+                if (FAILED(pLibraryProvider->ProvideLibrary(dacName, dacTimestamp, dacSizeOfImage, &hDac)) ||
+                    hDac == NULL)
+                {
+                    hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
+                }
+            }
+        }
+
+        *ppProcess = NULL;
+
+        if (SUCCEEDED(hr) && pDacModulePath != NULL)
+        {
+            // Get access to the latest OVP implementation and call it
+            OpenVirtualProcessImpl2FnPtr ovpFn = (OpenVirtualProcessImpl2FnPtr)GetProcAddress(hDbi, "OpenVirtualProcessImpl2");
+            if (ovpFn != NULL)
+            {
+                hr = ovpFn(moduleBaseAddress, pDataTarget, pDacModulePath, pMaxDebuggerSupportedVersion, riidProcess, ppProcess, pFlags);
+                if (FAILED(hr))
+                {
+                    _ASSERTE(ppProcess == NULL || *ppProcess == NULL);
+                    _ASSERTE(pFlags == NULL || *pFlags == 0);
+                }
+            }
+#ifdef HOST_UNIX
+            else
+            {
+                // On Linux/MacOS the DAC module handle needs to be re-created using the DAC PAL instance
+                // before being passed to DBI's OpenVirtualProcess* implementation. The DBI and DAC share
+                // the same PAL where dbgshim has it's own.
+                LoadLibraryWFnPtr loadLibraryWFn = (LoadLibraryWFnPtr)GetProcAddress(hDac, "LoadLibraryW");
+                if (loadLibraryWFn != NULL)
+                {
+                    hDac = loadLibraryWFn(pDacModulePath);
+                    if (hDac == NULL)
+                    {
+                        hr = E_HANDLE;
+                    }
+                }
+                else
+                {
+                    hr = E_HANDLE;
+                }
+            }
+#endif // HOST_UNIX
+        }
+
+        // If no errors so far and "OpenVirtualProcessImpl2" doesn't exist
+        if (SUCCEEDED(hr) && *ppProcess == NULL)
+        {
+            // Get access to OVP and call it
+            OpenVirtualProcessImplFnPtr ovpFn = (OpenVirtualProcessImplFnPtr)GetProcAddress(hDbi, "OpenVirtualProcessImpl");
+            if (ovpFn == NULL)
+            {
+                // Fallback to CLR v4 Beta1 path, but skip some of the checking we'd normally do (maxSupportedVersion, etc.)
+                OpenVirtualProcess2FnPtr ovp2Fn = (OpenVirtualProcess2FnPtr)GetProcAddress(hDbi, "OpenVirtualProcess2");
+                if (ovp2Fn == NULL)
+                {
+                    hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
+                }
+                else
+                {
+                    hr = ovp2Fn(moduleBaseAddress, pDataTarget, hDac, riidProcess, ppProcess, pFlags);
+                }
+            }
+            else
+            {
+                // Have a CLR v4 Beta2+ DBI, call it and let it do the version check
+                hr = ovpFn(moduleBaseAddress, pDataTarget, hDac, pMaxDebuggerSupportedVersion, riidProcess, ppProcess, pFlags);
+                if (FAILED(hr))
+                {
+                    _ASSERTE(ppProcess == NULL || *ppProcess == NULL);
+                    _ASSERTE(pFlags == NULL || *pFlags == 0);
+                }
+            }
+        }
+    }
+
+    //version is still valid in some failure cases
+    if (pVersion != NULL &&
+        (SUCCEEDED(hr) ||
+        (hr == CORDBG_E_UNSUPPORTED_DEBUGGING_MODEL) ||
+            (hr == CORDBG_E_UNSUPPORTED_FORWARD_COMPAT)))
+    {
+        memcpy(pVersion, &version, sizeof(CLR_DEBUGGING_VERSION));
+    }
+
+    if (pDacModulePath != NULL)
+    {
+#ifdef HOST_UNIX
+        free(pDacModulePath);
+#else
+        CoTaskMemFree(pDacModulePath);
+#endif
+    }
+
+    if (pDbiModulePath != NULL)
+    {
+#ifdef HOST_UNIX
+        free(pDbiModulePath);
+#else
+        CoTaskMemFree(pDbiModulePath);
+#endif
+    }
+
+    // free the data target we QI'ed earlier
+    if (pDt != NULL)
+    {
+        pDt->Release();
+    }
+
+    return hr;
+}
+
+// Checks to see if this DAC is one of a known set of old DAC builds which contains an issue.
+// If so we retarget to a newer compatible version which has the bug fixed. This is done
+// by changing the PE information used to lookup the DAC.
+//
+// Arguments
+//   pdwTimeStamp - on input, the timestamp of DAC as embedded in the CLR image
+//                  on output, a potentially new timestamp for an updated DAC to use
+//                  instead
+//   pdwSizeOfImage - on input, the sizeOfImage of DAC as embedded in the CLR image
+//                  on output, a potentially new sizeOfImage for an updated DAC to use
+//                  instead
+VOID CLRDebuggingImpl::RetargetDacIfNeeded(DWORD* pdwTimeStamp,
+                                           DWORD* pdwSizeOfImage)
+{
+
+    // This code is auto generated by the CreateRetargetTable tool
+    // on 3/4/2011 6:35 PM
+    // and then copy-pasted here.
+    //
+    //
+    //
+    // Retarget the GDR1 amd64 build
+    if( (*pdwTimeStamp == 0x4d536868) && (*pdwSizeOfImage == 0x17b000))
+    {
+        *pdwTimeStamp = 0x4d71a160;
+        *pdwSizeOfImage = 0x17b000;
+    }
+    // Retarget the GDR1 x86 build
+    else if( (*pdwTimeStamp == 0x4d5368f2) && (*pdwSizeOfImage == 0x120000))
+    {
+        *pdwTimeStamp = 0x4d71a14f;
+        *pdwSizeOfImage = 0x120000;
+    }
+    // Retarget the RTM amd64 build
+    else if( (*pdwTimeStamp == 0x4ba21fa7) && (*pdwSizeOfImage == 0x17b000))
+    {
+        *pdwTimeStamp = 0x4d71a13c;
+        *pdwSizeOfImage = 0x17b000;
+    }
+    // Retarget the RTM x86 build
+    else if( (*pdwTimeStamp == 0x4ba1da25) && (*pdwSizeOfImage == 0x120000))
+    {
+        *pdwTimeStamp = 0x4d71a128;
+        *pdwSizeOfImage = 0x120000;
+    }
+    // This code is auto generated by the CreateRetargetTable tool
+    // on 8/17/2011 1:28 AM
+    // and then copy-pasted here.
+    //
+    //
+    //
+    // Retarget the GDR2 amd64 build
+    else if( (*pdwTimeStamp == 0x4da428c7) && (*pdwSizeOfImage == 0x17b000))
+    {
+        *pdwTimeStamp = 0x4e4b7bc2;
+        *pdwSizeOfImage = 0x17b000;
+    }
+    // Retarget the GDR2 x86 build
+    else if( (*pdwTimeStamp == 0x4da3fe52) && (*pdwSizeOfImage == 0x120000))
+    {
+        *pdwTimeStamp = 0x4e4b7bb1;
+        *pdwSizeOfImage = 0x120000;
+    }
+    // End auto-generated code
+}
+
+#define PE_FIXEDFILEINFO_SIGNATURE 0xFEEF04BD
+
+// The format of the special debugging resource we embed in CLRs starting in
+// v4
+struct CLR_DEBUG_RESOURCE
+{
+    DWORD dwVersion;
+    GUID signature;
+    DWORD dwDacTimeStamp;
+    DWORD dwDacSizeOfImage;
+    DWORD dwDbiTimeStamp;
+    DWORD dwDbiSizeOfImage;
+};
+
+// Checks to see if a module is a CLR and if so, fetches the debug data
+// from the embedded resource
+//
+// Arguments
+//   pDataTarget - dataTarget for the process we are inspecting
+//   moduleBaseAddress - base address of a module we should inspect
+//   pVersion - output, the version of the CLR detected if this is a CLR
+//   pdwDbiTimeStamp - the timestamp of DBI as embedded in the CLR image
+//   pdwDbiSizeOfImage - the SizeOfImage of DBI as embedded in the CLR image
+//   pDbiName - output, the filename of DBI (as calculated by this function but that might change)
+//   dwDbiNameCharCount - input, the number of WCHARs in the buffer pointed to by pDbiName
+//   pdwDacTimeStampe - the timestamp of DAC as embedded in the CLR image
+//   pdwDacSizeOfImage - the SizeOfImage of DAC as embedded in the CLR image
+//   pDacName - output, the filename of DAC (as calculated by this function but that might change)
+//   dwDacNameCharCount - input, the number of WCHARs in the buffer pointed to by pDacName
+HRESULT CLRDebuggingImpl::GetCLRInfo(ICorDebugDataTarget* pDataTarget,
+                                     ULONG64 moduleBaseAddress,
+                                     CLR_DEBUGGING_VERSION* pVersion,
+                                     DWORD* pdwDbiTimeStamp,
+                                     DWORD* pdwDbiSizeOfImage,
+                                     _Inout_updates_z_(dwDbiNameCharCount) WCHAR* pDbiName,
+                                     DWORD  dwDbiNameCharCount,
+                                     DWORD* pdwDacTimeStamp,
+                                     DWORD* pdwDacSizeOfImage,
+                                     _Inout_updates_z_(dwDacNameCharCount) WCHAR* pDacName,
+                                     DWORD  dwDacNameCharCount)
+{
+#ifdef HOST_WINDOWS
+    if(IsTargetWindows(pDataTarget))
+    {
+        WORD imageFileMachine = 0;
+        DWORD resourceSectionRVA = 0;
+        HRESULT hr = GetMachineAndResourceSectionRVA(pDataTarget, moduleBaseAddress, &imageFileMachine, &resourceSectionRVA);
+
+        // We want the version resource which has type = RT_VERSION = 16, name = 1, language = 0x409
+        DWORD versionResourceRVA = 0;
+        DWORD versionResourceSize = 0;
+        if(SUCCEEDED(hr))
+        {
+            hr = GetResourceRvaFromResourceSectionRva(pDataTarget, moduleBaseAddress, resourceSectionRVA, 16, 1, 0x409,
+                     &versionResourceRVA, &versionResourceSize);
+        }
+
+        // At last we get our version info
+        VS_FIXEDFILEINFO fixedFileInfo = {0};
+        if(SUCCEEDED(hr))
+        {
+            // The version resource has 3 words, then the unicode string "VS_VERSION_INFO"
+            // (16 WCHARS including the null terminator)
+            // then padding to a 32-bit boundary, then the VS_FIXEDFILEINFO struct
+            DWORD fixedFileInfoRVA = ((versionResourceRVA + 3*2 + 16*2 + 3)/4)*4;
+            hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + fixedFileInfoRVA, (BYTE*)&fixedFileInfo, sizeof(fixedFileInfo));
+        }
+
+        //Verify the signature on the version resource
+        if(SUCCEEDED(hr) && fixedFileInfo.dwSignature != PE_FIXEDFILEINFO_SIGNATURE)
+        {
+            hr = CORDBG_E_NOT_CLR;
+        }
+
+        // Record the version information
+        if(SUCCEEDED(hr))
+        {
+            pVersion->wMajor = (WORD) (fixedFileInfo.dwProductVersionMS >> 16);
+            pVersion->wMinor = (WORD) (fixedFileInfo.dwProductVersionMS & 0xFFFF);
+            pVersion->wBuild = (WORD) (fixedFileInfo.dwProductVersionLS >> 16);
+            pVersion->wRevision = (WORD) (fixedFileInfo.dwProductVersionLS & 0xFFFF);
+        }
+
+        // Now grab the special clr debug info resource
+        // We may need to scan a few different names searching though...
+        // 1) CLRDEBUGINFO<host_os><host_arch> where host_os = 'WINDOWS' or 'CORESYS' and host_arch = 'X86' or 'ARM' or 'AMD64'
+        // 2) For back-compat if the host os is windows and the host architecture matches the target then CLRDEBUGINFO is used with no suffix.
+        DWORD debugResourceRVA = 0;
+        DWORD debugResourceSize = 0;
+        BOOL useCrossPlatformNaming = FALSE;
+        if(SUCCEEDED(hr))
+        {
+            // the initial state is that we haven't found a proper resource
+            HRESULT hrGetResource = E_FAIL;
+
+            // First check for the resource which has type = RC_DATA = 10, name = "CLRDEBUGINFO<host_os><host_arch>", language = 0
+    #if defined (HOST_WINDOWS) && defined(HOST_X86)
+            const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSX86");
+    #endif
+
+    #if !defined (HOST_WINDOWS) && defined(HOST_X86)
+            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSX86");
+    #endif
+
+    #if defined (HOST_WINDOWS) && defined(HOST_AMD64)
+            const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSAMD64");
+    #endif
+
+    #if !defined (HOST_WINDOWS) && defined(HOST_AMD64)
+            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSAMD64");
+    #endif
+
+    #if defined (HOST_WINDOWS) && defined(HOST_ARM64)
+            const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSARM64");
+    #endif
+
+    #if !defined (HOST_WINDOWS) && defined(HOST_ARM64)
+            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSARM64");
+    #endif
+
+    #if defined (HOST_WINDOWS) && defined(HOST_ARM)
+            const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSARM");
+    #endif
+
+    #if !defined (HOST_WINDOWS) && defined(HOST_ARM)
+            const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSARM");
+    #endif
+
+            hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, resourceName, 0,
+                     &debugResourceRVA, &debugResourceSize);
+            useCrossPlatformNaming = SUCCEEDED(hrGetResource);
+
+
+    #if defined(HOST_WINDOWS) && (defined(HOST_X86) || defined(HOST_AMD64) || defined(HOST_ARM))
+      #if defined(HOST_X86)
+        #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_I386
+      #elif defined(HOST_AMD64)
+        #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64
+      #elif defined(HOST_ARM)
+        #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_ARMNT
+      #endif
+
+            // if this is windows, and if host_arch matches target arch then we can fallback to searching for CLRDEBUGINFO on failure
+            if(FAILED(hrGetResource) && (imageFileMachine == _HOST_MACHINE_TYPE))
+            {
+                hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, W("CLRDEBUGINFO"), 0,
+                     &debugResourceRVA, &debugResourceSize);
+            }
+
+      #undef _HOST_MACHINE_TYPE
+    #endif
+            // if the search failed, we don't recognize the CLR
+            if(FAILED(hrGetResource))
+                hr = CORDBG_E_NOT_CLR;
+        }
+
+        CLR_DEBUG_RESOURCE debugResource;
+        if(SUCCEEDED(hr) && debugResourceSize != sizeof(debugResource))
+        {
+            hr = CORDBG_E_NOT_CLR;
+        }
+
+        // Get the special debug resource from the image and return the results
+        if(SUCCEEDED(hr))
+        {
+            hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + debugResourceRVA, (BYTE*)&debugResource, sizeof(debugResource));
+        }
+        if(SUCCEEDED(hr) && (debugResource.dwVersion != 0))
+        {
+            hr = CORDBG_E_NOT_CLR;
+        }
+
+        // The signature needs to match m_skuId exactly, except for m_skuId=CLR_ID_ONECORE_CLR which is
+        // also compatible with the older CLR_ID_PHONE_CLR signature.
+        if(SUCCEEDED(hr) &&
+           (debugResource.signature != m_skuId) &&
+           !( (debugResource.signature == CLR_ID_PHONE_CLR) && (m_skuId == CLR_ID_ONECORE_CLR) ))
+        {
+            hr = CORDBG_E_NOT_CLR;
+        }
+
+        if(SUCCEEDED(hr) &&
+           (debugResource.signature != CLR_ID_ONECORE_CLR) &&
+           useCrossPlatformNaming)
+        {
+            FormatLongDacModuleName(pDacName, dwDacNameCharCount, imageFileMachine, &fixedFileInfo);
+            swprintf_s(pDbiName, dwDbiNameCharCount, W("%s_%s.dll"), MAIN_DBI_MODULE_NAME_W, W("x86"));
+        }
+        else
+        {
+            if(m_skuId == CLR_ID_V4_DESKTOP)
+                swprintf_s(pDacName, dwDacNameCharCount, W("%s.dll"), CLR_DAC_MODULE_NAME_W);
+            else
+                swprintf_s(pDacName, dwDacNameCharCount, W("%s.dll"), CORECLR_DAC_MODULE_NAME_W);
+            swprintf_s(pDbiName, dwDbiNameCharCount, W("%s.dll"), MAIN_DBI_MODULE_NAME_W);
+        }
+
+        if(SUCCEEDED(hr))
+        {
+            *pdwDbiTimeStamp = debugResource.dwDbiTimeStamp;
+            *pdwDbiSizeOfImage = debugResource.dwDbiSizeOfImage;
+            *pdwDacTimeStamp = debugResource.dwDacTimeStamp;
+            *pdwDacSizeOfImage = debugResource.dwDacSizeOfImage;
+        }
+
+        // any failure should be interpreted as this module not being a CLR
+        if(FAILED(hr))
+        {
+            return CORDBG_E_NOT_CLR;
+        }
+        else
+        {
+            return S_OK;
+        }
+    }
+    else
+#endif // !HOST_WINDOWS
+    {
+        swprintf_s(pDacName, dwDacNameCharCount, W("%s"), MAKEDLLNAME_W(CORECLR_DAC_MODULE_NAME_W));
+        swprintf_s(pDbiName, dwDbiNameCharCount, W("%s"), MAKEDLLNAME_W(MAIN_DBI_MODULE_NAME_W));
+
+        pVersion->wMajor = 0;
+        pVersion->wMinor = 0;
+        pVersion->wBuild = 0;
+        pVersion->wRevision = 0;
+
+        *pdwDbiTimeStamp = 0;
+        *pdwDbiSizeOfImage = 0;
+        *pdwDacTimeStamp = 0;
+        *pdwDacSizeOfImage = 0;
+
+        return S_OK;
+    }
+}
+
+// Formats the long name for DAC
+HRESULT CLRDebuggingImpl::FormatLongDacModuleName(_Inout_updates_z_(cchBuffer) WCHAR * pBuffer,
+                                                  DWORD cchBuffer,
+                                                  DWORD targetImageFileMachine,
+                                                  VS_FIXEDFILEINFO * pVersion)
+{
+
+#ifndef HOST_WINDOWS
+    _ASSERTE(!"NYI");
+    return E_NOTIMPL;
+#endif
+
+#if defined(HOST_X86)
+    const WCHAR* pHostArch = W("x86");
+#elif defined(HOST_AMD64)
+    const WCHAR* pHostArch = W("amd64");
+#elif defined(HOST_ARM)
+    const WCHAR* pHostArch = W("arm");
+#elif defined(HOST_ARM64)
+    const WCHAR* pHostArch = W("arm64");
+#else
+    _ASSERTE(!"Unknown host arch");
+    return E_NOTIMPL;
+#endif
+
+    const WCHAR* pDacBaseName = NULL;
+    if(m_skuId == CLR_ID_V4_DESKTOP)
+        pDacBaseName = CLR_DAC_MODULE_NAME_W;
+    else if(m_skuId == CLR_ID_CORECLR || m_skuId == CLR_ID_PHONE_CLR || m_skuId == CLR_ID_ONECORE_CLR)
+        pDacBaseName = CORECLR_DAC_MODULE_NAME_W;
+    else
+    {
+        _ASSERTE(!"Unknown SKU id");
+        return E_UNEXPECTED;
+    }
+
+    const WCHAR* pTargetArch = NULL;
+    if(targetImageFileMachine == IMAGE_FILE_MACHINE_I386)
+    {
+        pTargetArch = W("x86");
+    }
+    else if(targetImageFileMachine == IMAGE_FILE_MACHINE_AMD64)
+    {
+        pTargetArch = W("amd64");
+    }
+    else if(targetImageFileMachine == IMAGE_FILE_MACHINE_ARMNT)
+    {
+        pTargetArch = W("arm");
+    }
+    else if(targetImageFileMachine == IMAGE_FILE_MACHINE_ARM64)
+    {
+        pTargetArch = W("arm64");
+    }
+    else
+    {
+        _ASSERTE(!"Unknown target image file machine type");
+        return E_INVALIDARG;
+    }
+
+    const WCHAR* pBuildFlavor = W("");
+    if(pVersion->dwFileFlags & VS_FF_DEBUG)
+    {
+        if(pVersion->dwFileFlags & VS_FF_SPECIALBUILD)
+            pBuildFlavor = W(".dbg");
+        else
+            pBuildFlavor = W(".chk");
+    }
+
+    // WARNING: if you change the formatting make sure you recalculate the maximum
+    // possible size string and verify callers pass a big enough buffer. This doesn't
+    // have to be a tight estimate, just make sure its >= the biggest possible DAC name
+    // and it can be calculated statically
+    DWORD minCchBuffer =
+        (DWORD) wcslen(CLR_DAC_MODULE_NAME_W) + (DWORD) wcslen(CORECLR_DAC_MODULE_NAME_W) + // max name
+        10 + // max host arch
+        10 + // max target arch
+        40 + // max version
+        10 + // max build flavor
+        (DWORD) wcslen(W("name_host_target_version.flavor.dll")) + // max intermediate formatting chars
+        1; // null terminator
+
+    // validate the output buffer is larger than our estimate above
+    _ASSERTE(cchBuffer >= minCchBuffer);
+    if(!(cchBuffer >= minCchBuffer)) return E_INVALIDARG;
+
+    swprintf_s(pBuffer, cchBuffer, W("%s_%s_%s_%u.%u.%u.%02u%s.dll"),
+        pDacBaseName,
+        pHostArch,
+        pTargetArch,
+        pVersion->dwProductVersionMS >> 16,
+        pVersion->dwProductVersionMS & 0xFFFF,
+        pVersion->dwProductVersionLS >> 16,
+        pVersion->dwProductVersionLS & 0xFFFF,
+        pBuildFlavor);
+    return S_OK;
+}
+
+// An implementation of ICLRDebugging::CanUnloadNow
+//
+// Arguments:
+//   hModule - a handle to a module provided earlier by ProvideLibrary
+//
+// Returns:
+//   S_OK if the library is no longer in use and can be unloaded, S_FALSE otherwise
+//
+STDMETHODIMP CLRDebuggingImpl::CanUnloadNow(HMODULE hModule)
+{
+    // In V4 at least we don't support any unloading.
+    HRESULT hr = S_FALSE;
+
+    return hr;
+}
+
+
+
+STDMETHODIMP CLRDebuggingImpl::QueryInterface(REFIID riid, void **ppvObject)
+{
+    HRESULT hr = S_OK;
+
+    if (riid == __uuidof(IUnknown))
+    {
+        IUnknown *pItf = static_cast<IUnknown *>(this);
+        pItf->AddRef();
+        *ppvObject = pItf;
+    }
+    else if (riid == __uuidof(ICLRDebugging))
+    {
+        ICLRDebugging *pItf = static_cast<ICLRDebugging *>(this);
+        pItf->AddRef();
+        *ppvObject = pItf;
+    }
+    else
+        hr = E_NOINTERFACE;
+
+    return hr;
+}
+
+// Standard AddRef implementation
+ULONG CLRDebuggingImpl::AddRef()
+{
+    return InterlockedIncrement(&m_cRef);
+}
+
+// Standard Release implementation.
+ULONG CLRDebuggingImpl::Release()
+{
+    _ASSERTE(m_cRef > 0);
+
+    ULONG cRef = InterlockedDecrement(&m_cRef);
+
+    if (cRef == 0)
+        delete this; // Relies on virtual dtor to work properly.
+
+    return cRef;
+}
diff --git a/src/dbgshim/debugshim.h b/src/dbgshim/debugshim.h
new file mode 100644 (file)
index 0000000..93df463
--- /dev/null
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// debugshim.h
+//
+
+//
+//*****************************************************************************
+
+#ifndef _DEBUG_SHIM_
+#define _DEBUG_SHIM_
+
+#include "cor.h"
+#include "cordebug.h"
+#include <wchar.h>
+#include <metahost.h>
+
+#define CORECLR_DAC_MODULE_NAME_W W("mscordaccore")
+#define CLR_DAC_MODULE_NAME_W W("mscordacwks")
+#define MAIN_DBI_MODULE_NAME_W W("mscordbi")
+
+// forward declaration
+struct ICorDebugDataTarget;
+
+// ICLRDebugging implementation.
+class CLRDebuggingImpl : public ICLRDebugging
+{
+
+public:
+    CLRDebuggingImpl(GUID skuId) : m_cRef(0), m_skuId(skuId)
+    {
+    }
+
+    virtual ~CLRDebuggingImpl() {}
+
+public:
+    // ICLRDebugging methods:
+    STDMETHOD(OpenVirtualProcess(
+        ULONG64 moduleBaseAddress,
+        IUnknown * pDataTarget,
+        ICLRDebuggingLibraryProvider * pLibraryProvider,
+        CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
+        REFIID riidProcess,
+        IUnknown ** ppProcess,
+        CLR_DEBUGGING_VERSION * pVersion,
+        CLR_DEBUGGING_PROCESS_FLAGS * pFlags));
+
+    STDMETHOD(CanUnloadNow(HMODULE hModule));
+
+       //IUnknown methods:
+       STDMETHOD(QueryInterface(
+                REFIID riid,
+                void **ppvObject));
+
+       // Standard AddRef implementation
+       STDMETHOD_(ULONG, AddRef());
+
+       // Standard Release implementation.
+       STDMETHOD_(ULONG, Release());
+
+
+
+private:
+    VOID RetargetDacIfNeeded(DWORD* pdwTimeStamp,
+                             DWORD* pdwSizeOfImage);
+
+    HRESULT GetCLRInfo(ICorDebugDataTarget * pDataTarget,
+                       ULONG64 moduleBaseAddress,
+                       CLR_DEBUGGING_VERSION * pVersion,
+                       DWORD * pdwDbiTimeStamp,
+                       DWORD * pdwDbiSizeOfImage,
+                       _Inout_updates_z_(dwDbiNameCharCount) WCHAR * pDbiName,
+                       DWORD   dwDbiNameCharCount,
+                       DWORD * pdwDacTimeStamp,
+                       DWORD * pdwDacSizeOfImage,
+                       _Inout_updates_z_(dwDacNameCharCount) WCHAR * pDacName,
+                       DWORD   dwDacNameCharCount);
+
+    HRESULT FormatLongDacModuleName(_Inout_updates_z_(cchBuffer) WCHAR * pBuffer,
+                                    DWORD cchBuffer,
+                                    DWORD targetImageFileMachine,
+                                    VS_FIXEDFILEINFO * pVersion);
+
+       volatile LONG m_cRef;
+    GUID m_skuId;
+
+};  // class CLRDebuggingImpl
+
+#endif
diff --git a/src/dbgshim/pkg/Directory.Build.props b/src/dbgshim/pkg/Directory.Build.props
new file mode 100644 (file)
index 0000000..f013850
--- /dev/null
@@ -0,0 +1,43 @@
+<Project>
+  <Import Project="$(MSBuildThisFileDirectory)..\..\Directory.Build.props"/>
+  <PropertyGroup>
+    <IsShipping>true</IsShipping>
+    <NoPackageAnalysis>true</NoPackageAnalysis>
+    <PackageDescription>Internal implementation package not meant for direct consumption. Please do not reference directly.</PackageDescription>
+  </PropertyGroup>
+
+  <Choose>
+    <When Condition="$(OutputRid.StartsWith('win'))">
+      <PropertyGroup>
+        <OsFolderName>Windows_NT</OsFolderName>
+        <ExeSuffix>.exe</ExeSuffix>
+        <LibSuffix>.dll</LibSuffix>
+        <StaticLibSuffix>.lib</StaticLibSuffix>
+        <SymbolsSuffix>.pdb</SymbolsSuffix>
+      </PropertyGroup>
+    </When>
+    <When Condition="$(OutputRid.StartsWith('osx'))">
+      <PropertyGroup>
+        <OsFolderName>OSX</OsFolderName>
+        <LibPrefix>lib</LibPrefix>
+        <LibSuffix>.dylib</LibSuffix>
+        <StaticLibSuffix>.a</StaticLibSuffix>
+        <SymbolsSuffix>.dwarf</SymbolsSuffix>
+      </PropertyGroup>
+    </When>
+    <Otherwise>
+      <PropertyGroup>
+        <OsFolderName>Linux</OsFolderName>
+        <OsFolderName Condition="$(OutputRid.StartsWith('linux-musl'))">Linux-musl</OsFolderName>
+        <LibPrefix>lib</LibPrefix>
+        <LibSuffix>.so</LibSuffix>
+        <StaticLibSuffix>.a</StaticLibSuffix>
+        <SymbolsSuffix>.dbg</SymbolsSuffix>
+      </PropertyGroup>
+    </Otherwise>
+  </Choose>
+
+  <PropertyGroup>
+    <NativeBinDir>$(ArtifactsBinDir)\$(OsFolderName).$(PackageArch).$(Configuration)\</NativeBinDir>
+  </PropertyGroup>
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-arm.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-arm.proj
new file mode 100644 (file)
index 0000000..039146b
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>linux-arm</OutputRid>
+    <PackageArch>arm</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-arm64.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-arm64.proj
new file mode 100644 (file)
index 0000000..bc7268c
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>linux-arm64</OutputRid>
+    <PackageArch>arm64</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-musl-arm64.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-musl-arm64.proj
new file mode 100644 (file)
index 0000000..f0ed0b0
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>linux-musl-x64</OutputRid>
+    <PackageArch>x64</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-musl-x64.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-musl-x64.proj
new file mode 100644 (file)
index 0000000..f0ed0b0
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>linux-musl-x64</OutputRid>
+    <PackageArch>x64</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-x64.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.linux-x64.proj
new file mode 100644 (file)
index 0000000..b68d4f6
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>linux-x64</OutputRid>
+    <PackageArch>x64</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.osx-arm64.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.osx-arm64.proj
new file mode 100644 (file)
index 0000000..1db7896
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>osx-arm64</OutputRid>
+    <PackageArch>arm64</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.osx-x64.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.osx-x64.proj
new file mode 100644 (file)
index 0000000..8e7c9ec
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>osx-x64</OutputRid>
+    <PackageArch>x64</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.proj
new file mode 100644 (file)
index 0000000..13da9be
--- /dev/null
@@ -0,0 +1,26 @@
+<Project Sdk="Microsoft.Build.NoTargets">
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <IsPackable>true</IsPackable>
+    <!-- Reference the outputs for the dependency nodes calculation. -->
+    <NoTargetsDoNotReferenceOutputAssemblies>false</NoTargetsDoNotReferenceOutputAssemblies>
+    <!-- This is a meta package and doesn't contain any libs. -->
+    <NoWarn>$(NoWarn);NU5128</NoWarn>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <!--
+      Listing the runtime specific packages to populate the dependencies section.
+      Not building these references to avoid unintentional Build/Pack invocations.
+    -->
+    <ProjectReference Include="$(MSBuildThisFileDirectory)*.proj" Exclude="$(MSBuildProjectFile)" BuildReference="false" />
+  </ItemGroup>
+
+  <Target Name="PackRidSpecificPackages"
+          AfterTargets="Pack">
+    <MSBuild Targets="Pack"
+          Projects="@(ProjectReference)"
+          Properties="$(TraversalGlobalProperties)" />
+  </Target>
+
+</Project>
\ No newline at end of file
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.props b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.props
new file mode 100644 (file)
index 0000000..045b82e
--- /dev/null
@@ -0,0 +1,34 @@
+<Project Sdk="Microsoft.Build.NoTargets">
+    <PropertyGroup>
+      <TargetFramework>netstandard2.0</TargetFramework>
+      <SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
+      <!-- IncludeBuildOutput needs to be set to true to make NuGet include the passed in debug symbol files. -->
+      <IncludeBuildOutput>false</IncludeBuildOutput>
+      <IncludeSymbols>true</IncludeSymbols>
+      <DebugSymbols>false</DebugSymbols>
+      <DebugType>none</DebugType>
+      <IsPackable>true</IsPackable>
+      <AllowedOutputExtensionsInSymbolsPackageBuildOutputFolder>.pdb;.dbg;.dwarf</AllowedOutputExtensionsInSymbolsPackageBuildOutputFolder>
+      <!-- When KeepNativeSymbols is set, debug symbols are kept in the .so files.  Separate symbol files do not exist that need to be packed. -->
+      <!-- <TargetsForTfmSpecificDebugSymbolsInPackage Condition="'$(KeepNativeSymbols)' != 'true'">$(TargetsForTfmSpecificDebugSymbolsInPackage);AddRuntimeSpecificNativeSymbolToPackage</TargetsForTfmSpecificDebugSymbolsInPackage> -->
+      <UseRuntimePackageDisclaimer>true</UseRuntimePackageDisclaimer>
+      <!-- This is a native package and doesn't contain any ref/lib assets. -->
+      <NoWarn>$(NoWarn);NU5128</NoWarn>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <None Include="$(NativeBinDir)$(LibPrefix)dbgshim$(LibSuffix)"
+            PackagePath="runtimes/$(OutputRid)/native"
+            Pack="true" />
+    </ItemGroup>
+
+    <Target Name="AddRuntimeSpecificNativeSymbolToPackage">
+      <ItemGroup>
+        <TfmSpecificDebugSymbolsFile Include="$(NativeBinDir)$(LibPrefix)dbgshim$(LibSuffix)$(SymbolsSuffix)"
+                                     TargetPath="/runtimes/$(OutputRid)/native"
+                                     TargetFramework="$(TargetFramework)" />
+      </ItemGroup>
+    </Target>
+
+    <Target Name="CreateManifestResourceNames" />
+  </Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-arm.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-arm.proj
new file mode 100644 (file)
index 0000000..a017c11
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>win-arm</OutputRid>
+    <PackageArch>arm</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-arm64.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-arm64.proj
new file mode 100644 (file)
index 0000000..07c9fc3
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>win-arm64</OutputRid>
+    <PackageArch>arm64</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-x64.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-x64.proj
new file mode 100644 (file)
index 0000000..87f3cef
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>win-x64</OutputRid>
+    <PackageArch>x64</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
diff --git a/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-x86.proj b/src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.win-x86.proj
new file mode 100644 (file)
index 0000000..a3699b1
--- /dev/null
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <OutputRid>win-x86</OutputRid>
+    <PackageArch>x86</PackageArch>
+  </PropertyGroup>
+  <Import Project="Microsoft.Diagnostics.DbgShim.props" />
+</Project>
index 360c2fd6ffd76b2436137af1f35053a9df564b2b..677ffb3fe7a60c196043cc3189cef3d524389b72 100644 (file)
@@ -1,7 +1,3 @@
-if(CLR_CMAKE_HOST_UNIX)
-    include_directories(${ROOT_DIR}/src/pal/inc)
-    include_directories(${ROOT_DIR}/src/pal/inc/rt)
-endif(CLR_CMAKE_HOST_UNIX)
 
 set( CORGUIDS_IDL_SOURCES
   cordebug.idl
diff --git a/src/inc/check.h b/src/inc/check.h
new file mode 100644 (file)
index 0000000..c033965
--- /dev/null
@@ -0,0 +1,726 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// Check.h
+//
+
+//
+// Assertion checking infrastructure
+// ---------------------------------------------------------------------------
+
+
+#ifndef CHECK_H_
+#define CHECK_H_
+
+#include "static_assert.h"
+#include "daccess.h"
+#include "unreachable.h"
+
+#ifdef _DEBUG
+
+#ifdef _MSC_VER
+// Make sure we can recurse deep enough for FORCEINLINE
+#pragma inline_recursion(on)
+#pragma inline_depth(16)
+#pragma warning(disable:4714)
+#endif // _MSC_VER
+
+#if !defined(DISABLE_CONTRACTS)
+#define CHECK_INVARIANTS 1
+#define VALIDATE_OBJECTS 1
+#endif
+
+#endif  // _DEBUG
+
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
+#define _DEBUG_IMPL 1
+#endif
+
+#ifdef _DEBUG
+#define DEBUG_ARG(x)  , x
+#else
+#define DEBUG_ARG(x)
+#endif
+
+#define CHECK_STRESS 1
+
+//--------------------------------------------------------------------------------
+// A CHECK is an object which encapsulates a potential assertion
+// failure.  It not only contains the result of the check, but if the check fails,
+// also records information about the condition and call site.
+//
+// CHECK also serves as a holder to prevent recursive CHECKS. These can be
+// particularly common when putting preconditions inside predicates, especially
+// routines called by an invariant.
+//
+// Note that using CHECK is perfectly efficient in a free build - the CHECK becomes
+// a simple string constant pointer (typically either NULL or (LPCSTR)1, although some
+// check failures may include messages)
+//
+// NOTE: you should NEVER use the CHECK class API directly - use the macros below.
+//--------------------------------------------------------------------------------
+
+class SString;
+
+class CHECK
+{
+protected:
+    // On retail, this is a pointer to a string literal, null or (LPCSTR)1.
+    // On debug, this is a pointer to dynamically allocated memory - that
+    // lets us have formatted strings in debug builds.
+    LPCSTR  m_message;
+
+#ifdef _DEBUG
+    LPCSTR  m_condition;
+    LPCSTR  m_file;
+    INT     m_line;
+    LONG    *m_pCount;
+
+    // Keep leakage counters.
+    static  size_t s_cLeakedBytes;
+    static  size_t s_cNumFailures;
+
+    static thread_local LONG t_count;
+#endif
+
+    static BOOL s_neverEnforceAsserts;
+
+public: // !!! NOTE: Called from macros only!!!
+
+    // If we are not in a check, return TRUE and PushCheck; otherwise return FALSE
+    BOOL EnterAssert();
+
+    // Pops check count
+    void LeaveAssert();
+
+    // Just return if we are in a check
+    BOOL IsInAssert();
+
+    // Should we skip enforcing asserts
+    static BOOL EnforceAssert();
+
+    static BOOL EnforceAssert_StaticCheckOnly();
+
+    static void ResetAssert();
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4702) // Disable bogus unreachable code warning
+#endif // _MSC_VER
+    CHECK() : m_message(NULL)
+#ifdef _DEBUG
+              , m_condition (NULL)
+              , m_file(NULL)
+              , m_line(NULL)
+              , m_pCount(NULL)
+#endif
+    {}
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+
+    // Fail records the result of a condition check.  Can take either a
+    // boolean value or another check result
+    BOOL Fail(BOOL condition);
+    BOOL Fail(const CHECK &check);
+
+    // Setup records context info after a failure.
+    void Setup(LPCSTR message DEBUG_ARG(LPCSTR condition) DEBUG_ARG(LPCSTR file) DEBUG_ARG(INT line));
+    static LPCSTR FormatMessage(LPCSTR messageFormat, ...);
+
+    // Trigger triggers the actual check failure.  The trigger may provide a reason
+    // to include in the failure message.
+    void Trigger(LPCSTR reason);
+
+    // Finally, convert to a BOOL to allow just testing the result of a Check function
+    operator BOOL();
+
+    BOOL operator!();
+
+    CHECK &operator()() { return *this; }
+
+    static inline const CHECK OK() {
+        return CHECK();
+    }
+
+    static void SetAssertEnforcement(BOOL value);
+
+  private:
+#ifdef _DEBUG
+    static LPCSTR AllocateDynamicMessage(const SString &s);
+#endif
+};
+
+
+//--------------------------------------------------------------------------------
+// These CHECK macros are the correct way to propagate an assertion.  These
+// routines are designed for use inside "Check" routines.  Such routines may
+// be Invariants, Validate routines, or any other assertional predicates.
+//
+// A Check routine should return a value of type CHECK.
+//
+// It should consist of multiple CHECK or CHECK_MSG statements (along with appropritate
+// control flow) and should end with CHECK_OK() if all other checks pass.
+//
+// It may contain a CONTRACT_CHECK contract, but this is only appropriate if the
+// check is used for non-assertional purposes (otherwise the contract will never execute).
+// Note that CONTRACT_CHECK contracts do not support postconditions.
+//
+// CHECK: Check the given condition, return a CHECK failure if FALSE
+// CHECK_MSG: Same, but include a message paramter if the check fails
+// CHECK_OK: Return a successful check value;
+//--------------------------------------------------------------------------------
+
+#ifdef _DEBUG
+#define DEBUG_ONLY_MESSAGE(msg)     msg
+#else
+// On retail, we don't want to add a bunch of string literals to the image,
+// so we just use the same one everywhere.
+#define DEBUG_ONLY_MESSAGE(msg)     ((LPCSTR)1)
+#endif
+
+#define CHECK_MSG_EX(_condition, _message, _RESULT)                 \
+do                                                                  \
+{                                                                   \
+    CHECK _check;                                                   \
+    if (_check.Fail(_condition))                                    \
+    {                                                               \
+        ENTER_DEBUG_ONLY_CODE;                                      \
+        _check.Setup(DEBUG_ONLY_MESSAGE(_message)                   \
+            DEBUG_ARG(#_condition)                                  \
+            DEBUG_ARG(__FILE__)                                     \
+            DEBUG_ARG(__LINE__));                                   \
+        _RESULT(_check);                                            \
+        LEAVE_DEBUG_ONLY_CODE;                                      \
+    }                                                               \
+} while (0)
+
+#define RETURN_RESULT(r) return r
+
+#define CHECK_MSG(_condition, _message)                             \
+    CHECK_MSG_EX(_condition, _message, RETURN_RESULT)
+
+#define CHECK(_condition)                                           \
+    CHECK_MSG(_condition, "")
+
+#define CHECK_MSGF(_condition, _args)                               \
+    CHECK_MSG(_condition, CHECK::FormatMessage _args)
+
+#define CHECK_FAIL(_message)                                        \
+    CHECK_MSG(FALSE, _message); UNREACHABLE()
+
+#define CHECK_FAILF(_args)                                          \
+    CHECK_MSGF(FALSE, _args); UNREACHABLE()
+
+#define CHECK_OK                                                    \
+    return CHECK::OK()
+
+//--------------------------------------------------------------------------------
+// ASSERT_CHECK is the proper way to trigger a check result.  If the CHECK
+// has failed, the diagnostic assertion routines will fire with appropriate
+// context information.
+//
+// Note that the condition may either be a raw boolean expression or a CHECK result
+// returned from a Check routine.
+//
+// Recursion note: ASSERT_CHECKs are only performed if there is no current check in
+// progress.
+//--------------------------------------------------------------------------------
+
+#ifndef ENTER_DEBUG_ONLY_CODE
+#define ENTER_DEBUG_ONLY_CODE
+#endif
+
+#ifndef LEAVE_DEBUG_ONLY_CODE
+#define LEAVE_DEBUG_ONLY_CODE
+#endif
+
+#define ASSERT_CHECK(_condition, _message, _reason)                 \
+do                                                                  \
+{                                                                   \
+    CHECK _check;                                                   \
+    if (_check.EnterAssert())                                       \
+    {                                                               \
+        ENTER_DEBUG_ONLY_CODE;                                      \
+        if (_check.Fail(_condition))                                \
+        {                                                           \
+            _check.Setup(_message                                   \
+                DEBUG_ARG(#_condition)                              \
+                DEBUG_ARG(__FILE__)                                 \
+                DEBUG_ARG(__LINE__));                               \
+            _check.Trigger(_reason);                                \
+        }                                                           \
+        LEAVE_DEBUG_ONLY_CODE;                                      \
+        _check.LeaveAssert();                                       \
+    }                                                               \
+} while (0)
+
+// ex: ASSERT_CHECKF(1+2==4, "my reason", ("Woah %d", 1+3));
+// note that the double parenthesis, the 'args' param below will include one pair of parens.
+#define ASSERT_CHECKF(_condition, _reason, _args)                   \
+    ASSERT_CHECK(_condition, CHECK::FormatMessage _args, _reason)
+
+//--------------------------------------------------------------------------------
+// INVARIANTS are descriptions of conditions which are always true at well defined
+// points of execution.  Invariants may be checked by the caller or callee at any
+// time as paranoia requires.
+//
+// There are really two flavors of invariant.  The "public invariant" describes
+// to the caller invariant behavior about the abstraction which is visible from
+// the public API (and of course it should be expressible in that public API).
+//
+// The "internal invariant" (or representation invariant), on the other hand, is
+// a description of the private implementation of the abstraction, which may examine
+// internal state of the abstraction or use private entry points.
+//
+// Classes with invariants should introduce methods called
+// void Invariant();
+// and
+// void InternalInvariant();
+// to allow invariant checks.
+//--------------------------------------------------------------------------------
+
+#if CHECK_INVARIANTS
+
+template <typename TYPENAME>
+CHECK CheckInvariant(TYPENAME &obj)
+{
+#if defined(_MSC_VER) || defined(__llvm__)
+    __if_exists(TYPENAME::Invariant)
+    {
+        CHECK(obj.Invariant());
+    }
+    __if_exists(TYPENAME::InternalInvariant)
+    {
+        CHECK(obj.InternalInvariant());
+    }
+#endif
+
+    CHECK_OK;
+}
+
+#define CHECK_INVARIANT(o) \
+    ASSERT_CHECK(CheckInvariant(o), NULL, "Invariant failure")
+
+#else
+
+#define CHECK_INVARIANT(o)  do { } while (0)
+
+#endif
+
+//--------------------------------------------------------------------------------
+// VALIDATE is a check to be made on an object type which identifies a pointer as
+// a valid instance of the object, by calling CheckPointer on it.  Normally a null
+// pointer is treated as an error; VALIDATE_NULL (or CheckPointer(o, NULL_OK))
+// may be used when a null pointer is acceptible.
+//
+// In addition to the null/non-null check, a type may provide a specific Check method
+// for more sophisticated identification. In general, the Check method
+// should answer the question
+// "Is this a valid instance of its declared compile-time type?". For instance, if
+// runtype type identification were supported for the type, it should be invoked here.
+//
+// Note that CheckPointer will also check the invariant(s) if appropriate, so the
+// invariants should NOT be explicitly invoked from the Check method.
+//--------------------------------------------------------------------------------
+
+enum IsNullOK
+{
+    NULL_NOT_OK = 0,
+    NULL_OK = 1
+};
+
+#if CHECK_INVARIANTS
+template <typename TYPENAME>
+CHECK CheckPointer(TYPENAME *o, IsNullOK ok = NULL_NOT_OK)
+{
+    if (o == NULL)
+    {
+        CHECK_MSG(ok, "Illegal null pointer");
+    }
+    else
+    {
+#if defined(_MSC_VER) || defined(__llvm__)
+        __if_exists(TYPENAME::Check)
+        {
+            CHECK(o->Check());
+        }
+#endif
+    }
+
+    CHECK_OK;
+}
+
+template <typename TYPENAME>
+CHECK CheckValue(TYPENAME &val)
+{
+#if defined(_MSC_VER) || defined(__llvm__)
+    __if_exists(TYPENAME::Check)
+    {
+        CHECK(val.Check());
+    }
+#endif
+
+    CHECK(CheckInvariant(val));
+
+    CHECK_OK;
+}
+#else // CHECK_INVARIANTS
+
+#ifdef _DEBUG_IMPL
+// Don't defined these functions to be nops for the non-debug
+// build as it may hide important checks
+template <typename TYPENAME>
+CHECK CheckPointer(TYPENAME *o, IsNullOK ok = NULL_NOT_OK)
+{
+    if (o == NULL)
+    {
+        CHECK_MSG(ok, "Illegal null pointer");
+    }
+
+    CHECK_OK;
+}
+
+template <typename TYPENAME>
+CHECK CheckValue(TYPENAME &val)
+{
+    CHECK_OK;
+}
+#endif
+
+#endif  // CHECK_INVARIANTS
+
+#if VALIDATE_OBJECTS
+
+#define VALIDATE(o) \
+    ASSERT_CHECK(CheckPointer(o), "Validation failure")
+#define VALIDATE_NULL(o) \
+    ASSERT_CHECK(CheckPointer(o, NULL_OK), "Validation failure")
+
+#else
+
+#define VALIDATE(o)         do { } while (0)
+#define VALIDATE_NULL(o)    do { } while (0)
+
+#endif
+
+//--------------------------------------------------------------------------------
+// CONSISTENCY_CHECKS are ad-hoc assertions about the expected state of the program
+// at a given time.  A failure in one of these indicates a bug in the code.
+//
+// Note that the condition may either be a raw boolean expression or a CHECK result
+// returned from a Check routine.
+//--------------------------------------------------------------------------------
+
+#define CONSISTENCY_CHECK(_condition) \
+    CONSISTENCY_CHECK_MSG(_condition, "")
+
+#ifdef _DEBUG_IMPL
+
+#define CONSISTENCY_CHECK_MSG(_condition, _message) \
+    ASSERT_CHECK(_condition, _message, "Consistency check failed")
+
+#define CONSISTENCY_CHECK_MSGF(_condition, args) \
+    ASSERT_CHECKF(_condition, "Consistency check failed", args)
+
+#else
+
+#define CONSISTENCY_CHECK_MSG(_condition, _message) do { } while (0)
+#define CONSISTENCY_CHECK_MSGF(_condition, args) do { } while (0)
+
+#endif
+
+//--------------------------------------------------------------------------------
+// SIMPLIFYING_ASSUMPTIONS are workarounds which are placed in the code to allow progress
+// to be made in the case of difficult corner cases.  These should NOT be left in the
+// code; they are really just markers of things which need to be fixed.
+//
+// Note that the condition may either be a raw boolean expression or a CHECK result
+// returned from a Check routine.
+//--------------------------------------------------------------------------------
+
+// Ex usage:
+// SIMPLIFYING_ASSUMPTION(SomeExpression());
+#define SIMPLIFYING_ASSUMPTION(_condition) \
+    SIMPLIFYING_ASSUMPTION_MSG(_condition, "")
+
+
+// Helper for HRs. Will provide formatted message showing the failure code.
+#define SIMPLIFYING_ASSUMPTION_SUCCEEDED(__hr) \
+    { \
+        HRESULT __hr2 = (__hr); \
+        (void)__hr2; \
+        SIMPLIFYING_ASSUMPTION_MSGF(SUCCEEDED(__hr2), ("HRESULT failed.\n Expected success.\n Actual=0x%x\n", __hr2)); \
+    }
+
+#ifdef _DEBUG_IMPL
+
+// Ex usage:
+// SIMPLIFYING_ASSUMPTION_MSG(SUCCEEDED(hr), "It failed!");
+#define SIMPLIFYING_ASSUMPTION_MSG(_condition, _message) \
+    ASSERT_CHECK(_condition, _message, "Unhandled special case detected")
+
+// use a formatted string. Ex usage:
+// SIMPLIFYING_ASSUMPTION_MSGF(SUCCEEDED(hr), ("Woah it failed! 0x%08x", hr));
+#define SIMPLIFYING_ASSUMPTION_MSGF(_condition, args) \
+    ASSERT_CHECKF(_condition, "Unhandled special case detected", args)
+
+#else   // !_DEBUG_IMPL
+
+#define SIMPLIFYING_ASSUMPTION_MSG(_condition, _message)    do { } while (0)
+#define SIMPLIFYING_ASSUMPTION_MSGF(_condition, args)       do { } while (0)
+
+#endif  // !_DEBUG_IMPL
+
+//--------------------------------------------------------------------------------
+// COMPILER_ASSUME_MSG is a statement that tells the compiler to assume the
+// condition is true.  In a checked build these turn into asserts;
+// in a free build they are passed through to the compiler to use in optimization.
+//--------------------------------------------------------------------------------
+
+#if defined(_PREFAST_) || defined(_PREFIX_) || defined(__clang_analyzer__)
+#define COMPILER_ASSUME_MSG(_condition, _message) if (!(_condition)) __UNREACHABLE();
+#define COMPILER_ASSUME_MSGF(_condition, args) if (!(_condition)) __UNREACHABLE();
+#else
+
+#if defined(DACCESS_COMPILE)
+#define COMPILER_ASSUME_MSG(_condition, _message) do { } while (0)
+#define COMPILER_ASSUME_MSGF(_condition, args)    do { } while (0)
+#else
+
+#if defined(_DEBUG)
+#define COMPILER_ASSUME_MSG(_condition, _message) \
+    ASSERT_CHECK(_condition, _message, "Compiler optimization assumption invalid")
+#define COMPILER_ASSUME_MSGF(_condition, args) \
+    ASSERT_CHECKF(_condition, "Compiler optimization assumption invalid", args)
+#else
+#define COMPILER_ASSUME_MSG(_condition, _message) __assume(_condition)
+#define COMPILER_ASSUME_MSGF(_condition, args) __assume(_condition)
+#endif // _DEBUG
+
+#endif // DACCESS_COMPILE
+
+#endif // _PREFAST_ || _PREFIX_
+
+
+#define COMPILER_ASSUME(_condition) \
+    COMPILER_ASSUME_MSG(_condition, "")
+
+
+//--------------------------------------------------------------------------------
+// PREFIX_ASSUME_MSG and PREFAST_ASSUME_MSG are just another name
+// for COMPILER_ASSUME_MSG
+// In a checked build these turn into asserts; in a free build
+// they are passed through to the compiler to use in optimization;
+//  via an __assume(_condition) optimization hint.
+//--------------------------------------------------------------------------------
+
+#define PREFIX_ASSUME_MSG(_condition, _message) \
+    COMPILER_ASSUME_MSG(_condition, _message)
+
+#define PREFIX_ASSUME_MSGF(_condition, args) \
+    COMPILER_ASSUME_MSGF(_condition, args)
+
+#define PREFIX_ASSUME(_condition) \
+    COMPILER_ASSUME_MSG(_condition, "")
+
+#define PREFAST_ASSUME_MSG(_condition, _message) \
+    COMPILER_ASSUME_MSG(_condition, _message)
+
+#define PREFAST_ASSUME_MSGF(_condition, args) \
+    COMPILER_ASSUME_MSGF(_condition, args)
+
+#define PREFAST_ASSUME(_condition) \
+    COMPILER_ASSUME_MSG(_condition, "")
+
+//--------------------------------------------------------------------------------
+// UNREACHABLE points are locations in the code which should not be able to be
+// reached under any circumstances (e.g. a default in a switch which is supposed to
+// cover all cases.).  This macro tells the compiler this, and also embeds a check
+// to make sure it is always true.
+//--------------------------------------------------------------------------------
+
+#define UNREACHABLE() \
+    UNREACHABLE_MSG("")
+
+#ifdef __llvm__
+
+// LLVM complains if a function does not return what it says.
+#define UNREACHABLE_RET() do { UNREACHABLE(); return 0; } while (0)
+#define UNREACHABLE_MSG_RET(_message) UNREACHABLE_MSG(_message); return 0;
+
+#else // __llvm__
+
+#define UNREACHABLE_RET() UNREACHABLE()
+#define UNREACHABLE_MSG_RET(_message) UNREACHABLE_MSG(_message)
+
+#endif // __llvm__ else
+
+#ifdef _DEBUG_IMPL
+
+// Note that the "do { } while (0)" syntax trick here doesn't work, as the compiler
+// gives an error that the while(0) is unreachable code
+#define UNREACHABLE_MSG(_message)                                               \
+{                                                                               \
+    CHECK _check;                                                               \
+    _check.Setup(_message, "<unreachable>", __FILE__, __LINE__);                \
+    _check.Trigger("Reached the \"unreachable\"");                              \
+} __UNREACHABLE()
+
+#else
+
+#define UNREACHABLE_MSG(_message) __UNREACHABLE()
+
+#endif
+
+
+//--------------------------------------------------------------------------------
+// STRESS_CHECK represents a check which is included in a free build
+// @todo: behavior on trigger
+//
+// Note that the condition may either be a raw boolean expression or a CHECK result
+// returned from a Check routine.
+//
+// Since Retail builds don't allow formatted checks, there's no STRESS_CHECK_MSGF.
+//--------------------------------------------------------------------------------
+
+#if CHECK_STRESS
+
+#define STRESS_CHECK(_condition, _message) \
+    ASSERT_CHECK(_condition, _message, "Stress Assertion Failure")
+
+#else
+
+#define STRESS_CHECK(_condition, _message)  do { } while (0)
+
+#endif
+
+//--------------------------------------------------------------------------------
+// CONTRACT_CHECK is used to put contracts on Check function.  Note that it does
+// not support postconditions.
+//--------------------------------------------------------------------------------
+
+#define CONTRACT_CHECK      CONTRACTL
+#define CONTRACT_CHECK_END  CONTRACTL_END
+
+//--------------------------------------------------------------------------------
+// CCHECK is used for Check functions which may fail due to out of memory
+// or other transient failures. These failures should be ignored when doing
+// assertions, but they cannot be ignored when the Check function is used in
+// normal code.
+// @todo: really crufty to have 2 sets of CHECK macros
+//--------------------------------------------------------------------------------
+
+#ifdef _DEBUG
+
+#define CCHECK_START                                                            \
+    {                                                                           \
+        BOOL ___exception = FALSE;                                              \
+        BOOL ___transient = FALSE;                                              \
+        CHECK ___result = CHECK::OK();                                          \
+        EX_TRY {
+
+#define CCHECK_END                                                              \
+        } EX_CATCH {                                                            \
+            if (___result.IsInAssert())                                            \
+            {                                                                   \
+                ___exception = TRUE;                                            \
+                ___transient = GET_EXCEPTION()->IsTransient();                  \
+            }                                                                   \
+            else                                                                \
+                EX_RETHROW;                                                     \
+        } EX_END_CATCH(RethrowTerminalExceptions);                              \
+                                                                                \
+        if (___exception)                                                       \
+        {                                                                       \
+            if (___transient)                                                   \
+                CHECK_OK;                                                       \
+            else                                                                \
+                CHECK_FAIL("Nontransient exception occurred during check");     \
+        }                                                                       \
+        CHECK(___result);                                                       \
+    }
+
+#define CRETURN_RESULT(r) ___result =  r
+
+#define CCHECK_MSG(_condition, _message)                             \
+    CHECK_MSG_EX(_condition, _message, CRETURN_RESULT)
+
+#define CCHECK(_condition)                                           \
+    CCHECK_MSG(_condition, "")
+
+#define CCHECK_MSGF(_condition, _args)                               \
+    CCHECK_MSG(_condition, CHECK::FormatMessage _args)
+
+#define CCHECK_FAIL(_message)                                        \
+    CCHECK_MSG(FALSE, _message); UNREACHABLE()
+
+#define CCHECK_FAILF(_args)                                          \
+    CCHECK_MSGF(FALSE, _args); UNREACHABLE()
+
+#else // _DEBUG
+
+#define CCHECK_START
+#define CCHECK_END
+
+#define CCHECK          CHECK
+#define CCHECK_MSG      CHECK_MSG
+#define CCHECK_MSGF     CHECK_MSGF
+#define CCHECK_FAIL     CHECK_FAIL
+#define CCHECK_FAILF    CHECK_FAILF
+
+#endif
+
+
+
+//--------------------------------------------------------------------------------
+// Common base level checks
+//--------------------------------------------------------------------------------
+
+CHECK CheckAlignment(UINT alignment);
+
+CHECK CheckAligned(UINT value, UINT alignment);
+#if defined(_MSC_VER)
+CHECK CheckAligned(ULONG value, UINT alignment);
+#endif
+CHECK CheckAligned(UINT64 value, UINT alignment);
+CHECK CheckAligned(const void *address, UINT alignment);
+
+CHECK CheckOverflow(UINT value1, UINT value2);
+#if defined(_MSC_VER)
+CHECK CheckOverflow(ULONG value1, ULONG value2);
+#endif
+CHECK CheckOverflow(UINT64 value1, UINT64 value2);
+CHECK CheckOverflow(PTR_CVOID address, UINT offset);
+#if defined(_MSC_VER)
+CHECK CheckOverflow(const void *address, ULONG offset);
+#endif
+CHECK CheckOverflow(const void *address, UINT64 offset);
+
+CHECK CheckUnderflow(UINT value1, UINT value2);
+#if defined(_MSC_VER)
+CHECK CheckUnderflow(ULONG value1, ULONG value2);
+#endif
+CHECK CheckUnderflow(UINT64 value1, UINT64 value2);
+CHECK CheckUnderflow(const void *address, UINT offset);
+#if defined(_MSC_VER)
+CHECK CheckUnderflow(const void *address, ULONG offset);
+#endif
+CHECK CheckUnderflow(const void *address, UINT64 offset);
+CHECK CheckUnderflow(const void *address, void *address2);
+
+CHECK CheckZeroedMemory(const void *memory, SIZE_T size);
+
+// These include overflow checks
+CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset);
+CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset, UINT32 size);
+
+void WINAPI ReleaseCheckTls(LPVOID pTlsData);
+
+// ================================================================================
+// Inline definitions
+// ================================================================================
+
+#include "check.inl"
+
+#endif // CHECK_H_
diff --git a/src/inc/check.inl b/src/inc/check.inl
new file mode 100644 (file)
index 0000000..f234e98
--- /dev/null
@@ -0,0 +1,325 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef CHECK_INL_
+#define CHECK_INL_
+
+#include "check.h"
+#include "clrhost.h"
+#include "debugmacros.h"
+#include "clrtypes.h"
+
+FORCEINLINE BOOL CHECK::EnterAssert()
+{
+    if (s_neverEnforceAsserts)
+        return FALSE;
+
+#ifdef _DEBUG_IMPL
+    m_pCount = &t_count;
+
+    if (!*m_pCount)
+    {
+        *m_pCount = 1;
+        return TRUE;
+    }
+    else
+        return FALSE;
+#else
+    // Don't bother doing recursive checks on a free build, since checks should
+    // be extremely isolated
+    return TRUE;
+#endif
+}
+
+FORCEINLINE void CHECK::LeaveAssert()
+{
+#ifdef _DEBUG_IMPL
+    *m_pCount = 0;
+#endif
+}
+
+FORCEINLINE BOOL CHECK::IsInAssert()
+{
+#ifdef _DEBUG_IMPL
+    if (!m_pCount)
+        m_pCount = &t_count;
+
+    return *m_pCount;
+#else
+    return FALSE;
+#endif
+}
+
+FORCEINLINE BOOL CHECK::EnforceAssert()
+{
+    if (s_neverEnforceAsserts)
+        return FALSE;
+    else
+    {
+        CHECK chk;
+        return !chk.IsInAssert();
+    }
+}
+
+FORCEINLINE void CHECK::ResetAssert()
+{
+    CHECK chk;
+    if (chk.IsInAssert())
+        chk.LeaveAssert();
+}
+
+inline void CHECK::SetAssertEnforcement(BOOL value)
+{
+    s_neverEnforceAsserts = !value;
+}
+
+// Fail records the result of a condition check.  Can take either a
+// boolean value or another check result
+FORCEINLINE BOOL CHECK::Fail(BOOL condition)
+{
+#ifdef _DEBUG
+    if (!condition)
+    {
+        m_condition = NULL;
+        m_file = NULL;
+        m_line = 0;
+    }
+#endif
+    return !condition;
+}
+
+FORCEINLINE BOOL CHECK::Fail(const CHECK &check)
+{
+    m_message = check.m_message;
+#ifdef _DEBUG
+    if (m_message != NULL)
+    {
+        m_condition = check.m_condition;
+        m_file = check.m_file;
+        m_line = check.m_line;
+    }
+#endif
+    return m_message != NULL;
+}
+
+#ifndef _DEBUG
+FORCEINLINE void CHECK::Setup(LPCSTR message)
+{
+    m_message = message;
+}
+
+FORCEINLINE LPCSTR CHECK::FormatMessage(LPCSTR messageFormat, ...)
+{
+    return messageFormat;
+}
+#endif
+
+FORCEINLINE CHECK::operator BOOL ()
+{
+    return m_message == NULL;
+}
+
+FORCEINLINE BOOL CHECK::operator!()
+{
+    return m_message != NULL;
+}
+
+inline CHECK CheckAlignment(UINT alignment)
+{
+    STATIC_CONTRACT_WRAPPER;
+    CHECK((alignment & (alignment-1)) == 0);
+    CHECK_OK;
+}
+
+inline CHECK CheckAligned(UINT value, UINT alignment)
+{
+    STATIC_CONTRACT_WRAPPER;
+    CHECK(AlignmentTrim(value, alignment) == 0);
+    CHECK_OK;
+}
+
+#ifndef HOST_UNIX
+// For Unix this and the previous function get the same types.
+// So, exclude this one.
+inline CHECK CheckAligned(ULONG value, UINT alignment)
+{
+    STATIC_CONTRACT_WRAPPER;
+    CHECK(AlignmentTrim(value, alignment) == 0);
+    CHECK_OK;
+}
+#endif // HOST_UNIX
+
+inline CHECK CheckAligned(UINT64 value, UINT alignment)
+{
+    STATIC_CONTRACT_WRAPPER;
+    CHECK(AlignmentTrim(value, alignment) == 0);
+    CHECK_OK;
+}
+
+inline CHECK CheckAligned(const void *address, UINT alignment)
+{
+    STATIC_CONTRACT_WRAPPER;
+    CHECK(AlignmentTrim((SIZE_T)address, alignment) == 0);
+    CHECK_OK;
+}
+
+inline CHECK CheckOverflow(UINT value1, UINT value2)
+{
+    CHECK(value1 + value2 >= value1);
+    CHECK_OK;
+}
+
+#if defined(_MSC_VER)
+inline CHECK CheckOverflow(ULONG value1, ULONG value2)
+{
+    CHECK(value1 + value2 >= value1);
+    CHECK_OK;
+}
+#endif
+
+inline CHECK CheckOverflow(UINT64 value1, UINT64 value2)
+{
+    CHECK(value1 + value2 >= value1);
+    CHECK_OK;
+}
+
+inline CHECK CheckOverflow(PTR_CVOID address, UINT offset)
+{
+    TADDR targetAddr = dac_cast<TADDR>(address);
+#if POINTER_BITS == 32
+    CHECK((UINT) (SIZE_T)(targetAddr) + offset >= (UINT) (SIZE_T) (targetAddr));
+#else
+    CHECK((UINT64) targetAddr + offset >= (UINT64) targetAddr);
+#endif
+
+    CHECK_OK;
+}
+
+#if defined(_MSC_VER)
+inline CHECK CheckOverflow(const void *address, ULONG offset)
+{
+#if POINTER_BITS == 32
+    CHECK((ULONG) (SIZE_T) address + offset >= (ULONG) (SIZE_T) address);
+#else
+    CHECK((UINT64) address + offset >= (UINT64) address);
+#endif
+
+    CHECK_OK;
+}
+#endif
+
+inline CHECK CheckOverflow(const void *address, UINT64 offset)
+{
+#if POINTER_BITS == 32
+    CHECK(offset >> 32 == 0);
+    CHECK((UINT) (SIZE_T) address + (UINT) offset >= (UINT) (SIZE_T) address);
+#else
+    CHECK((UINT64) address + offset >= (UINT64) address);
+#endif
+
+    CHECK_OK;
+}
+
+
+inline CHECK CheckUnderflow(UINT value1, UINT value2)
+{
+    CHECK(value1 - value2 <= value1);
+
+    CHECK_OK;
+}
+
+#ifndef HOST_UNIX
+// For Unix this and the previous function get the same types.
+// So, exclude this one.
+inline CHECK CheckUnderflow(ULONG value1, ULONG value2)
+{
+    CHECK(value1 - value2 <= value1);
+
+    CHECK_OK;
+}
+#endif // HOST_UNIX
+
+inline CHECK CheckUnderflow(UINT64 value1, UINT64 value2)
+{
+    CHECK(value1 - value2 <= value1);
+
+    CHECK_OK;
+}
+
+inline CHECK CheckUnderflow(const void *address, UINT offset)
+{
+#if POINTER_BITS == 32
+    CHECK((UINT) (SIZE_T) address - offset <= (UINT) (SIZE_T) address);
+#else
+    CHECK((UINT64) address - offset <= (UINT64) address);
+#endif
+
+    CHECK_OK;
+}
+
+#if defined(_MSC_VER)
+inline CHECK CheckUnderflow(const void *address, ULONG offset)
+{
+#if POINTER_BITS == 32
+    CHECK((ULONG) (SIZE_T) address - offset <= (ULONG) (SIZE_T) address);
+#else
+    CHECK((UINT64) address - offset <= (UINT64) address);
+#endif
+
+    CHECK_OK;
+}
+#endif
+
+inline CHECK CheckUnderflow(const void *address, UINT64 offset)
+{
+#if POINTER_BITS == 32
+    CHECK(offset >> 32 == 0);
+    CHECK((UINT) (SIZE_T) address - (UINT) offset <= (UINT) (SIZE_T) address);
+#else
+    CHECK((UINT64) address - offset <= (UINT64) address);
+#endif
+
+    CHECK_OK;
+}
+
+inline CHECK CheckUnderflow(const void *address, void *address2)
+{
+#if POINTER_BITS == 32
+    CHECK((UINT) (SIZE_T) address - (UINT) (SIZE_T) address2 <= (UINT) (SIZE_T) address);
+#else
+    CHECK((UINT64) address - (UINT64) address2 <= (UINT64) address);
+#endif
+
+    CHECK_OK;
+}
+
+inline CHECK CheckZeroedMemory(const void *memory, SIZE_T size)
+{
+    CHECK(CheckOverflow(memory, size));
+
+    BYTE *p = (BYTE *) memory;
+    BYTE *pEnd = p + size;
+
+    while (p < pEnd)
+        CHECK(*p++ == 0);
+
+    CHECK_OK;
+}
+
+inline CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset)
+{
+    CHECK(CheckOverflow(dac_cast<PTR_CVOID>(rangeBase), rangeSize));
+    CHECK(offset <= rangeSize);
+    CHECK_OK;
+}
+
+inline CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset, UINT32 size)
+{
+    CHECK(CheckOverflow(dac_cast<PTR_CVOID>(rangeBase), rangeSize));
+    CHECK(CheckOverflow(offset, size));
+    CHECK(offset + size <= rangeSize);
+    CHECK_OK;
+}
+
+#endif  // CHECK_INL_
+
diff --git a/src/inc/clrhost.h b/src/inc/clrhost.h
new file mode 100644 (file)
index 0000000..d8fe0c5
--- /dev/null
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+//
+
+
+#ifndef __CLRHOST_H__
+#define __CLRHOST_H__
+
+#include "windows.h" // worth to include before mscoree.h so we are guaranteed to pick few definitions
+#ifdef CreateSemaphore
+#undef CreateSemaphore
+#endif
+#include "mscoree.h"
+#include "clrinternal.h"
+#include "switches.h"
+#include "holder.h"
+#include "new.hpp"
+#include "staticcontract.h"
+#include "predeftlsslot.h"
+#include "safemath.h"
+#include "debugreturn.h"
+#include "yieldprocessornormalized.h"
+
+#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
+#define _DEBUG_IMPL 1
+#endif
+
+#define BEGIN_PRESERVE_LAST_ERROR \
+    { \
+        DWORD __dwLastError = ::GetLastError(); \
+        DEBUG_ASSURE_NO_RETURN_BEGIN(PRESERVE_LAST_ERROR); \
+            {
+
+#define END_PRESERVE_LAST_ERROR \
+            } \
+        DEBUG_ASSURE_NO_RETURN_END(PRESERVE_LAST_ERROR); \
+        ::SetLastError(__dwLastError); \
+    }
+
+//
+// TRASH_LASTERROR macro sets bogus last error in debug builds to help find places that fail to save it
+//
+#ifdef _DEBUG
+
+#define LAST_ERROR_TRASH_VALUE 42424 /* = 0xa5b8 */
+
+#define TRASH_LASTERROR \
+    SetLastError(LAST_ERROR_TRASH_VALUE)
+
+#else // _DEBUG
+
+#define TRASH_LASTERROR
+
+#endif // _DEBUG
+
+
+LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
+BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
+SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
+BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
+
+#ifdef HOST_WINDOWS
+HANDLE ClrGetProcessExecutableHeap();
+#endif
+
+#ifdef FAILPOINTS_ENABLED
+extern int RFS_HashStack();
+#endif
+
+// Critical section support for CLR DLLs other than the the EE.
+// Include the header defining each Crst type and its corresponding level (relative rank). This is
+// auto-generated from a tool that takes a high-level description of each Crst type and its dependencies.
+#include "crsttypes.h"
+
+// critical section api
+CRITSEC_COOKIE ClrCreateCriticalSection(CrstType type, CrstFlags flags);
+void ClrDeleteCriticalSection(CRITSEC_COOKIE cookie);
+void ClrEnterCriticalSection(CRITSEC_COOKIE cookie);
+void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie);
+
+// Rather than use the above APIs directly, it is recommended that holder classes
+// be used.  This guarantees that the locks will be vacated when the scope is popped,
+// either on exception or on return.
+
+typedef Holder<CRITSEC_COOKIE, ClrEnterCriticalSection, ClrLeaveCriticalSection, NULL> CRITSEC_Holder;
+
+// Use this holder to manage CRITSEC_COOKIE allocation to ensure it will be released if anything goes wrong
+FORCEINLINE void VoidClrDeleteCriticalSection(CRITSEC_COOKIE cs) { if (cs != NULL) ClrDeleteCriticalSection(cs); }
+typedef Wrapper<CRITSEC_COOKIE, DoNothing<CRITSEC_COOKIE>, VoidClrDeleteCriticalSection, NULL> CRITSEC_AllocationHolder;
+
+DWORD GetClrModulePathName(SString& buffer);
+
+extern thread_local int t_CantAllocCount;
+
+inline void IncCantAllocCount()
+{
+    t_CantAllocCount++;
+}
+
+inline void DecCantAllocCount()
+{
+    t_CantAllocCount--;
+}
+
+class CantAllocHolder
+{
+public:
+    CantAllocHolder ()
+    {
+        IncCantAllocCount ();
+    }
+    ~CantAllocHolder()
+    {
+           DecCantAllocCount ();
+    }
+};
+
+// At places where want to allocate stress log, we need to first check if we are allowed to do so.
+inline bool IsInCantAllocRegion ()
+{
+    return t_CantAllocCount != 0;
+}
+inline BOOL IsInCantAllocStressLogRegion()
+{
+    return t_CantAllocCount != 0;
+}
+
+#endif
diff --git a/src/inc/clrnt.h b/src/inc/clrnt.h
new file mode 100644 (file)
index 0000000..e12c588
--- /dev/null
@@ -0,0 +1,1032 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#ifndef CLRNT_H_
+#define CLRNT_H_
+
+#include "staticcontract.h"
+
+//
+// This file is the result of some changes to the SDK header files.
+// In particular, nt.h and some of its dependencies are no longer
+// available except as "nonship" files.  As a result, this file
+// was created as a simple cut and past of structures and functions
+// from NT that are either not yet documented or have been overlooked
+// as being part of the platform SDK.
+//
+
+//
+// ALL PLATFORMS
+//
+
+#define STATUS_INVALID_PARAMETER_3       ((NTSTATUS)0xC00000F1L)
+#define STATUS_INVALID_PARAMETER_4       ((NTSTATUS)0xC00000F2L)
+#define STATUS_UNSUCCESSFUL              ((NTSTATUS)0xC0000001L)
+#define STATUS_SUCCESS                   ((NTSTATUS)0x00000000L)
+
+#ifndef STATUS_UNWIND
+#define STATUS_UNWIND                    ((NTSTATUS)0x80000027L)
+#endif
+
+#ifndef DBG_PRINTEXCEPTION_C
+#define DBG_PRINTEXCEPTION_C             ((DWORD)0x40010006L)
+#endif
+
+#ifndef STATUS_UNWIND_CONSOLIDATE
+#define STATUS_UNWIND_CONSOLIDATE        ((NTSTATUS)0x80000029L)
+#endif
+
+#ifndef STATUS_LONGJUMP
+#define STATUS_LONGJUMP        ((NTSTATUS)0x80000026L)
+#endif
+
+#ifndef LOCALE_NAME_MAX_LENGTH
+#define LOCALE_NAME_MAX_LENGTH 85
+#endif // !LOCALE_NAME_MAX_LENGTH
+
+#ifndef SUBLANG_CUSTOM_DEFAULT
+#define SUBLANG_CUSTOM_DEFAULT                      0x03    // default custom language/locale
+#define SUBLANG_CUSTOM_UNSPECIFIED                  0x04    // custom language/locale
+#define LOCALE_CUSTOM_DEFAULT                                                 \
+              (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT))
+#define LOCALE_CUSTOM_UNSPECIFIED                                             \
+              (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT))
+#endif // !SUBLANG_CUSTOM_DEFAULT
+
+#ifndef __out_xcount_opt
+#define __out_xcount_opt(var) __out
+#endif
+
+#ifndef __encoded_pointer
+#define __encoded_pointer
+#endif
+
+#ifndef __range
+#define __range(min, man)
+#endif
+
+#ifndef __field_bcount
+#define __field_bcount(size)
+#endif
+
+#ifndef __field_ecount_opt
+#define __field_ecount_opt(nFields)
+#endif
+
+#ifndef __field_ecount
+#define __field_ecount(EHCount)
+#endif
+
+#undef _Ret_bytecap_
+#define _Ret_bytecap_(_Size)
+
+#ifndef NT_SUCCESS
+#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
+#endif
+
+#define ARGUMENT_PRESENT(ArgumentPointer)    (\
+    (CHAR *)(ArgumentPointer) != (CHAR *)(NULL) )
+
+#define EXCEPTION_CHAIN_END ((PEXCEPTION_REGISTRATION_RECORD)-1)
+
+typedef signed char SCHAR;
+typedef SCHAR *PSCHAR;
+typedef LONG NTSTATUS;
+
+#ifndef HOST_UNIX
+
+#define TLS_MINIMUM_AVAILABLE 64    // winnt
+#define TLS_EXPANSION_SLOTS   1024
+
+typedef enum _THREADINFOCLASS {
+    ThreadBasicInformation,
+    ThreadTimes,
+    ThreadPriority,
+    ThreadBasePriority,
+    ThreadAffinityMask,
+    ThreadImpersonationToken,
+    ThreadDescriptorTableEntry,
+    ThreadEnableAlignmentFaultFixup,
+    ThreadEventPair_Reusable,
+    ThreadQuerySetWin32StartAddress,
+    ThreadZeroTlsCell,
+    ThreadPerformanceCount,
+    ThreadAmILastThread,
+    ThreadIdealProcessor,
+    ThreadPriorityBoost,
+    ThreadSetTlsArrayAddress,
+    ThreadIsIoPending,
+    ThreadHideFromDebugger,
+    ThreadBreakOnTermination,
+    MaxThreadInfoClass
+    } THREADINFOCLASS;
+
+typedef enum _SYSTEM_INFORMATION_CLASS {
+    SystemBasicInformation,
+    SystemProcessorInformation,             // obsolete...delete
+    SystemPerformanceInformation,
+    SystemTimeOfDayInformation,
+    SystemPathInformation,
+    SystemProcessInformation,
+    SystemCallCountInformation,
+    SystemDeviceInformation,
+    SystemProcessorPerformanceInformation,
+    SystemFlagsInformation,
+    SystemCallTimeInformation,
+    SystemModuleInformation,
+    SystemLocksInformation,
+    SystemStackTraceInformation,
+    SystemPagedPoolInformation,
+    SystemNonPagedPoolInformation,
+    SystemHandleInformation,
+    SystemObjectInformation,
+    SystemPageFileInformation,
+    SystemVdmInstemulInformation,
+    SystemVdmBopInformation,
+    SystemFileCacheInformation,
+    SystemPoolTagInformation,
+    SystemInterruptInformation,
+    SystemDpcBehaviorInformation,
+    SystemFullMemoryInformation,
+    SystemLoadGdiDriverInformation,
+    SystemUnloadGdiDriverInformation,
+    SystemTimeAdjustmentInformation,
+    SystemSummaryMemoryInformation,
+    SystemMirrorMemoryInformation,
+    SystemPerformanceTraceInformation,
+    SystemObsolete0,
+    SystemExceptionInformation,
+    SystemCrashDumpStateInformation,
+    SystemKernelDebuggerInformation,
+    SystemContextSwitchInformation,
+    SystemRegistryQuotaInformation,
+    SystemExtendServiceTableInformation,
+    SystemPrioritySeperation,
+    SystemVerifierAddDriverInformation,
+    SystemVerifierRemoveDriverInformation,
+    SystemProcessorIdleInformation,
+    SystemLegacyDriverInformation,
+    SystemCurrentTimeZoneInformation,
+    SystemLookasideInformation,
+    SystemTimeSlipNotification,
+    SystemSessionCreate,
+    SystemSessionDetach,
+    SystemSessionInformation,
+    SystemRangeStartInformation,
+    SystemVerifierInformation,
+    SystemVerifierThunkExtend,
+    SystemSessionProcessInformation,
+    SystemLoadGdiDriverInSystemSpace,
+    SystemNumaProcessorMap,
+    SystemPrefetcherInformation,
+    SystemExtendedProcessInformation,
+    SystemRecommendedSharedDataAlignment,
+    SystemComPlusPackage,
+    SystemNumaAvailableMemory,
+    SystemProcessorPowerInformation,
+    SystemEmulationBasicInformation,
+    SystemEmulationProcessorInformation,
+    SystemExtendedHandleInformation,
+    SystemLostDelayedWriteInformation
+} SYSTEM_INFORMATION_CLASS;
+
+typedef enum _EVENT_INFORMATION_CLASS {
+    EventBasicInformation
+    } EVENT_INFORMATION_CLASS;
+
+typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
+    LARGE_INTEGER IdleTime;
+    LARGE_INTEGER KernelTime;
+    LARGE_INTEGER UserTime;
+    LARGE_INTEGER DpcTime;          // DEVL only
+    LARGE_INTEGER InterruptTime;    // DEVL only
+    ULONG InterruptCount;
+} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
+
+typedef enum _EVENT_TYPE {
+    NotificationEvent,
+    SynchronizationEvent
+    } EVENT_TYPE;
+
+typedef struct _EVENT_BASIC_INFORMATION {
+    EVENT_TYPE EventType;
+    LONG EventState;
+} EVENT_BASIC_INFORMATION, *PEVENT_BASIC_INFORMATION;
+
+#define RTL_MEG                   (1024UL * 1024UL)
+#define RTLP_IMAGE_MAX_DOS_HEADER ( 256UL * RTL_MEG)
+
+typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION {
+    BOOLEAN KernelDebuggerEnabled;
+    BOOLEAN KernelDebuggerNotPresent;
+} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;
+
+typedef struct _STRING {
+    USHORT Length;
+    USHORT MaximumLength;
+#ifdef MIDL_PASS
+    [size_is(MaximumLength), length_is(Length) ]
+#endif // MIDL_PASS
+    PCHAR Buffer;
+} STRING;
+typedef STRING *PSTRING;
+
+typedef STRING ANSI_STRING;
+typedef PSTRING PANSI_STRING;
+
+typedef STRING OEM_STRING;
+typedef PSTRING POEM_STRING;
+typedef CONST STRING* PCOEM_STRING;
+
+typedef struct _UNICODE_STRING {
+    USHORT Length;
+    USHORT MaximumLength;
+#ifdef MIDL_PASS
+    [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
+#else // MIDL_PASS
+    PWSTR  Buffer;
+#endif // MIDL_PASS
+} UNICODE_STRING;
+typedef UNICODE_STRING *PUNICODE_STRING;
+typedef const UNICODE_STRING *PCUNICODE_STRING;
+#define UNICODE_NULL ((WCHAR)0) // winnt
+
+typedef struct _STRING32 {
+    USHORT   Length;
+    USHORT   MaximumLength;
+    ULONG  Buffer;
+} STRING32;
+typedef STRING32 *PSTRING32;
+
+typedef STRING32 UNICODE_STRING32;
+typedef UNICODE_STRING32 *PUNICODE_STRING32;
+
+typedef STRING32 ANSI_STRING32;
+typedef ANSI_STRING32 *PANSI_STRING32;
+
+
+typedef struct _STRING64 {
+    USHORT   Length;
+    USHORT   MaximumLength;
+    ULONGLONG  Buffer;
+} STRING64;
+typedef STRING64 *PSTRING64;
+
+typedef STRING64 UNICODE_STRING64;
+typedef UNICODE_STRING64 *PUNICODE_STRING64;
+
+typedef STRING64 ANSI_STRING64;
+typedef ANSI_STRING64 *PANSI_STRING64;
+
+#define GDI_HANDLE_BUFFER_SIZE32  34
+#define GDI_HANDLE_BUFFER_SIZE64  60
+
+#if !defined(TARGET_AMD64)
+#define GDI_HANDLE_BUFFER_SIZE      GDI_HANDLE_BUFFER_SIZE32
+#else
+#define GDI_HANDLE_BUFFER_SIZE      GDI_HANDLE_BUFFER_SIZE64
+#endif
+
+typedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32];
+typedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64];
+typedef ULONG GDI_HANDLE_BUFFER  [GDI_HANDLE_BUFFER_SIZE  ];
+
+
+typedef struct _PEB_LDR_DATA {
+    ULONG Length;
+    BOOLEAN Initialized;
+    HANDLE SsHandle;
+    LIST_ENTRY InLoadOrderModuleList;
+    LIST_ENTRY InMemoryOrderModuleList;
+    LIST_ENTRY InInitializationOrderModuleList;
+    PVOID EntryInProgress;
+} PEB_LDR_DATA, *PPEB_LDR_DATA;
+
+typedef struct _PEB_FREE_BLOCK {
+    struct _PEB_FREE_BLOCK *Next;
+    ULONG Size;
+} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;
+
+typedef PVOID* PPVOID;
+
+typedef
+VOID
+(*PPS_POST_PROCESS_INIT_ROUTINE) (
+    VOID
+    );
+
+typedef struct _LDR_DATA_TABLE_ENTRY {
+    LIST_ENTRY InLoadOrderLinks;
+    LIST_ENTRY InMemoryOrderLinks;
+    LIST_ENTRY InInitializationOrderLinks;
+    PVOID DllBase;
+    PVOID EntryPoint;
+    ULONG SizeOfImage;
+    UNICODE_STRING FullDllName;
+    UNICODE_STRING BaseDllName;
+    ULONG Flags;
+    USHORT LoadCount;
+    USHORT TlsIndex;
+    union _foo {
+        LIST_ENTRY HashLinks;
+        struct _bar {
+            PVOID SectionPointer;
+            ULONG CheckSum;
+        };
+    };
+    union _foo2 {
+        struct _bar2 {
+            ULONG TimeDateStamp;
+        };
+        struct _bar3 {
+            PVOID LoadedImports;
+        };
+    };
+    PVOID EntryPointActivationContext;
+} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
+
+#define TYPE3(arg) arg
+
+typedef struct _PEB {
+    BOOLEAN InheritedAddressSpace;      // These four fields cannot change unless the
+    BOOLEAN ReadImageFileExecOptions;   //
+    BOOLEAN BeingDebugged;              //
+    BOOLEAN SpareBool;                  //
+    HANDLE Mutant;                      // INITIAL_PEB structure is also updated.
+
+    PVOID ImageBaseAddress;
+    PPEB_LDR_DATA Ldr;
+    TYPE3(struct _RTL_USER_PROCESS_PARAMETERS*) ProcessParameters;
+    PVOID SubSystemData;
+    PVOID ProcessHeap;
+    TYPE3(struct _RTL_CRITICAL_SECTION*) FastPebLock;
+    PVOID FastPebLockRoutine;
+    PVOID FastPebUnlockRoutine;
+    ULONG EnvironmentUpdateCount;
+    PVOID KernelCallbackTable;
+    ULONG SystemReserved[1];
+
+    struct _foo {
+        ULONG ExecuteOptions : 2;
+        ULONG SpareBits : 30;
+    };
+
+
+    PPEB_FREE_BLOCK FreeList;
+    ULONG TlsExpansionCounter;
+    PVOID TlsBitmap;
+    ULONG TlsBitmapBits[2];         // TLS_MINIMUM_AVAILABLE bits
+    PVOID ReadOnlySharedMemoryBase;
+    PVOID ReadOnlySharedMemoryHeap;
+    PPVOID ReadOnlyStaticServerData;
+    PVOID AnsiCodePageData;
+    PVOID OemCodePageData;
+    PVOID UnicodeCaseTableData;
+
+    //
+    // Useful information for LdrpInitialize
+    ULONG NumberOfProcessors;
+    ULONG NtGlobalFlag;
+
+    //
+    // Passed up from MmCreatePeb from Session Manager registry key
+    //
+
+    LARGE_INTEGER CriticalSectionTimeout;
+    SIZE_T HeapSegmentReserve;
+    SIZE_T HeapSegmentCommit;
+    SIZE_T HeapDeCommitTotalFreeThreshold;
+    SIZE_T HeapDeCommitFreeBlockThreshold;
+
+    //
+    // Where heap manager keeps track of all heaps created for a process
+    // Fields initialized by MmCreatePeb.  ProcessHeaps is initialized
+    // to point to the first free byte after the PEB and MaximumNumberOfHeaps
+    // is computed from the page size used to hold the PEB, less the fixed
+    // size of this data structure.
+    //
+
+    ULONG NumberOfHeaps;
+    ULONG MaximumNumberOfHeaps;
+    PPVOID ProcessHeaps;
+
+    //
+    //
+    PVOID GdiSharedHandleTable;
+    PVOID ProcessStarterHelper;
+    ULONG GdiDCAttributeList;
+    PVOID LoaderLock;
+
+    //
+    // Following fields filled in by MmCreatePeb from system values and/or
+    // image header.
+    //
+
+    ULONG OSMajorVersion;
+    ULONG OSMinorVersion;
+    USHORT OSBuildNumber;
+    USHORT OSCSDVersion;
+    ULONG OSPlatformId;
+    ULONG ImageSubsystem;
+    ULONG ImageSubsystemMajorVersion;
+    ULONG ImageSubsystemMinorVersion;
+    ULONG_PTR ImageProcessAffinityMask;
+    GDI_HANDLE_BUFFER GdiHandleBuffer;
+    PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
+
+    PVOID TlsExpansionBitmap;
+    ULONG TlsExpansionBitmapBits[32];   // TLS_EXPANSION_SLOTS bits
+
+    //
+    // Id of the Hydra session in which this process is running
+    //
+    ULONG SessionId;
+
+    //
+    // Filled in by LdrpInstallAppcompatBackend
+    //
+    ULARGE_INTEGER AppCompatFlags;
+
+    //
+    // ntuser appcompat flags
+    //
+    ULARGE_INTEGER AppCompatFlagsUser;
+
+    //
+    // Filled in by LdrpInstallAppcompatBackend
+    //
+    PVOID pShimData;
+
+    //
+    // Filled in by LdrQueryImageFileExecutionOptions
+    //
+    PVOID AppCompatInfo;
+
+    //
+    // Used by GetVersionExW as the szCSDVersion string
+    //
+    UNICODE_STRING CSDVersion;
+
+    //
+    // Fusion stuff
+    //
+    PVOID ActivationContextData;
+    PVOID ProcessAssemblyStorageMap;
+    PVOID SystemDefaultActivationContextData;
+    PVOID SystemAssemblyStorageMap;
+
+    //
+    // Enforced minimum initial commit stack
+    //
+    SIZE_T MinimumStackCommit;
+
+} PEB, *PPEB;
+
+#define ACTIVATION_CONTEXT_STACK_FLAG_QUERIES_DISABLED (0x00000001)
+
+typedef struct _ACTIVATION_CONTEXT_STACK {
+    ULONG Flags;
+    ULONG NextCookieSequenceNumber;
+    PVOID ActiveFrame;
+    LIST_ENTRY FrameListCache;
+
+#if NT_SXS_PERF_COUNTERS_ENABLED
+    struct _ACTIVATION_CONTEXT_STACK_PERF_COUNTERS {
+        ULONGLONG Activations;
+        ULONGLONG ActivationCycles;
+        ULONGLONG Deactivations;
+        ULONGLONG DeactivationCycles;
+    } Counters;
+#endif // NT_SXS_PERF_COUNTERS_ENABLED
+} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK;
+
+typedef const ACTIVATION_CONTEXT_STACK *PCACTIVATION_CONTEXT_STACK;
+
+#define TEB_ACTIVE_FRAME_CONTEXT_FLAG_EXTENDED (0x00000001)
+
+typedef struct _TEB_ACTIVE_FRAME_CONTEXT {
+    ULONG Flags;
+    PCSTR FrameName;
+} TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT;
+
+typedef const struct _TEB_ACTIVE_FRAME_CONTEXT *PCTEB_ACTIVE_FRAME_CONTEXT;
+
+typedef struct _TEB_ACTIVE_FRAME_CONTEXT_EX {
+    TEB_ACTIVE_FRAME_CONTEXT BasicContext;
+    PCSTR SourceLocation; // e.g. "Z:\foo\bar\baz.c"
+} TEB_ACTIVE_FRAME_CONTEXT_EX, *PTEB_ACTIVE_FRAME_CONTEXT_EX;
+
+typedef const struct _TEB_ACTIVE_FRAME_CONTEXT_EX *PCTEB_ACTIVE_FRAME_CONTEXT_EX;
+
+#define TEB_ACTIVE_FRAME_FLAG_EXTENDED (0x00000001)
+
+typedef struct _TEB_ACTIVE_FRAME {
+    ULONG Flags;
+    TYPE3(struct _TEB_ACTIVE_FRAME*) Previous;
+    PCTEB_ACTIVE_FRAME_CONTEXT Context;
+} TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME;
+
+typedef const struct _TEB_ACTIVE_FRAME *PCTEB_ACTIVE_FRAME;
+
+typedef struct _TEB_ACTIVE_FRAME_EX {
+    TEB_ACTIVE_FRAME BasicFrame;
+    PVOID ExtensionIdentifier; // use address of your DLL Main or something unique to your mapping in the address space
+} TEB_ACTIVE_FRAME_EX, *PTEB_ACTIVE_FRAME_EX;
+
+typedef const struct _TEB_ACTIVE_FRAME_EX *PCTEB_ACTIVE_FRAME_EX;
+
+typedef struct _CLIENT_ID {
+    HANDLE UniqueProcess;
+    HANDLE UniqueThread;
+} CLIENT_ID;
+typedef CLIENT_ID *PCLIENT_ID;
+
+#define GDI_BATCH_BUFFER_SIZE 310
+
+typedef struct _GDI_TEB_BATCH {
+    ULONG    Offset;
+    ULONG_PTR HDC;
+    ULONG    Buffer[GDI_BATCH_BUFFER_SIZE];
+} GDI_TEB_BATCH,*PGDI_TEB_BATCH;
+
+typedef struct _Wx86ThreadState {
+    PULONG  CallBx86Eip;
+    PVOID   DeallocationCpu;
+    BOOLEAN UseKnownWx86Dll;
+    char    OleStubInvoked;
+} WX86THREAD, *PWX86THREAD;
+
+#define STATIC_UNICODE_BUFFER_LENGTH 261
+#define WIN32_CLIENT_INFO_LENGTH 62
+
+typedef struct _PEB* PPEB;
+
+typedef struct _TEB {
+    NT_TIB NtTib;
+    PVOID  EnvironmentPointer;
+    CLIENT_ID ClientId;
+    PVOID ActiveRpcHandle;
+    PVOID ThreadLocalStoragePointer;
+#if defined(PEBTEB_BITS)
+    PVOID ProcessEnvironmentBlock;
+#else
+    PPEB ProcessEnvironmentBlock;
+#endif
+    ULONG LastErrorValue;
+    ULONG CountOfOwnedCriticalSections;
+    PVOID CsrClientThread;
+    PVOID Win32ThreadInfo;          // PtiCurrent
+    ULONG User32Reserved[26];       // user32.dll items
+    ULONG UserReserved[5];          // Winsrv SwitchStack
+    PVOID WOW32Reserved;            // used by WOW
+    LCID CurrentLocale;
+    ULONG FpSoftwareStatusRegister; // offset known by outsiders!
+    PVOID SystemReserved1[54];      // Used by FP emulator
+    NTSTATUS ExceptionCode;         // for RaiseUserException
+    ACTIVATION_CONTEXT_STACK ActivationContextStack;   // Fusion activation stack
+    // sizeof(PVOID) is a way to express processor-dependence, more generally than #ifdef HOST_64BIT
+    UCHAR SpareBytes1[48 - sizeof(PVOID) - sizeof(ACTIVATION_CONTEXT_STACK)];
+    GDI_TEB_BATCH GdiTebBatch;      // Gdi batching
+    CLIENT_ID RealClientId;
+    HANDLE GdiCachedProcessHandle;
+    ULONG GdiClientPID;
+    ULONG GdiClientTID;
+    PVOID GdiThreadLocalInfo;
+    ULONG_PTR Win32ClientInfo[WIN32_CLIENT_INFO_LENGTH]; // User32 Client Info
+    PVOID glDispatchTable[233];     // OpenGL
+    ULONG_PTR glReserved1[29];      // OpenGL
+    PVOID glReserved2;              // OpenGL
+    PVOID glSectionInfo;            // OpenGL
+    PVOID glSection;                // OpenGL
+    PVOID glTable;                  // OpenGL
+    PVOID glCurrentRC;              // OpenGL
+    PVOID glContext;                // OpenGL
+    ULONG LastStatusValue;
+    UNICODE_STRING StaticUnicodeString;
+    WCHAR StaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
+    PVOID DeallocationStack;
+    PVOID TlsSlots[TLS_MINIMUM_AVAILABLE];
+    LIST_ENTRY TlsLinks;
+    PVOID Vdm;
+    PVOID ReservedForNtRpc;
+    PVOID DbgSsReserved[2];
+    ULONG HardErrorsAreDisabled;
+    PVOID Instrumentation[16];
+    PVOID WinSockData;              // WinSock
+    ULONG GdiBatchCount;
+    BOOLEAN InDbgPrint;
+    BOOLEAN FreeStackOnTermination;
+    BOOLEAN HasFiberData;
+    BOOLEAN IdealProcessor;
+    ULONG Spare3;
+    PVOID ReservedForPerf;
+    PVOID ReservedForOle;
+    ULONG WaitingOnLoaderLock;
+    WX86THREAD Wx86Thread;
+    PPVOID TlsExpansionSlots;
+    LCID ImpersonationLocale;       // Current locale of impersonated user
+    ULONG IsImpersonating;          // Thread impersonation status
+    PVOID NlsCache;                 // NLS thread cache
+    PVOID pShimData;                // Per thread data used in the shim
+    ULONG HeapVirtualAffinity;
+    HANDLE CurrentTransactionHandle;// reserved for TxF transaction context
+    PTEB_ACTIVE_FRAME ActiveFrame;
+} TEB;
+typedef TEB *PTEB;
+
+typedef struct _CURDIR {
+    UNICODE_STRING DosPath;
+    HANDLE Handle;
+} CURDIR, *PCURDIR;
+
+#define RTL_USER_PROC_CURDIR_CLOSE      0x00000002
+#define RTL_USER_PROC_CURDIR_INHERIT    0x00000003
+
+typedef struct _RTL_DRIVE_LETTER_CURDIR {
+    USHORT Flags;
+    USHORT Length;
+    ULONG TimeStamp;
+    STRING DosPath;
+} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
+
+
+#define RTL_MAX_DRIVE_LETTERS 32
+#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001
+
+typedef struct _RTL_USER_PROCESS_PARAMETERS {
+    ULONG MaximumLength;
+    ULONG Length;
+
+    ULONG Flags;
+    ULONG DebugFlags;
+
+    HANDLE ConsoleHandle;
+    ULONG  ConsoleFlags;
+    HANDLE StandardInput;
+    HANDLE StandardOutput;
+    HANDLE StandardError;
+
+    CURDIR CurrentDirectory;        // ProcessParameters
+    UNICODE_STRING DllPath;         // ProcessParameters
+    UNICODE_STRING ImagePathName;   // ProcessParameters
+    UNICODE_STRING CommandLine;     // ProcessParameters
+    PVOID Environment;              // NtAllocateVirtualMemory
+
+    ULONG StartingX;
+    ULONG StartingY;
+    ULONG CountX;
+    ULONG CountY;
+    ULONG CountCharsX;
+    ULONG CountCharsY;
+    ULONG FillAttribute;
+
+    ULONG WindowFlags;
+    ULONG ShowWindowFlags;
+    UNICODE_STRING WindowTitle;     // ProcessParameters
+    UNICODE_STRING DesktopInfo;     // ProcessParameters
+    UNICODE_STRING ShellInfo;       // ProcessParameters
+    UNICODE_STRING RuntimeData;     // ProcessParameters
+    RTL_DRIVE_LETTER_CURDIR CurrentDirectores[ RTL_MAX_DRIVE_LETTERS ];
+} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
+
+
+typedef enum _PROCESSINFOCLASS {
+    ProcessBasicInformation,
+    ProcessQuotaLimits,
+    ProcessIoCounters,
+    ProcessVmCounters,
+    ProcessTimes,
+    ProcessBasePriority,
+    ProcessRaisePriority,
+    ProcessDebugPort,
+    ProcessExceptionPort,
+    ProcessAccessToken,
+    ProcessLdtInformation,
+    ProcessLdtSize,
+    ProcessDefaultHardErrorMode,
+    ProcessIoPortHandlers,          // Note: this is kernel mode only
+    ProcessPooledUsageAndLimits,
+    ProcessWorkingSetWatch,
+    ProcessUserModeIOPL,
+    ProcessEnableAlignmentFaultFixup,
+    ProcessPriorityClass,
+    ProcessWx86Information,
+    ProcessHandleCount,
+    ProcessAffinityMask,
+    ProcessPriorityBoost,
+    ProcessDeviceMap,
+    ProcessSessionInformation,
+    ProcessForegroundInformation,
+    ProcessWow64Information,
+    ProcessImageFileName,
+    ProcessLUIDDeviceMapsEnabled,
+    ProcessBreakOnTermination,
+    ProcessDebugObjectHandle,
+    ProcessDebugFlags,
+    ProcessHandleTracing,
+    MaxProcessInfoClass             // MaxProcessInfoClass should always be the last enum
+    } PROCESSINFOCLASS;
+
+
+typedef struct _VM_COUNTERS {
+    SIZE_T PeakVirtualSize;
+    SIZE_T VirtualSize;
+    ULONG PageFaultCount;
+    SIZE_T PeakWorkingSetSize;
+    SIZE_T WorkingSetSize;
+    SIZE_T QuotaPeakPagedPoolUsage;
+    SIZE_T QuotaPagedPoolUsage;
+    SIZE_T QuotaPeakNonPagedPoolUsage;
+    SIZE_T QuotaNonPagedPoolUsage;
+    SIZE_T PagefileUsage;
+    SIZE_T PeakPagefileUsage;
+} VM_COUNTERS;
+typedef VM_COUNTERS *PVM_COUNTERS;
+
+#undef TYPE3
+
+#endif // !defined(HOST_UNIX)
+
+#if !defined(TARGET_X86)
+
+typedef enum _FUNCTION_TABLE_TYPE {
+    RF_SORTED,
+    RF_UNSORTED,
+    RF_CALLBACK
+} FUNCTION_TABLE_TYPE;
+
+typedef struct _DYNAMIC_FUNCTION_TABLE {
+    LIST_ENTRY Links;
+    PT_RUNTIME_FUNCTION FunctionTable;
+    LARGE_INTEGER TimeStamp;
+
+#ifdef TARGET_ARM
+    ULONG MinimumAddress;
+    ULONG MaximumAddress;
+    ULONG BaseAddress;
+#else
+    ULONG64 MinimumAddress;
+    ULONG64 MaximumAddress;
+    ULONG64 BaseAddress;
+#endif
+
+    PGET_RUNTIME_FUNCTION_CALLBACK Callback;
+    PVOID Context;
+    PWSTR OutOfProcessCallbackDll;
+    FUNCTION_TABLE_TYPE Type;
+    ULONG EntryCount;
+} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;
+
+#endif // !TARGET_X86
+
+//
+//   AMD64
+//
+#ifdef TARGET_AMD64
+
+#define RUNTIME_FUNCTION__BeginAddress(prf)             (prf)->BeginAddress
+#define RUNTIME_FUNCTION__SetBeginAddress(prf,address)  ((prf)->BeginAddress = (address))
+
+#define RUNTIME_FUNCTION__EndAddress(prf, ImageBase)    (prf)->EndAddress
+
+#define RUNTIME_FUNCTION__GetUnwindInfoAddress(prf) (prf)->UnwindData
+#define RUNTIME_FUNCTION__SetUnwindInfoAddress(prf,address) do { (prf)->UnwindData = (address); } while (0)
+#define OFFSETOF__RUNTIME_FUNCTION__UnwindInfoAddress offsetof(T_RUNTIME_FUNCTION, UnwindData)
+
+#include "win64unwind.h"
+
+typedef
+PEXCEPTION_ROUTINE
+(RtlVirtualUnwindFn) (
+    IN ULONG HandlerType,
+    IN ULONG64 ImageBase,
+    IN ULONG64 ControlPc,
+    IN PT_RUNTIME_FUNCTION FunctionEntry,
+    IN OUT PCONTEXT ContextRecord,
+    OUT PVOID *HandlerData,
+    OUT PULONG64 EstablisherFrame,
+    IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL
+    );
+
+#ifndef HOST_UNIX
+extern RtlVirtualUnwindFn* RtlVirtualUnwind_Unsafe;
+#else // !HOST_UNIX
+PEXCEPTION_ROUTINE
+RtlVirtualUnwind_Unsafe(
+    IN ULONG HandlerType,
+    IN ULONG64 ImageBase,
+    IN ULONG64 ControlPc,
+    IN PT_RUNTIME_FUNCTION FunctionEntry,
+    IN OUT PCONTEXT ContextRecord,
+    OUT PVOID *HandlerData,
+    OUT PULONG64 EstablisherFrame,
+    IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL
+    );
+#endif // !HOST_UNIX
+
+#endif // TARGET_AMD64
+
+//
+//  X86
+//
+
+#ifdef TARGET_X86
+#ifndef TARGET_UNIX
+//
+// x86 ABI does not define RUNTIME_FUNCTION. Define our own to allow unification between x86 and other platforms.
+//
+#ifdef HOST_X86
+typedef struct _RUNTIME_FUNCTION {
+    DWORD BeginAddress;
+    DWORD UnwindData;
+} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
+
+typedef struct _DISPATCHER_CONTEXT {
+    _EXCEPTION_REGISTRATION_RECORD* RegistrationPointer;
+} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
+#endif // HOST_X86
+#endif // !TARGET_UNIX
+
+#define RUNTIME_FUNCTION__BeginAddress(prf)             (prf)->BeginAddress
+#define RUNTIME_FUNCTION__SetBeginAddress(prf,addr)     ((prf)->BeginAddress = (addr))
+
+#ifdef FEATURE_EH_FUNCLETS
+#include "win64unwind.h"
+#include "daccess.h"
+
+FORCEINLINE
+DWORD
+RtlpGetFunctionEndAddress (
+    _In_ PT_RUNTIME_FUNCTION FunctionEntry,
+    _In_ TADDR ImageBase
+    )
+{
+    PTR_UNWIND_INFO pUnwindInfo = (PTR_UNWIND_INFO)(ImageBase + FunctionEntry->UnwindData);
+
+    return FunctionEntry->BeginAddress + pUnwindInfo->FunctionLength;
+}
+
+#define RUNTIME_FUNCTION__EndAddress(prf, ImageBase)   RtlpGetFunctionEndAddress(prf, ImageBase)
+
+#define RUNTIME_FUNCTION__GetUnwindInfoAddress(prf)    (prf)->UnwindData
+#define RUNTIME_FUNCTION__SetUnwindInfoAddress(prf, addr) do { (prf)->UnwindData = (addr); } while(0)
+
+#ifdef HOST_X86
+EXTERN_C
+NTSYSAPI
+PEXCEPTION_ROUTINE
+NTAPI
+RtlVirtualUnwind (
+    _In_ DWORD HandlerType,
+    _In_ DWORD ImageBase,
+    _In_ DWORD ControlPc,
+    _In_ PRUNTIME_FUNCTION FunctionEntry,
+    __inout PT_CONTEXT ContextRecord,
+    _Out_ PVOID *HandlerData,
+    _Out_ PDWORD EstablisherFrame,
+    __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
+    );
+#endif // HOST_X86
+#endif // FEATURE_EH_FUNCLETS
+
+#endif // TARGET_X86
+
+#ifdef TARGET_ARM
+#include "daccess.h"
+
+//
+// Define unwind information flags.
+//
+
+#define UNW_FLAG_NHANDLER               0x0             /* any handler */
+#define UNW_FLAG_EHANDLER               0x1             /* filter handler */
+#define UNW_FLAG_UHANDLER               0x2             /* unwind handler */
+
+// This function returns the length of a function using the new unwind info on arm.
+// Taken from minkernel\ntos\rtl\arm\ntrtlarm.h.
+FORCEINLINE
+ULONG
+RtlpGetFunctionEndAddress (
+    _In_ PT_RUNTIME_FUNCTION FunctionEntry,
+    _In_ TADDR ImageBase
+    )
+{
+    ULONG FunctionLength;
+
+    FunctionLength = FunctionEntry->UnwindData;
+    if ((FunctionLength & 3) != 0) {
+        FunctionLength = (FunctionLength >> 2) & 0x7ff;
+    } else {
+        FunctionLength = *(PTR_ULONG)(ImageBase + FunctionLength) & 0x3ffff;
+    }
+
+    return FunctionEntry->BeginAddress + 2 * FunctionLength;
+}
+
+#define RUNTIME_FUNCTION__BeginAddress(FunctionEntry)               ThumbCodeToDataPointer<DWORD,DWORD>((FunctionEntry)->BeginAddress)
+#define RUNTIME_FUNCTION__SetBeginAddress(FunctionEntry,address)    ((FunctionEntry)->BeginAddress = DataPointerToThumbCode<DWORD,DWORD>(address))
+
+#define RUNTIME_FUNCTION__EndAddress(FunctionEntry, ImageBase)      ThumbCodeToDataPointer<DWORD,DWORD>(RtlpGetFunctionEndAddress(FunctionEntry, ImageBase))
+
+#define RUNTIME_FUNCTION__SetUnwindInfoAddress(prf,address) do { (prf)->UnwindData = (address); } while (0)
+
+typedef struct _UNWIND_INFO {
+    // dummy
+} UNWIND_INFO, *PUNWIND_INFO;
+
+#if defined(HOST_UNIX) || defined(HOST_X86)
+
+EXTERN_C
+NTSYSAPI
+PEXCEPTION_ROUTINE
+NTAPI
+RtlVirtualUnwind (
+    _In_ DWORD HandlerType,
+    _In_ DWORD ImageBase,
+    _In_ DWORD ControlPc,
+    _In_ PT_RUNTIME_FUNCTION FunctionEntry,
+    __inout PT_CONTEXT ContextRecord,
+    _Out_ PVOID *HandlerData,
+    _Out_ PDWORD EstablisherFrame,
+    __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
+    );
+#endif // HOST_UNIX || HOST_X86
+
+#define UNW_FLAG_NHANDLER 0x0
+
+#endif // TARGET_ARM
+
+#ifdef TARGET_ARM64
+#include "daccess.h"
+
+#define UNW_FLAG_NHANDLER               0x0             /* any handler */
+#define UNW_FLAG_EHANDLER               0x1             /* filter handler */
+#define UNW_FLAG_UHANDLER               0x2             /* unwind handler */
+
+// This function returns the RVA of the end of the function (exclusive, so one byte after the actual end)
+// using the unwind info on ARM64. (see ExternalAPIs\Win9CoreSystem\inc\winnt.h)
+FORCEINLINE
+ULONG64
+RtlpGetFunctionEndAddress (
+    _In_ PT_RUNTIME_FUNCTION FunctionEntry,
+    _In_ ULONG64 ImageBase
+    )
+{
+    ULONG64 FunctionLength;
+
+    FunctionLength = FunctionEntry->UnwindData;
+    if ((FunctionLength & 3) != 0) {
+        FunctionLength = (FunctionLength >> 2) & 0x7ff;
+    } else {
+        FunctionLength = *(PTR_ULONG64)(ImageBase + FunctionLength) & 0x3ffff;
+    }
+
+    return FunctionEntry->BeginAddress + 4 * FunctionLength;
+}
+
+#define RUNTIME_FUNCTION__BeginAddress(FunctionEntry)               ((FunctionEntry)->BeginAddress)
+#define RUNTIME_FUNCTION__SetBeginAddress(FunctionEntry,address)    ((FunctionEntry)->BeginAddress = (address))
+
+#define RUNTIME_FUNCTION__EndAddress(FunctionEntry, ImageBase)      (RtlpGetFunctionEndAddress(FunctionEntry, (ULONG64)(ImageBase)))
+
+#define RUNTIME_FUNCTION__SetUnwindInfoAddress(prf,address)         do { (prf)->UnwindData = (address); } while (0)
+
+typedef struct _UNWIND_INFO {
+    // dummy
+} UNWIND_INFO, *PUNWIND_INFO;
+
+EXTERN_C
+NTSYSAPI
+PEXCEPTION_ROUTINE
+NTAPI
+RtlVirtualUnwind(
+    IN ULONG HandlerType,
+    IN ULONG64 ImageBase,
+    IN ULONG64 ControlPc,
+    IN PRUNTIME_FUNCTION FunctionEntry,
+    IN OUT PCONTEXT ContextRecord,
+    OUT PVOID *HandlerData,
+    OUT PULONG64 EstablisherFrame,
+    IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL
+    );
+
+#ifndef IMAGE_FILE_MACHINE_ARM64
+#define IMAGE_FILE_MACHINE_ARM64             0xAA64  // ARM64 Little-Endian
+#endif
+
+#ifndef IMAGE_REL_ARM64_BRANCH26
+#define IMAGE_REL_ARM64_BRANCH26        0x0003  // 26 bit offset << 2 & sign ext. for B & BL
+#endif
+
+#ifndef IMAGE_REL_ARM64_PAGEBASE_REL21
+#define IMAGE_REL_ARM64_PAGEBASE_REL21  0x0004  // ADRP 21 bit PC-relative page address
+#endif
+
+#ifndef IMAGE_REL_ARM64_PAGEOFFSET_12A
+#define IMAGE_REL_ARM64_PAGEOFFSET_12A  0x0006  // ADD 12 bit page offset
+#endif
+
+#endif
+
+#endif  // CLRNT_H_
diff --git a/src/inc/clrprivappxhosting.idl b/src/inc/clrprivappxhosting.idl
deleted file mode 100644 (file)
index 04a4cf9..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-import "unknwn.idl";
-
-// Forward declarations
-interface ICLRPrivAppXDomain;
-interface ICLRPrivAppXRuntime;
-
-/**************************************************************************************
- ** ICLRPrivAppXRuntime
- **************************************************************************************/
-[
-    uuid(6D2DF5A4-FA3A-4481-8BA0-0422FD21720F), 
-    version(1.0),
-    local
-] 
-interface ICLRPrivAppXRuntime : IUnknown
-{
-    /**********************************************************************************
-     ** Use to create and initialize the AppX domain. Should only be called once; all
-     ** subsequent calls will fail. Thread safe.
-     **
-     ** wzFriendlyName - the domain friendly name.
-     **********************************************************************************/
-    HRESULT InitializeAppXDomain(
-        [in]  LPCWSTR  wzFriendlyName);
-
-    /**********************************************************************************
-     ** Use to retrieve the AppX domain. InitializeAppXDomain must have been
-     ** successfully called previously. May be called multiple times. Thread safe.
-     **
-     ** riidDomain - the IID of the interface to be returned in ppvDomain.
-     ** ppIAppXDomain - receives the ICLRPrivAppXDomain interface.
-     **********************************************************************************/
-    HRESULT GetAppXDomain(
-        [in]  REFIID   riidDomain,
-        [out] LPVOID * ppvDomain);
-}
-
-/**************************************************************************************
- ** ICLRPrivAppXDomain
- **************************************************************************************/
-[
-    uuid(6633398E-823D-4361-B30E-824043BD4686), 
-    version(1.0),
-    local
-] 
-interface ICLRPrivAppXDomain : IUnknown
-{
-    /**********************************************************************************
-     ** Use to create a delegate to a static method.
-     **
-     ** wzAssemblyName - the name of the assembly that contains the target type.
-     ** wzTypeName - the name of the type that contains the target method.
-     ** wzMethodName - the static method for which to create a delegate.
-     ** ppvDelegate - receives the native-callable function pointer corresponding to
-     **     the specified static method.
-     **********************************************************************************/
-    HRESULT CreateDelegate(
-        [in] LPCWSTR wzAssemblyName,
-        [in] LPCWSTR wzTypeName,
-        [in] LPCWSTR wzMethodName,
-        [out] LPVOID * ppvDelegate);
-};
diff --git a/src/inc/clrprivbinding.idl b/src/inc/clrprivbinding.idl
deleted file mode 100644 (file)
index 9f4ee2f..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-import "unknwn.idl";
-import "objidl.idl";
-
-// Forward declarations
-interface ICLRPrivBinder;
-interface ICLRPrivAssembly;
-
-/**************************************************************************************
- ** This IDL file defines the assembly binding host interfaces. Some things to keep
- ** in mind:
- **    - Equality is determined by pointer equality: two interface instances
- **      should be considered equal if and only if their pointer values are equal.
- **    - All operations are idempotent: when a method is called more than once with
- **      the same input values, it is required to return identical results. The only
- **      possible exceptions center around transient errors such as E_OUTOFMEMORY.
- **************************************************************************************/
-
-/**************************************************************************************
- ** ICLRPrivBinder - Use to bind to an assembly by name or by metadata reference.
- **************************************************************************************/
-[
-    uuid(2601F621-E462-404C-B299-3E1DE72F8542),
-    version(1.0),
-    local
-]
-interface ICLRPrivBinder : IUnknown
-{
-    /**********************************************************************************
-     ** BindAssemblyByName -- Binds an assembly by name.
-     **     NOTE: This method is required to be idempotent. See general comment above.
-     **
-     ** pAssemblyFullName - name of the assembly for which a bind is being requested.
-     ** ppAssembly - upon success, receives the bound assembly.
-     **********************************************************************************/
-    HRESULT BindAssemblyByName(
-        [in] struct AssemblyNameData* pAssemblyNameData,
-        [out, retval] ICLRPrivAssembly ** ppAssembly);
-
-    /**********************************************************************************
-     ** GetBinderID
-     **  pBinderId, pointer to binder id. The binder id has the following properties
-     **        It is a pointer that does not change over the lifetime of a binder object
-     **        It points at an object in memory that will remain allocated for the lifetime of the binder.
-     **        This value should be the same for a set of binder objects that represent the same binder behavior.
-     **********************************************************************************/
-    HRESULT GetBinderID(
-        [out, retval] UINT_PTR *pBinderId);
-
-    /**********************************************************************************
-     ** GetLoaderAllocator
-     ** Get LoaderAllocator for binders that contain it. For other binders, return
-     ** E_FAIL
-     **
-     **  pLoaderAllocator - when successful, constains the returned LoaderAllocator
-     **********************************************************************************/
-    HRESULT GetLoaderAllocator(
-        [out, retval] LPVOID * pLoaderAllocator);
-};
-
-/**************************************************************************************
- ** ASSEMBLY_IMAGE_TYPES - The set of assembly image formats.
- **************************************************************************************/
-enum ASSEMBLY_IMAGE_TYPES
-{
-    // IL image format
-    ASSEMBLY_IMAGE_TYPE_IL                      = 0x0001,
-    // Native image (NGEN) format
-    ASSEMBLY_IMAGE_TYPE_NATIVE                  = 0x0002,
-    // Binder's preferred image type
-    ASSEMBLY_IMAGE_TYPE_DEFAULT                 = 0x0003,
-    // Only supported on CoreCLR
-    ASSEMBLY_IMAGE_TYPE_ASSEMBLY                = 0x0004,
-};
-
-/**************************************************************************************
- ** ICLRPrivAssembly - Represents an assembly bind result. Extends ICLRPrivBinder, which
- ** implicitly tracks the parent binder, and enables simple assembly-relative binds.
- **************************************************************************************/
-[
-    uuid(2601F621-E462-404C-B299-3E1DE72F8543),
-    version(1.0),
-    local
-]
-interface ICLRPrivAssembly : ICLRPrivBinder
-{
-    /**********************************************************************************
-     ** GetAvailableImageTypes - Use to retrieve the set of images available for an
-     ** assembly.
-     **     NOTE: This method is required to be idempotent. See general comment above.
-     **
-     ** pdwImageTypes - set to values from ASSEMBLY_IMAGE_TYPES to indicate
-     **     which image formats are available for the assembly.
-     **********************************************************************************/
-    HRESULT GetAvailableImageTypes(
-        [out, retval] LPDWORD pdwImageTypes);
-};
diff --git a/src/inc/clrprivhosting.idl b/src/inc/clrprivhosting.idl
deleted file mode 100644 (file)
index b288c28..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-import "unknwn.idl";
-import "CLRPrivBinding.idl";
-
-//=====================================================================================================================
-// Forward declarations
-interface ICLRPrivRuntime;
-
-//=====================================================================================================================
-// CLRPrivHosting coclass
-//=====================================================================================================================
-[
-    uuid("EDA73987-E6C0-42BF-A6B7-073F7B24D8C7")
-]
-library CLRPrivHosting
-{
-    //=================================================================================================================
-    // CLRPrivRuntime
-    //=================================================================================================================
-    [
-        uuid(BC1B53A8-DCBC-43B2-BB17-1E4061447AE8)
-    ]
-    coclass CLRPrivRuntime
-    {
-        [default] interface ICLRPrivRuntime;
-    };
-};
-
-//=====================================================================================================================
-// ICLRPrivRuntime
-//=====================================================================================================================
-[
-    uuid(BC1B53A8-DCBC-43B2-BB17-1E4061447AE9),
-    version(1.0),
-    local
-]
-interface ICLRPrivRuntime : IUnknown
-{
-    /**********************************************************************************
-     ** Used for accessing additional hosting functionality.
-     **
-     ** rclsid - the CoClass from which to request the interface.
-     ** riid - the IID of the interface being requested.
-     ** ppUnk - receives the interface pointer value.
-     **********************************************************************************/
-    HRESULT GetInterface(
-        [in]  REFCLSID rclsid,
-        [in]  REFIID riid,
-        [out, iid_is(riid), retval] LPVOID *ppUnk);
-    
-    /**********************************************************************************
-     ** Creates a domain using the provided binder for the root default bind context.
-     **
-     ** pwzFriendlyName - the name to associate with the domain.
-     ** pBinder - the binder to use for root-level binds in the default context.
-     ** pdwAppDomainId - receives the ID of the created domain.
-     **********************************************************************************/
-    HRESULT CreateAppDomain(
-        [in, string]  LPCWSTR pwzFriendlyName,
-        [in]  ICLRPrivBinder * pBinder,
-        [out, retval] LPDWORD pdwAppDomainId);
-
-    /**********************************************************************************
-     ** Creates a native-callable function pointer to the specified method.
-     **
-     ** appDomainID - the domain in which to create the delegate.
-     ** wszAssemblyName - the name of the assembly in which the method is defined.
-     ** wszClassName - the name of the class (including namespace) in which the method
-     **                is defined.
-     ** wszMethodName - the name of the method for which to create a delegate.
-     ** ppvDelegate - receives the delegate pointer value.
-     **********************************************************************************/
-    HRESULT CreateDelegate(
-        [in]  DWORD appDomainID,
-        [in, string]  LPCWSTR wszAssemblyName,
-        [in, string]  LPCWSTR wszClassName,
-        [in, string]  LPCWSTR wszMethodName,
-        [out, retval] LPVOID * ppvDelegate);
-
-    /**********************************************************************************
-     ** Creates an AppX appdomain and executes entrypoint method of an executable there 
-     **
-     **********************************************************************************/
-    HRESULT ExecuteMain(
-        [in]  ICLRPrivBinder * pBinder,
-        [out, retval] int * pRetVal
-    );
-};
-
diff --git a/src/inc/clrprivruntimebinders.idl b/src/inc/clrprivruntimebinders.idl
deleted file mode 100644 (file)
index 0da7e3a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-import "CLRPrivBinding.idl";
-
-//=====================================================================================================================
-// CLRPrivRuntime
-//=====================================================================================================================
-[
-    uuid("EA6A2170-8F6A-4007-87A9-02429F615958")
-]
-library CLRPrivRuntimeBinders
-{
-    //=================================================================================================================
-    // CLRPrivAppXBinder
-    //=================================================================================================================
-    [
-        uuid(E990F732-2D0A-48AC-87FC-EF12B618981A),
-        helpstring("Runtime-provided package-based assembly binder for AppX."),
-    ]
-    coclass CLRPrivAppXBinder
-    {
-        [default] interface ICLRPrivBinder;
-    };
-
-    //=================================================================================================================
-    // CLRPrivFusionBinder
-    //=================================================================================================================
-    [
-        uuid(E990F732-2D0A-48AC-87FC-EF12B618981C),
-        helpstring("Runtime-provided binder for wrapping ICLRPrivBinder-compatible subset of fusion functionality."),
-    ]
-    coclass CLRPrivFusionBinder
-    {
-        [default] interface ICLRPrivBinder;
-    };
-};
-
diff --git a/src/inc/clrtypes.h b/src/inc/clrtypes.h
new file mode 100644 (file)
index 0000000..6050936
--- /dev/null
@@ -0,0 +1,409 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ================================================================================
+// Standard primitive types for CLR code
+//
+// This header serves as a platform layer containing all of the primitive types
+// which we use across CLR implementation code.
+// ================================================================================
+
+
+#ifndef CLRTYPES_H_
+#define CLRTYPES_H_
+
+#if defined(_MSC_VER) && !defined(SOURCE_FORMATTING) && defined(FEATURE_CORESYSTEM)
+    // Prefer intsafe.h when available, which defines many of the MAX/MIN
+    // values below (which is why they are in #ifndef blocks).
+    #include <intsafe.h>
+#endif
+
+#include "crtwrap.h"
+#include "winwrap.h"
+#include "staticcontract.h"
+#include "static_assert.h"
+
+#if HOST_64BIT
+    #define POINTER_BITS (64)
+#else
+    #define POINTER_BITS (32)
+#endif
+
+// ================================================================================
+// Integral types - use these for all integral types
+// These types are in ALL_CAPS.  Each type has a _MIN and _MAX defined for it.
+// ================================================================================
+
+// --------------------------------------------------------------------------------
+// Use these types for fixed size integers:
+// INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64
+// --------------------------------------------------------------------------------
+
+#ifndef INT8_MAX
+    typedef signed char           INT8;
+    typedef unsigned char         UINT8;
+    typedef short                 INT16;
+    typedef unsigned short        UINT16;
+    typedef int                   INT32;
+    typedef unsigned int          UINT32;
+    typedef __int64               INT64;
+    typedef unsigned __int64      UINT64;
+
+    #ifdef _MSC_VER
+        /* These macros must exactly match those in the Windows SDK's intsafe.h */
+        #define INT8_MIN        (-127i8 - 1)
+        #define INT16_MIN       (-32767i16 - 1)
+        #define INT32_MIN       (-2147483647i32 - 1)
+        #define INT64_MIN       (-9223372036854775807i64 - 1)
+
+        #define INT8_MAX        127i8
+        #define INT16_MAX       32767i16
+        #define INT32_MAX       2147483647i32
+        #define INT64_MAX       9223372036854775807i64
+
+        #define UINT8_MAX       0xffui8
+        #define UINT16_MAX      0xffffui16
+        #define UINT32_MAX      0xffffffffui32
+        #define UINT64_MAX      0xffffffffffffffffui64
+    #else
+        #define INT8_MIN        ((INT8)0x80)
+        #define INT16_MIN       ((INT16)0x8000)
+        #define INT32_MIN       ((INT32)0x80000000)
+        #define INT64_MIN       ((INT64) I64(0x8000000000000000))
+
+        #define INT8_MAX        ((INT8)0x7f)
+        #define INT16_MAX       ((INT16)0x7fff)
+        #define INT32_MAX       ((INT32)0x7fffffff)
+        #define INT64_MAX       ((INT64) I64(0x7fffffffffffffff))
+
+        #define UINT8_MAX       ((UINT8)0xffU)
+        #define UINT16_MAX      ((UINT16)0xffffU)
+        #define UINT32_MAX      ((UINT32)0xffffffffU)
+        #define UINT64_MAX      ((UINT64) UI64(0xffffffffffffffff))
+    #endif
+#endif // !INT8_MAX
+
+// UINTX_MINs aren't defined in standard header files,
+// so definition must be separately predicated.
+#ifndef UINT8_MIN
+    #ifdef _MSC_VER
+        #define UINT8_MIN       0ui8
+        #define UINT16_MIN      0ui16
+        #define UINT32_MIN      0ui32
+        #define UINT64_MIN      0ui64
+    #else
+        #define UINT8_MIN       ((UINT8)0U)
+        #define UINT16_MIN      ((UINT16)0U)
+        #define UINT32_MIN      ((UINT32)0U)
+        #define UINT64_MIN      ((UINT64) UI64(0))
+    #endif
+#endif
+
+
+// --------------------------------------------------------------------------------
+// Use these types for pointer-sized integral types
+// SIZE_T SSIZE_T
+//
+// These types are the ONLY types which can be safely cast back and forth from a
+// pointer.
+// --------------------------------------------------------------------------------
+
+#ifndef SIZE_T_MAX
+    #if NEED_POINTER_SIZED_TYPEDEFS
+        typedef size_t                SIZE_T;
+        typedef ptrdiff_t             SSIZE_T;
+    #endif
+
+    #if POINTER_BITS == 64
+        #define SIZE_T_MAX              UINT64_MAX
+        #define SIZE_T_MIN              UINT64_MIN
+
+        #define SSIZE_T_MAX             INT64_MAX
+        #define SSIZE_T_MIN             INT64_MIN
+    #else
+        #define SIZE_T_MAX              UINT32_MAX
+        #define SIZE_T_MIN              UINT32_MIN
+
+        #define SSIZE_T_MAX             INT32_MAX
+        #define SSIZE_T_MIN             INT32_MIN
+    #endif
+#endif
+
+// --------------------------------------------------------------------------------
+// Non-pointer sized types
+// COUNT_T SCOUNT_T
+//
+// Use these types for "large" counts or indexes which will not exceed 32 bits.  They
+// may also be used for pointer differences, if you can guarantee that the pointers
+// are pointing to the same region of memory. (It can NOT be used for arbitrary
+// pointer subtraction.)
+// --------------------------------------------------------------------------------
+
+#ifndef COUNT_T_MAX
+    typedef UINT32                  COUNT_T;
+    typedef INT32                   SCOUNT_T;
+
+    #define COUNT_T_MAX             UINT32_MAX
+    #define COUNT_T_MIN             UINT32_MIN
+
+    #define SCOUNT_T_MAX            INT32_MAX
+    #define SCOUNT_T_MIN            INT32_MIN
+#endif
+
+// --------------------------------------------------------------------------------
+// Integral types with additional semantic content
+// BOOL BYTE
+// --------------------------------------------------------------------------------
+
+#ifndef BYTE_MAX
+    #if NEED_BOOL_TYPEDEF
+        typedef bool                    BOOL;
+    #endif
+
+    #define BOOL_MAX                1
+    #define BOOL_MIN                0
+
+    #define TRUE                    1
+    #define FALSE                   0
+
+    typedef UINT8                   BYTE;
+
+    #define BYTE_MAX                UINT8_MAX
+    #define BYTE_MIN                UINT8_MIN
+#endif
+
+// --------------------------------------------------------------------------------
+// Character types
+// CHAR SCHAR UCHAR WCHAR
+// --------------------------------------------------------------------------------
+
+typedef char                    CHAR;
+typedef signed char             SCHAR;
+typedef unsigned char           UCHAR;
+
+typedef CHAR                    ASCII;
+typedef CHAR                    ANSI;
+typedef CHAR                    UTF8;
+
+// Standard C defines:
+
+// CHAR_MAX
+// CHAR_MIN
+// SCHAR_MAX
+// SCHAR_MIN
+// UCHAR_MAX
+// UCHAR_MIN
+// WCHAR_MAX
+// WCHAR_MIN
+
+#ifndef ASCII_MAX
+    #define ASCII_MIN              ((ASCII)0)
+    #define ASCII_MAX              ((ASCII)127)
+
+    #define ANSI_MIN               ((ANSI)0)
+    #define ANSI_MAX               ((ANSI)255)
+
+    #define UTF8_MIN               ((UTF8)0)
+    #define UTF8_MAX               ((UTF8)255)
+#endif
+
+// ================================================================================
+// Non-integral types
+// These types are in ALL_CAPS.
+// ================================================================================
+
+// --------------------------------------------------------------------------------
+// Floating point types
+// FLOAT DOUBLE
+// --------------------------------------------------------------------------------
+
+// ================================================================================
+// Runtime type definitions - these are guaranteed to be identical with the
+// corresponding managed type
+// ================================================================================
+
+typedef WCHAR       CLR_CHAR;
+typedef INT8        CLR_I1;
+typedef UINT8       CLR_U1;
+typedef INT16       CLR_I2;
+typedef UINT16      CLR_U2;
+typedef INT32       CLR_I4;
+typedef UINT32      CLR_U4;
+typedef INT64       CLR_I8;
+typedef UINT64      CLR_U8;
+typedef FLOAT       CLR_R4;
+typedef DOUBLE      CLR_R8;
+typedef SSIZE_T     CLR_I;
+typedef SIZE_T      CLR_U;
+
+#define CLR_CHAR_MAX    WCHAR_MAX
+#define CLR_CHAR_MIN    WCHAR_MIN
+
+#define CLR_I1_MAX      INT8_MAX
+#define CLR_I1_MIN      INT8_MIN
+
+#define CLR_U1_MAX      UINT8_MAX
+#define CLR_U1_MIN      UINT8_MIN
+
+#define CLR_I2_MAX      INT16_MAX
+#define CLR_I2_MIN      INT16_MIN
+
+#define CLR_U2_MAX      UINT16_MAX
+#define CLR_U2_MIN      UINT16_MIN
+
+#define CLR_I4_MAX      INT32_MAX
+#define CLR_I4_MIN      INT32_MIN
+
+#define CLR_U4_MAX      UINT32_MAX
+#define CLR_U4_MIN      UINT32_MIN
+
+#define CLR_I8_MAX      INT64_MAX
+#define CLR_I8_MIN      INT64_MIN
+
+#define CLR_U8_MAX      UINT64_MAX
+#define CLR_U8_MIN      UINT64_MIN
+
+#define CLR_I_MAX       SSIZE_T_MAX
+#define CLR_I_MIN       SSIZE_T_MIN
+
+#define CLR_U_MAX       SIZE_T_MAX
+#define CLR_U_MIN       SIZE_T_MIN
+
+    typedef bool            CLR_BOOL;
+
+static_assert_no_msg(sizeof(CLR_BOOL) == 1);
+
+#define CLR_BOOL_MAX    BOOL_MAX
+#define CLR_BOOL_MIN    BOOL_MIN
+
+#define CLR_NAN_32 0xFFC00000
+#define CLR_NAN_64 I64(0xFFF8000000000000)
+
+// ================================================================================
+// Simple utility functions
+// ================================================================================
+
+// Note that these routines are in terms of UINT, ULONG, and ULONG64, since those are
+// the unsigned integral types the compiler overloads based on.
+
+// --------------------------------------------------------------------------------
+// Min/Max
+// --------------------------------------------------------------------------------
+
+template <typename T>
+T Min(T v1, T v2)
+{
+    STATIC_CONTRACT_LEAF;
+    return v1 < v2 ? v1 : v2;
+}
+
+template <typename T>
+T Max(T v1, T v2)
+{
+    STATIC_CONTRACT_LEAF;
+    return v1 > v2 ? v1 : v2;
+}
+
+// --------------------------------------------------------------------------------
+// Alignment bit twiddling macros - "alignment" must be power of 2
+//
+// AlignUp - align value to given increment, rounding up
+// AlignmentPad - amount adjusted by AlignUp
+//       AlignUp(value, x) == value + AlignmentPad(value, x)
+//
+// AlignDown - align value to given increment, rounding down
+// AlignmentTrim - amount adjusted by AlignDown
+//       AlignDown(value, x) == value - AlignmentTrim(value, x)
+// --------------------------------------------------------------------------------
+
+inline UINT AlignUp(UINT value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return (value+alignment-1)&~(alignment-1);
+}
+
+#if defined(_MSC_VER)
+inline ULONG AlignUp(ULONG value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return (value+alignment-1)&~(alignment-1);
+}
+#endif
+
+inline UINT64 AlignUp(UINT64 value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return (value+alignment-1)&~(UINT64)(alignment-1);
+}
+
+inline UINT AlignDown(UINT value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return (value&~(alignment-1));
+}
+
+#if defined(_MSC_VER)
+inline ULONG AlignDown(ULONG value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return (value&~(ULONG)(alignment-1));
+}
+#endif
+
+inline UINT64 AlignDown(UINT64 value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return (value&~(UINT64)(alignment-1));
+}
+
+inline UINT AlignmentPad(UINT value, UINT alignment)
+{
+    STATIC_CONTRACT_WRAPPER;
+    return AlignUp(value, alignment) - value;
+}
+
+#if defined(_MSC_VER)
+inline UINT AlignmentPad(ULONG value, UINT alignment)
+{
+    STATIC_CONTRACT_WRAPPER;
+    return AlignUp(value, alignment) - value;
+}
+#endif
+
+inline UINT AlignmentPad(UINT64 value, UINT alignment)
+{
+    STATIC_CONTRACT_WRAPPER;
+    return (UINT) (AlignUp(value, alignment) - value);
+}
+
+inline UINT AlignmentTrim(UINT value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return value&(alignment-1);
+}
+
+#ifndef HOST_UNIX
+// For Unix this and the previous function get the same types.
+// So, exclude this one.
+inline UINT AlignmentTrim(ULONG value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return value&(alignment-1);
+}
+#endif // HOST_UNIX
+
+inline UINT AlignmentTrim(UINT64 value, UINT alignment)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return ((UINT)value)&(alignment-1);
+}
+
+#endif  // CLRTYPES_H_
diff --git a/src/inc/contract.h b/src/inc/contract.h
new file mode 100644 (file)
index 0000000..a880d77
--- /dev/null
@@ -0,0 +1,2236 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// Contract.h
+//
+
+// ! I am the owner for issues in the contract *infrastructure*, not for every
+// ! CONTRACT_VIOLATION dialog that comes up. If you interrupt my work for a routine
+// ! CONTRACT_VIOLATION, you will become the new owner of this file.
+//--------------------------------------------------------------------------------
+// CONTRACTS - User Reference
+//
+//   A CONTRACT is a container for a set of checked declarations about a
+// function.  Besides giving developers a "laundry list" of checks to
+// make checking more complete, contracts compile these checks
+// as hidden annotations into the checked executable that our static scanner
+// uses to detect violations automatically.
+//
+//   Contracts can be dynamic or static. Dynamic contracts perform runtime checks
+// as well as being visible to the static scanner. Static contracts generate no
+// runtime code but are still visible to the scanner. Dynamic contracts are
+// preferred unless perf or other considerations preclude them.
+//
+//   The following annotations can appear in contracts:
+//
+//
+//      THROWS          an exception might be thrown out of the function
+//      -or- NOTHROW    an exception will NOT be thrown out of the function
+//
+//
+//
+//      INJECT_FAULT(statement)   function might require its caller to handle an OOM
+//      -or- FAULT_FORBID         function will NOT require its caller to handle an OOM
+//
+//
+//
+//      GC_TRIGGERS             the function can trigger a GC
+//      -or- GC_NOTRIGGER       the function will never trigger a GC provided its
+//                              called in coop mode.
+//
+//
+//      MODE_COOPERATIVE        the function requires Cooperative GC mode on entry
+//      -or- MODE_PREEMPTIVE    the function requires Preemptive GC mode on entry
+//      -or- MODE_ANY           the function can be entered in either mode
+//
+//      LOADS_TYPE(level)       the function promises not to load any types beyond "level"
+//
+//      CAN_TAKE_LOCK           the function has a code path that takes a lock
+//      _or_ (CAN_TAKE_LOCK and CANNOT_RETAKE_LOCK)
+//                              the function has a code path that takes a lock, but never tries to reenter
+//                              locks held at the time this function was called.
+//      -or- CANNOT_TAKE_LOCK   the function will never allow a lock to be taken
+//      -or-                    the default is WRAPPER(CAN_TAKE_LOCK).  i.e., if any callees take locks,
+//                              then it's ok for this function to as well.  If LIMITED_METHOD_CONTRACT is specified,
+//                              however, then CANNOT_TAKE_LOCK is assumed.
+//
+//
+//      SUPPORTS_DAC            The function has been written to be callable from out-of-process using DAC.
+//                              In builds where DACCESS_COMPILE is defined, such functions can only call
+//                              other such functions (and a few primitives like new).  Functions that support
+//                              DAC must be carefully written to conform to the rules in daccess.h.
+//
+//      SUPPORTS_DAC_HOST_ONLY  The function and its call graph has been written to be callable from out of process
+//                              using DAC, but it differs from SUPPORTS_DAC in that these functions won't perform
+//                              any marshalling. Because it does no marshalling, SUPPORTS_DAC_HOST_ONLY functions
+//                              and their call graph won't be checked by DacCop. This should only be used by utility
+//                              functions which will never marshal anything.
+//
+//      PRECONDITION(X) -   generic CHECK or BOOL expression which should be true
+//                          on function entry
+//
+//      POSTCONDITION(X) -  generic CHECK or BOOL expression which should be true
+//                          on function entry.  Note that variable RETVAL will be
+//                          available for use in the expression.
+//
+//
+//      INSTANCE_CHECK -    equivalent of:
+//                          PRECONDITION(CheckPointer(this));
+//                          POSTCONDITION(CheckInvariant(this));
+//      INSTANCE_CHECK_NULL - equivalent of:
+//                          PRECONDITION(CheckPointer(this, NULL_OK));
+//                          POSTCONDITION(CheckInvariant(this, NULL_OK));
+//      CONSTRUCTOR_CHECK - equivalent of:
+//                          POSTCONDITION(CheckPointer(this));
+//      DESTRUCTOR_CHECK -  equivalent of:
+//                          PRECONDITION(CheckPointer(this));
+//
+//
+//
+//
+//   Contracts come in the following flavors:
+//
+//     Dynamic:
+//        CONTRACTL          the standard version used for all dynamic contracts
+//                           except those including postconditions.
+//
+//        CONTRACT(rettype)  an uglier version of CONTRACTL that's unfortunately
+//                           needed to support postconditions. You must specify
+//                           the correct return type and it cannot be "void."
+//                           (Use CONTRACT_VOID instead) You must use the
+//                           RETURN macro rather than the "return" keyword.
+//
+//        CONTRACT_VOID      you can't supply "void" to a CONTRACT - use this
+//                           instead.
+//
+//     Static:
+//        LIMITED_METHOD_CONTRACT
+//                           A static contract equivalent to NOTHROW/GC_NOTRIGGER/FORBID_FAULT/MODE_ANY.
+//                           Use only for trivial functions that call only functions with LIMITED_METHOD_CONTRACTs
+//                           (as long as there is no cycle that may introduce infinite recursion).
+//
+//        STATIC_CONTRACT_THROWS
+//        STATIC_CONTRACT_NOTHROW
+//        STATIC_CONTRACT_GC_TRIGGERS
+//        STATIC_CONTRACT_GCNOTRIGGER
+//        STATIC_CONTRACT_FAULT
+//        STATIC_CONTRACT_FORBID_FAULT
+//                           use to implement statically checkable contracts
+//                           when runtime contracts cannot be used.
+//
+//
+//   WRAPPER(annotation)
+//
+// When a function does not explicitly caused a condition, use the WRAPPER macro around
+// the declaration.  This implies that the function is dependent on the functions it calls
+// for its behaviour, and guarantees nothing.
+//
+//
+//   CONTRACT_VIOLATION(violationmask):
+//
+//        A bandaid used to suppress contract assertions. A contract violation
+//        is always a bug and you're expected to remove it before shipping.
+//        If a violation cannot be fixed immediately, however, it's better
+//        to use this on the offending callsite than to disable a contract entirely.
+//
+//        The violationmask can be one or more of the following OR'd together.
+//
+//              ThrowsViolation
+//              GCViolation
+//              ModeViolation
+//              FaultViolation
+//              FaultNotFatal
+//              HostViolation
+//              LoadsTypeViolation
+//              TakesLockViolation
+//
+//        The associated assertion will be suppressed until you leave the scope
+//        containing the CONTRACT_VIOLATION. Note, however, that any called
+//        function that redeclares the associated annotation reinstates
+//        the assert for the scope of *its* call. This prevents a CONTRACT_VIOLATION
+//        placed at the root of a calltree from decimating our entire protection.
+//
+//
+//   PERMANENT_CONTRACT_VIOLATION(violationmask, permanentContractViolationReason):
+//
+//        Like a CONTRACT_VIOLATION but also indicates that the violation was a deliberate decision
+//        and we don't plan on removing the violation in the next release.  The reason
+//        for the violation should be given as the second parameter to the macro.  Reasons
+//        are currently for documentation purposes only and do not have an effect on the binary.
+//        Valid values are listed below in the definition of PermanentContractViolationReason.
+//
+//
+//    CONDITIONAL_CONTRACT_VIOLATION(violationmask, condition):
+//
+//        Similar to CONTRACT_VIOLATION, but only suppresses the contract if the
+//        condition evaluates to non-zero.  The need for this macro should be very
+//        rare, but it can be useful if a contract should be suppressed based on a
+//        condition known only at run-time.  For example, if a particular test causes
+//        call sequences never expected by real scenarios, you may want to suppress
+//        resulting violations, but only when that test is run.
+//
+//   WRAPPER_NO_CONTRACT
+//
+//        A do-nothing contract used by functions that trivially wrap another.
+//
+//
+// "LEGACY" stuff - these features have been mostly superceded by better solutions
+//     so their use should be discouraged.
+//
+//
+//   DISABLED(annotation)
+//
+//        Indicates that a condition is supposed to be checked but is being suppressed
+//        due to some temporary bug. The more surgical CONTRACT_VIOLATION is
+//        preferred over DISABLED.
+//
+//   UNCHECKED(annotation)
+//
+//        Indicates that a condition is supposed to be checked but is being suppressed
+//        due for perf reasons. Use STATIC_CONTRACT over this.
+//
+//
+//   Default values:
+//        If you don't specify certain annotaions, you get defaults.
+//           - THROWS/NOTHROW          defaults to THROWS
+//           - GCTRIGGERS/GCNOTRIGGER  defaults to GCTRIGGERS within the VM directory
+//                                     and to no check otherwise
+//           - INJECT/FORBID_FAULT     defaults to no check
+//           - MODE                    defaults to MODE_ANY
+//
+//        The problem is that defaults don't work well with static contracts.
+//        The scanner will always treat a missing annotation as DISABLED.
+//        New code should not rely on defaults. Explicitly state your invariants.
+//
+//
+//--------------------------------------------------------------------------------
+
+
+
+
+#ifndef CONTRACT_H_
+#define CONTRACT_H_
+
+#ifdef _MSC_VER
+#pragma warning(disable:4189) //local variable is initialized but not referenced
+#endif
+
+
+// We only enable contracts in _DEBUG builds
+#if defined(_DEBUG) && !defined(DISABLE_CONTRACTS) && !defined(JIT_BUILD)
+#define ENABLE_CONTRACTS_DATA
+#endif
+
+// Also, we won't enable contracts if this is a DAC build.
+#if defined(ENABLE_CONTRACTS_DATA) && !defined(DACCESS_COMPILE) && !defined(CROSS_COMPILE)
+#define ENABLE_CONTRACTS
+#endif
+
+// Finally, only define the implementaiton parts of contracts if this isn't a DAC build.
+#if defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS)
+#define ENABLE_CONTRACTS_IMPL
+#endif
+
+#include "specstrings.h"
+#include "clrtypes.h"
+#include "malloc.h"
+#include "check.h"
+#include "debugreturn.h"
+#include "staticcontract.h"
+
+#ifdef ENABLE_CONTRACTS_DATA
+
+#include "eh.h"
+
+// We chain these onto a stack to give us a stack trace of contract assertions (useful
+// when the bug report doesn't contain valid symbols)
+
+struct ContractStackRecord
+{
+    ContractStackRecord *m_pNext;
+    const char          *m_szFunction;
+    const char          *m_szFile;
+    int                  m_lineNum;
+    UINT                 m_testmask;  // Bitmask of Contract::TestEnum bitsf
+    const char          *m_construct; // The syntactic construct that pushed this thing
+};
+
+class CrstBase;
+
+// The next few enums / structs are used to keep track of all kinds of locks
+// currently taken by the current thread (crsts, spinlocks, CLR critical sections).
+// Across the VM, there are still multiple counts of locks.  The lock counts in these
+// contract structs are used to verify consistency of lock take/release in EE code, and
+// for contracts.  Both user and EE locks are tracked here, but it's EE code consistency
+// we're verifying.  The Thread object keeps its own counts as well, primarily of user
+// locks for implementing thread abort & escalation policy.  We tried to have the Thread
+// counts also be used for consistency checking, but that doesn't work.  Thread counters
+// have the following behavior that hurts our internal consistency checks:
+//      - They only count user locks.
+//      - Counters are reset & restored as we leave and return to AppDomains
+
+// An array of these is stored in DbgStateLockData::m_rgTakenLockInfos
+// to remember which locks we've taken.  If you hit an assert that
+// indicates we're exiting locks in the wrong order, or that locks were
+// taken when we expected none to be taken, then you can use
+// DbgStateLockData::m_rgTakenLockInfos to see the locks we know about.
+struct TakenLockInfo
+{
+    // Generally, this will be a pointer to the lock, but really it's just
+    // a value that identifies which lock is taken.  Ya see, sometimes we don't
+    // have a lock pointer handy (e.g., if the lock is based on a GC object,
+    // which has no persistent object pointer we can use).  Look at the source
+    // indicated by m_szFile / m_lineNum to see what was specified as m_pvLock.
+    //
+    // A common case is that the lock is just a Crst, so to aid debugging, we
+    // also include a statically typed version of this pointer (m_pCrstBase) just
+    // for Crsts. Again, you'll want look at m_szFile / m_lineNum to see how to
+    // interpret this union.
+    union
+    {
+        void *           m_pvLock;
+        CrstBase *       m_pCrstBase;
+    };
+
+    // File & line of the *LOCK_TAKEN* macro that added this lock to our list
+    const char *         m_szFile;
+    int                  m_lineNum;
+};
+
+enum DbgStateLockType
+{
+    // EE locks (used to sync EE structures).  These do not include
+    // CRST_HOST_BREAKABLE Crsts, and are thus not held while managed
+    // code runs
+    kDbgStateLockType_EE,
+
+    // CRST_HOST_BREAKABLE Crsts.  These can be held while arbitrary
+    // managed code runs.
+    kDbgStateLockType_HostBreakableCrst,
+
+    // User locks (e.g., Monitor.Enter, ReaderWriterLock class)
+    kDbgStateLockType_User,
+
+    // add more lock types here
+
+    kDbgStateLockType_Count
+};
+
+// This keeps track of how many locks, and which locks, are currently owned
+// by the current thread.  There is one instance of this structure per
+// thread (no EE Thread object required).  This is in contrast to the
+// ClrDebugState structure, which is instantiated once per function
+// on the stack.  Reason is that ClrDebugState resets its state on exit
+// of function (Contract destructor reinstates previous ClrDebugState), whereas
+// we want DbgStateLockData to persist across function enters & exits.
+struct DbgStateLockData
+{
+    // When a lock is taken, we keep track of its pointer and file/line# when it
+    // was added in a static-size array DbgStateLockData::m_rgTakenLockInfos.  This is
+    // the size of that array, and therefore indicates the maximum number of locks we
+    // expect one thread to hold at the same time.  If we should exceed this limit,
+    // we'll lose this data for the latter locks that exceed this limit
+    // (though still maintaining an accurate *count* of locks).
+    static const int     kMaxAllowedSimultaneousLocks = 20;
+
+    // Count of locks taken, separately by type
+    UINT                 m_rgcLocksTaken[kDbgStateLockType_Count];
+
+    // List of the specific locks that have been taken (all DbgStateLockTypes
+    // intermingled), in the order they were taken.  If we exceed the elements
+    // in the array, we just won't track the latter locks in here (though they are
+    // included in the counts above)
+    TakenLockInfo        m_rgTakenLockInfos[kMaxAllowedSimultaneousLocks];
+
+    void SetStartingValues();
+    void LockTaken(DbgStateLockType dbgStateLockType,
+                     UINT cEntrances,
+                     void * pvLock,
+                     _In_z_ const char * szFunction,
+                     _In_z_ const char * szFile,
+                     int lineNum);
+    void LockReleased(DbgStateLockType dbgStateLockType, UINT cExits, void * pvLock);
+    UINT GetLockCount(DbgStateLockType dbgStateLockType);
+    UINT GetCombinedLockCount();
+};
+
+// This struct contains all lock contract information.  It is created and destroyed along with
+// ClrDebugState. m_pLockData points to a DbgStateLockData object that is allocated per thread
+// and persists across function enters and exists.
+struct DbgStateLockState
+{
+private:
+    // Count of locks taken at the time the function with CANNOT_RETAKE_LOCK contract
+    // was called
+    UINT               m_cLocksEnteringCannotRetakeLock;
+
+    DbgStateLockData * m_pLockData;  // How many and which locks are currently taken on this thread
+
+public:
+    void SetStartingValues();
+    void OnEnterCannotRetakeLockFunction();
+    BOOL IsLockRetaken(void * pvLock);
+    BOOL IsSafeToRelease(UINT cReleases);
+    void SetDbgStateLockData(DbgStateLockData * pDbgStateLockData);
+    DbgStateLockData * GetDbgStateLockData();
+};
+
+
+#define CONTRACT_BITMASK_OK_TO_THROW          0x1 << 0
+#define CONTRACT_BITMASK_FAULT_FORBID         0x1 << 1
+#define CONTRACT_BITMASK_HOSTCALLS            0x1 << 2
+#define CONTRACT_BITMASK_SOTOLERANT           0x1 << 3
+#define CONTRACT_BITMASK_DEBUGONLY            0x1 << 4
+#define CONTRACT_BITMASK_SONOTMAINLINE        0x1 << 5
+#define CONTRACT_BITMASK_OK_TO_LOCK           0x1 << 6
+#define CONTRACT_BITMASK_OK_TO_RETAKE_LOCK    0x1 << 7
+
+
+#define CONTRACT_BITMASK_IS_SET(whichbit)    ((m_flags & (whichbit)) != 0)
+#define CONTRACT_BITMASK_SET(whichbit)       (m_flags |= (whichbit))
+#define CONTRACT_BITMASK_RESET(whichbit)     (m_flags &= ~(whichbit))
+#define CONTRACT_BITMASK_UPDATE(whichbit, value)  ((value)?CONTRACT_BITMASK_SET(whichbit):CONTRACT_BITMASK_RESET(whichbit))
+
+struct ClrDebugState
+{
+private:
+    UINT_PTR              m_flags;
+    UINT_PTR             m_violationmask;      // Current CONTRACT_VIOLATIONS in effect
+    ContractStackRecord *m_pContractStackTrace;
+    UINT                 m_GCNoTriggerCount;
+    UINT                 m_GCForbidCount;
+    UINT                  m_maxLoadTypeLevel;   // taken from enum ClassLoadLevel
+    BOOL                  m_allowGetThread;     // TRUE if GetThread() is ok in this scope
+    DbgStateLockState     m_LockState;
+
+public:
+    // Use an explicit Init rather than ctor as we don't want automatic
+    // construction of the ClrDebugState embedded inside the contract.
+    void SetStartingValues()
+    {
+        m_violationmask     = 0;            // No violations allowed
+
+        // Default is we're in a THROWS scope. This is not ideal, but there are
+                                            //  just too many places that I'd have to go clean up right now
+                                            //  (hundreds) in order to make this FALSE by default.
+        // Faults not forbidden (an unfortunate default but
+                                            //  we'd never get this debug infrastructure bootstrapped otherwise.)
+        // We start out in SO-tolerant mode and must probe before entering SO-intolerant
+        //   any global state updates.
+        // Initial mode is non-debug until we say otherwise
+        // Everthing defaults to mainline
+        // By default, GetThread() is perfectly fine to call
+        // By default, it's ok to take a lock (or call someone who does)
+        m_flags             = CONTRACT_BITMASK_OK_TO_THROW|
+                              CONTRACT_BITMASK_HOSTCALLS|
+                              CONTRACT_BITMASK_SOTOLERANT|
+                              CONTRACT_BITMASK_OK_TO_LOCK|
+                              CONTRACT_BITMASK_OK_TO_RETAKE_LOCK;
+
+        m_pContractStackTrace = NULL;       // At top of stack, no contracts in force
+        m_GCNoTriggerCount  = 0;
+        m_GCForbidCount     = 0;
+
+        m_maxLoadTypeLevel = ((UINT)(-1));  // ideally CLASS_LOAD_LEVEL_FINAL but we don't have access to that #define, so
+                                            // the max integer value will do as a substitute.
+
+        m_allowGetThread = TRUE;            // By default, GetThread() is perfectly fine to call
+
+        m_LockState.SetStartingValues();
+    }
+
+    void CheckOkayToThrow(_In_z_ const char *szFunction, _In_z_ const char *szFile, int lineNum); // Asserts if its not okay to throw.
+    BOOL CheckOkayToThrowNoAssert(); // Returns if OK to throw
+
+    //--//
+
+    UINT_PTR* ViolationMaskPtr()
+    {
+        return &m_violationmask;
+    }
+
+    UINT_PTR ViolationMask()
+    {
+        return m_violationmask;
+    }
+
+    void ViolationMaskSet( UINT_PTR value )
+    {
+        m_violationmask |= value;
+    }
+
+    void ViolationMaskReset( UINT_PTR value )
+    {
+        m_violationmask &= ~value;
+    }
+
+    //--//
+
+    BOOL IsOkToThrow()
+    {
+        return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_THROW);
+    }
+
+    void SetOkToThrow()
+    {
+        CONTRACT_BITMASK_SET(CONTRACT_BITMASK_OK_TO_THROW);
+    }
+
+    BOOL SetOkToThrow( BOOL value )
+    {
+        BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_THROW);
+        CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_OK_TO_THROW, value);
+        return prevState;
+    }
+
+    void ResetOkToThrow()
+    {
+        CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_OK_TO_THROW);
+    }
+    //--//
+
+    BOOL IsFaultForbid()
+    {
+        return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_FAULT_FORBID);
+    }
+
+
+    void SetFaultForbid()
+    {
+        CONTRACT_BITMASK_SET(CONTRACT_BITMASK_FAULT_FORBID);
+    }
+
+    BOOL SetFaultForbid(BOOL value)
+    {
+        BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_FAULT_FORBID);
+        CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_FAULT_FORBID, value);
+        return prevState;
+    }
+
+    void ResetFaultForbid()
+    {
+        CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_FAULT_FORBID);
+    }
+
+    //--//
+    BOOL IsHostCaller()
+    {
+        return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_HOSTCALLS);
+    }
+
+    void SetHostCaller()
+    {
+        CONTRACT_BITMASK_SET(CONTRACT_BITMASK_HOSTCALLS);
+    }
+
+
+    BOOL SetHostCaller(BOOL value)
+    {
+        BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_HOSTCALLS);
+        CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_HOSTCALLS,value);
+        return prevState;
+    }
+
+    void ResetHostCaller()
+    {
+        CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_HOSTCALLS);
+    }
+
+    //--//
+    BOOL IsDebugOnly()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_DEBUGONLY);
+    }
+
+    void SetDebugOnly()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        CONTRACT_BITMASK_SET(CONTRACT_BITMASK_DEBUGONLY);
+    }
+
+    BOOL SetDebugOnly(BOOL value)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_DEBUGONLY);
+        CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_DEBUGONLY,value);
+        return prevState;
+    }
+
+    void ResetDebugOnly()
+    {
+        STATIC_CONTRACT_LIMITED_METHOD;
+        CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_DEBUGONLY);
+    }
+
+    //--//
+    BOOL IsOkToLock()
+    {
+        return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_LOCK);
+    }
+
+    void SetOkToLock()
+    {
+        CONTRACT_BITMASK_SET(CONTRACT_BITMASK_OK_TO_LOCK);
+    }
+
+    BOOL SetOkToLock( BOOL value )
+    {
+        BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_LOCK);
+        CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_OK_TO_LOCK, value);
+        return prevState;
+    }
+
+    void ResetOkToLock()
+    {
+        CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_OK_TO_LOCK);
+    }
+
+    //--//
+    BOOL IsOkToRetakeLock()
+    {
+        return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_RETAKE_LOCK);
+    }
+
+    void ResetOkToRetakeLock()
+    {
+        CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_OK_TO_RETAKE_LOCK);
+    }
+
+
+    //--//
+    void LinkContractStackTrace( ContractStackRecord* pContractStackTrace )
+    {
+        pContractStackTrace->m_pNext = m_pContractStackTrace;
+
+        m_pContractStackTrace = pContractStackTrace;
+    }
+
+    ContractStackRecord* GetContractStackTrace()
+    {
+        return m_pContractStackTrace;
+    }
+
+    void SetContractStackTrace(ContractStackRecord* pContractStackTrace )
+    {
+        m_pContractStackTrace = pContractStackTrace;
+    }
+
+    //--//
+
+    UINT GetGCNoTriggerCount()
+    {
+        return m_GCNoTriggerCount;
+    }
+
+    void DecrementGCNoTriggerCount()
+    {
+        m_GCNoTriggerCount--;
+    }
+
+    void IncrementGCNoTriggerCount()
+    {
+        m_GCNoTriggerCount++;
+    }
+
+
+    UINT GetGCForbidCount()
+    {
+        return m_GCForbidCount;
+    }
+
+    void DecrementGCForbidCount()
+    {
+        m_GCForbidCount--;
+    }
+
+    void IncrementGCForbidCount()
+    {
+        m_GCForbidCount++;
+    }
+
+    UINT GetMaxLoadTypeLevel()
+    {
+        return m_maxLoadTypeLevel;
+    }
+
+    void SetMaxLoadTypeLevel(UINT newLevel)
+    {
+        m_maxLoadTypeLevel = newLevel;
+    }
+
+    //--//
+
+    void SetDbgStateLockData(DbgStateLockData * pDbgStateLockData)
+    {
+        m_LockState.SetDbgStateLockData(pDbgStateLockData);
+    }
+
+    DbgStateLockData * GetDbgStateLockData()
+    {
+        return m_LockState.GetDbgStateLockData();
+    }
+
+    void OnEnterCannotRetakeLockFunction()
+    {
+        m_LockState.OnEnterCannotRetakeLockFunction();
+    }
+
+    void CheckOkayToLock(_In_z_ const char *szFunction, _In_z_ const char *szFile, int lineNum); // Asserts if its not okay to lock
+    BOOL CheckOkayToLockNoAssert(); // Returns if OK to lock
+    void LockTaken(DbgStateLockType dbgStateLockType,
+                     UINT cEntrances,
+                     void * pvLock,
+                     _In_z_ const char * szFunction,
+                     _In_z_ const char * szFile,
+                     int lineNum);
+    void LockReleased(DbgStateLockType dbgStateLockType, UINT cExits, void * pvLock);
+    UINT GetLockCount(DbgStateLockType dbgStateLockType);
+    UINT GetCombinedLockCount();
+};
+
+#endif // ENABLE_CONTRACTS
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// Create ClrDebugState.
+// This routine is not allowed to return NULL. If it can't allocate the memory needed,
+// it should return a pointer to a global static ClrDebugState that indicates
+// that debug assertions should be skipped.
+ClrDebugState *CLRInitDebugState();
+ClrDebugState *GetClrDebugState(BOOL fAlloc = TRUE);
+
+extern thread_local ClrDebugState* t_pClrDebugState;
+
+// This function returns a ClrDebugState if one has been created, but will not create one itself.
+inline ClrDebugState *CheckClrDebugState()
+{
+    STATIC_CONTRACT_LIMITED_METHOD;
+    return t_pClrDebugState;
+}
+
+void CONTRACT_ASSERT(const char *szElaboration,
+                     UINT  whichTest,
+                     UINT  whichTestMask,
+                     const char *szFunction,
+                     const char *szFile,
+                     int   lineNum
+                     );
+
+#endif
+
+// This needs to be defined up here b/c it is used by ASSERT_CHECK which is used by the contract impl
+#ifdef _DEBUG
+#ifdef ENTER_DEBUG_ONLY_CODE
+#undef ENTER_DEBUG_ONLY_CODE
+#endif
+#ifdef LEAVE_DEBUG_ONLY_CODE
+#undef LEAVE_DEBUG_ONLY_CODE
+#endif
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// This can only appear in a debug function so don't define it non-debug
+class DebugOnlyCodeHolder
+{
+public:
+    // We use GetClrDebugState on entry, but CheckClrDebugState on Leave
+    // That way we make sure to create one if we need to set state, but
+    // we don't recreated one on exit if its been deleted.
+    DEBUG_NOINLINE void Enter()
+    {
+        SCAN_SCOPE_BEGIN;
+        STATIC_CONTRACT_DEBUG_ONLY;
+
+        m_pClrDebugState = GetClrDebugState();
+        if (m_pClrDebugState)
+        {
+            m_oldDebugOnlyValue = m_pClrDebugState->IsDebugOnly();
+            m_pClrDebugState->SetDebugOnly();
+        }
+    }
+
+    DEBUG_NOINLINE void Leave()
+    {
+        SCAN_SCOPE_END;
+        STATIC_CONTRACT_DEBUG_ONLY;
+
+        m_pClrDebugState = CheckClrDebugState();
+        if (m_pClrDebugState)
+        {
+            m_pClrDebugState->SetDebugOnly( m_oldDebugOnlyValue );
+        }
+    }
+
+private:
+BOOL           m_oldDebugOnlyValue;
+ClrDebugState *m_pClrDebugState;
+};
+
+#define ENTER_DEBUG_ONLY_CODE                                                \
+    DebugOnlyCodeHolder __debugOnlyCodeHolder;                               \
+    __debugOnlyCodeHolder.Enter();
+
+#define LEAVE_DEBUG_ONLY_CODE                                                \
+    __debugOnlyCodeHolder.Leave();
+
+
+class AutoCleanupDebugOnlyCodeHolder : public DebugOnlyCodeHolder
+{
+public:
+    DEBUG_NOINLINE AutoCleanupDebugOnlyCodeHolder()
+    {
+        SCAN_SCOPE_BEGIN;
+        STATIC_CONTRACT_DEBUG_ONLY;
+
+        Enter();
+    };
+
+    DEBUG_NOINLINE ~AutoCleanupDebugOnlyCodeHolder()
+    {
+        SCAN_SCOPE_END;
+
+        Leave();
+    };
+};
+
+#define DEBUG_ONLY_FUNCTION \
+    STATIC_CONTRACT_DEBUG_ONLY;                                             \
+    AutoCleanupDebugOnlyCodeHolder __debugOnlyCodeHolder;
+
+#define DEBUG_ONLY_REGION() \
+    AutoCleanupDebugOnlyCodeHolder __debugOnlyCodeHolder;
+
+
+#define BEGIN_DEBUG_ONLY_CODE                                               \
+    {                                                                       \
+        AutoCleanupDebugOnlyCodeHolder __debugOnlyCodeHolder;
+
+#define END_DEBUG_ONLY_CODE                                                 \
+    }
+
+#else // ENABLE_CONTRACTS_IMPL
+#define DEBUG_ONLY_FUNCTION STATIC_CONTRACT_DEBUG_ONLY
+#define DEBUG_ONLY_REGION()
+#define BEGIN_DEBUG_ONLY_CODE
+#define END_DEBUG_ONLY_CODE
+#define ENTER_DEBUG_ONLY_CODE
+#define LEAVE_DEBUG_ONLY_CODE
+#endif
+
+#else // _DEBUG
+#define DEBUG_ONLY_REGION()
+#endif
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+// These helpers encapsulate our access to our FLS debug state. To improve
+// contract perf, we'll soon move these to a private alloced block
+// so we can reuse the pointer instead of constantly refetching it.
+// Thus, these helpers are just to bridge this transition.
+inline LPVOID GetViolationMask()
+{
+    ClrDebugState *pState = CheckClrDebugState();
+    if (pState)
+    {
+        return (LPVOID)pState->ViolationMask();
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+// This is the default binding of the MAYBETEMPLATE identifier,
+// used in the RETURN macro
+template <int DUMMY>
+class ___maybetemplate
+{
+  public:
+    FORCEINLINE void *operator new (size_t size)
+    {
+        return NULL;
+    }
+};
+
+// This is an abstract base class for contracts. The main reason we have this is so that the dtor for many derived class can
+// be performant. If this class was not abstract and had a dtor, then the dtor for the derived class adds EH overhead (even if the derived
+// class did not anything special in its dtor)
+class BaseContract
+{
+    // Really private, but used by macros
+    public:
+
+    // We use a single integer to specify all the settings for intrinsic tests
+    // such as THROWS and GC_TRIGGERS. The compiler should be able to fold all
+    // these clauses into a single constant.
+    //
+    // The value "0" is significant as this is what the entire mask will be initialized to
+    // in the absence of any clauses. Hence, whichever value is assigned "0" will be the
+    // default setting for the test.
+    //
+    // Also, there must be a "disabled" setting for each category in order to support
+    // the DISABLED macro.
+    enum TestEnum
+    {
+        THROWS_Mask         = 0x00000003,
+        THROWS_Yes          = 0x00000000,   // the default
+        THROWS_No           = 0x00000001,
+        THROWS_Disabled     = 0x00000002,
+
+        GC_Mask             = 0x0000000C,
+        GC_Triggers         = 0x00000000,   // the default
+        GC_NoTrigger        = 0x00000004,
+        GC_Disabled         = 0x00000008,
+
+        FAULT_Mask          = 0x00000030,
+        FAULT_Disabled      = 0x00000000,   // the default
+        FAULT_Inject        = 0x00000010,
+        FAULT_Forbid        = 0x00000020,
+
+        MODE_Mask           = 0x000000C0,
+        MODE_Disabled       = 0x00000000,   // the default
+        MODE_Preempt        = 0x00000040,
+        MODE_Coop           = 0x00000080,
+
+        DEBUG_ONLY_Yes          = 0x00000400,  // code runs under debug only
+
+        SO_MAINLINE_No          = 0x00000800,  // code is not part of our mainline SO scenario
+
+        // Any place where we can't safely call into the host should have a HOST_NoCalls contract
+        HOST_Mask               = 0x00003000,
+        HOST_Calls              = 0x00002000,
+        HOST_NoCalls            = 0x00001000,
+        HOST_Disabled           = 0x00000000,   // the default
+
+        // These enforce the CAN_TAKE_LOCK / CANNOT_TAKE_LOCK contracts
+        CAN_TAKE_LOCK_Mask      = 0x00060000,
+        CAN_TAKE_LOCK_Yes       = 0x00020000,
+        CAN_TAKE_LOCK_No        = 0x00040000,
+        CAN_TAKE_LOCK_Disabled  = 0x00000000,   // the default
+
+        // These enforce the CANNOT_RETAKE_LOCK contract
+        CAN_RETAKE_LOCK_No           = 0x00080000,
+        CAN_RETAKE_LOCK_No_Disabled  = 0x00000000,   // the default
+
+        PRECONDITION_Used       = 0x00010000,   // a PRECONDITION appeared inside the contract
+
+        // IMPORTANT!!! LOADS_TYPE_Mask and LOADS_TYPE_Shift must be kept in sync.
+        LOADS_TYPE_Mask         = 0x00f00000,   // the max loadstype level + 1 ("+1" because 0 is reserved for the default which is "disabled")
+        LOADS_TYPE_Shift        = 20,           // # of bits to right-shift to get loadstype bits to rightmost position.
+        LOADS_TYPE_Disabled     = 0x00000000,   // the default
+
+        ALL_Disabled            = THROWS_Disabled|GC_Disabled|FAULT_Disabled|MODE_Disabled|LOADS_TYPE_Disabled|
+                                  HOST_Disabled|CAN_TAKE_LOCK_Disabled|CAN_RETAKE_LOCK_No_Disabled
+
+    };
+
+    enum Operation
+    {
+        Setup = 0x01,
+        Preconditions = 0x02,
+        Postconditions = 0x04,
+    };
+
+
+    NOTHROW_DECL BaseContract() : m_testmask(0), m_pClrDebugState(NULL)
+    {
+    }
+    NOTHROW_DECL void Restore()
+    {
+        // m_pClrDebugState is setup in BaseContract::DoChecks. If an SO happens after the
+        // BaseContract object is constructed but before DoChecks is invoked, m_pClrDebugState
+        // will remain NULL (which is what it is set to in the BaseContract ctor).
+        //
+        // Thus, we should check for it being NULL before dereferencing it.
+        if (m_pClrDebugState)
+        {
+            // Backout all changes to debug state.
+            *m_pClrDebugState = m_IncomingClrDebugState;
+        }
+    }
+
+    void DoChecks(UINT testmask, _In_z_ const char *szFunction, _In_z_ const char *szFile, int lineNum);
+    void Disable()
+    {
+    }
+    BOOL CheckFaultInjection();
+
+  protected:
+    UINT            m_testmask;
+    // Override this function in any derived class to indicate that you have defined a destructor for that class
+    // and that dtor calls Restore()
+    virtual void DestructorDefinedThatCallsRestore() = 0;
+
+
+  protected:
+    ClrDebugState  *m_pClrDebugState;
+    ClrDebugState   m_IncomingClrDebugState;
+
+    ContractStackRecord m_contractStackRecord;
+
+  public:
+    // --------------------------------------------------------------------------------
+    // These classes and declarations are used to implement our fake return keyword.
+    // --------------------------------------------------------------------------------
+
+    // ___box is used to protect the "detected" return value from being combined with other parts
+    // of the return expression after we have processed it.  This can happen if the return
+    // expression is a non-parenthesized expression with an operator of lower precedence than
+    // ">".
+    //
+    // If you have such a case (and see this class listed in an error message),
+    // parenthesize your return value expression.
+    template <typename T>
+    class Box__USE_PARENS_WITH_THIS_EXPRESSION
+    {
+        const T &value;
+
+    public:
+
+        FORCEINLINE Box__USE_PARENS_WITH_THIS_EXPRESSION(const T &value)
+          : value(value)
+          {
+          }
+
+        FORCEINLINE const T& Unbox()
+          {
+              return value;
+          }
+    };
+
+    // PseudoTemplate is a class which can be instantated with a template-like syntax, resulting
+    // in an expression which simply boxes a following value in a Box
+
+    template <typename T>
+    class PseudoTemplate
+    {
+      public:
+        FORCEINLINE void *operator new (size_t size)
+        {
+            return NULL;
+        }
+
+        FORCEINLINE Box__USE_PARENS_WITH_THIS_EXPRESSION<T> operator>(const T &value)
+        {
+            return Box__USE_PARENS_WITH_THIS_EXPRESSION<T>(value);
+        }
+
+        FORCEINLINE PseudoTemplate operator<(int dummy)
+        {
+            return PseudoTemplate();
+        }
+    };
+
+    // Returner is used to assign the return value to the RETVAL local.  Note the use of
+    // operator , because of its low precedence.
+
+    template <typename RETURNTYPE>
+    class Returner
+    {
+        RETURNTYPE      &m_value;
+        BOOL            m_got;
+    public:
+
+        FORCEINLINE Returner(RETURNTYPE &value)
+          : m_value(value),
+            m_got(FALSE)
+        {
+        }
+
+        template <typename T>
+        FORCEINLINE RETURNTYPE operator,(Box__USE_PARENS_WITH_THIS_EXPRESSION<T> value)
+        {
+            m_value = value.Unbox();
+            m_got = TRUE;
+            return m_value;
+        }
+
+        FORCEINLINE void operator,(___maybetemplate<0> &dummy)
+        {
+            m_got = TRUE;
+        }
+
+        FORCEINLINE BOOL GotReturn()
+        {
+            return m_got;
+        }
+    };
+
+    // This type ensures that postconditions were run via RETURN or RETURN_VOID
+    class RanPostconditions
+    {
+    public:
+        bool ran;
+        int count;
+        const char *function;
+
+        FORCEINLINE RanPostconditions(const char *function)
+          : ran(false),
+            count(0),
+            function(function)
+        {
+        }
+
+        FORCEINLINE int operator++()
+        {
+            return ++count;
+        }
+
+        FORCEINLINE ~RanPostconditions()
+        {
+            // Note: __uncaught_exception() is not a perfect check. It will return TRUE during any exception
+            // processing. So, if there is a contract called from an exception filter (like our
+            // COMPlusFrameHandler) then it will return TRUE and the saftey check below will not be performed.
+            if (!__uncaught_exception())
+                ASSERT_CHECK(count == 0 || ran, function, "Didn't run postconditions - be sure to use RETURN at the end of the function");
+        }
+
+    };
+
+    // Set contract enforcement level
+    static void SetUnconditionalContractEnforcement(BOOL enforceUnconditionally);
+
+    // Check contract enforcement
+    static BOOL EnforceContract();
+
+ private:
+    static BOOL s_alwaysEnforceContracts;
+};
+
+class Contract: public BaseContract
+{
+   // Have to override this function in any derived class to indicate that a valid destructor is defined for this class
+   virtual void DestructorDefinedThatCallsRestore(){}
+
+   public:
+    NOTHROW_DECL ~Contract()
+    {
+        Restore();
+    }
+};
+
+#endif // ENABLE_CONTRACTS_IMPL
+
+
+#ifdef _DEBUG
+
+// Valid parameters for CONTRACT_VIOLATION macro
+enum ContractViolationBits
+{
+    ThrowsViolation = 0x00000001,  // suppress THROW tags in this scope
+    GCViolation     = 0x00000002,  // suppress GCTRIGGER tags in this scope
+    ModeViolation   = 0x00000004,  // suppress MODE_PREEMP and MODE_COOP tags in this scope
+    FaultViolation  = 0x00000008,  // suppress INJECT_FAULT assertions in this scope
+    FaultNotFatal   = 0x00000010,  // suppress INJECT_FAULT but not fault injection by harness
+    LoadsTypeViolation      = 0x00000040,  // suppress LOADS_TYPE tags in this scope
+    TakesLockViolation      = 0x00000080,  // suppress CAN_TAKE_LOCK tags in this scope
+    HostViolation           = 0x00000100,  // suppress HOST_CALLS tags in this scope
+
+    //These are not violation bits. We steal some bits out of the violation mask to serve as
+    // general flag bits.
+    CanFreeMe       = 0x00010000,  // If this bit is ON, the ClrDebugState was allocated by
+                                   // a version of utilcode that registers an Fls Callback to free
+                                   // the state. If this bit is OFF, the ClrDebugState was allocated
+                                   // by an old version of utilcode that doesn't. (And you can't
+                                   // assume that the old utilcode used the same allocator as the new utilcode.)
+                                   // (Most likely, this is because you are using an older shim with
+                                   // a newer mscorwks.dll)
+                                   //
+                                   // The Fls callback must only attempt to free debugstates that
+                                   // have this bit on.
+
+    BadDebugState   = 0x00020000,  // If we OOM creating the ClrDebugState, we return a pointer to
+                                   // a static ClrDebugState that has this bit turned on. (We don't
+                                   // want to slow down contracts with null tests everywhere.)
+                                   // Other than this specific bit, all other fields of the DebugState
+                                   // must be considered trash. You can stomp on them and you can bit-test them
+                                   // but you can't throw up any asserts based on them and you certainly
+                                   // can't deref any pointers stored in the bad DebugState.
+
+    AllViolation    = 0xFFFFFFFF,
+};
+
+#endif
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+// Global variables allow PRECONDITION and POSTCONDITION to be used outside contracts
+static const BaseContract::Operation ___op = (Contract::Operation) (Contract::Preconditions
+                                                                |Contract::Postconditions);
+enum {
+    ___disabled = 0
+};
+
+static UINT ___testmask;
+
+// End of global variables
+
+static int ___ran;
+
+class __SafeToUsePostCondition {
+public:
+    static int safe_to_use_postcondition() {return 0;};
+};
+
+class __YouCannotUseAPostConditionHere {
+private:
+    static int safe_to_use_postcondition() {return 0;};
+};
+
+typedef __SafeToUsePostCondition __PostConditionOK;
+
+// Uncomment the following line to disable runtime contracts completely - PRE/POST conditions will still be present
+//#define __FORCE_NORUNTIME_CONTRACTS__ 1
+
+#ifndef __FORCE_NORUNTIME_CONTRACTS__
+
+#define CONTRACT_SETUP(_contracttype, _returntype, _returnexp)          \
+    _returntype RETVAL;                                                 \
+    _contracttype ___contract;                                          \
+    Contract::Returner<_returntype> ___returner(RETVAL);                \
+    Contract::RanPostconditions ___ran(__FUNCTION__);                   \
+    Contract::Operation ___op = Contract::Setup;                        \
+    BOOL ___contract_enabled = FALSE;                                   \
+    DEBUG_ASSURE_NO_RETURN_BEGIN(CONTRACT)                              \
+    ___contract_enabled = Contract::EnforceContract();                  \
+    enum {___disabled = 0};                                             \
+    if (!___contract_enabled)                                           \
+        ___contract.Disable();                                          \
+    else                                                                \
+    {                                                                   \
+        enum { ___CheckMustBeInside_CONTRACT = 1 };                     \
+        if (0)                                                          \
+        {                                                               \
+        /* If you see an "unreferenced label" warning with this name, */\
+        /* Be sure that you have a RETURN at the end of your */         \
+        /* CONTRACT_VOID function */                                    \
+        ___run_postconditions_DID_YOU_FORGET_A_RETURN:                  \
+            if (___contract_enabled)                                    \
+            {                                                           \
+                ___op = Contract::Postconditions;                       \
+                ___ran.ran = true;                                      \
+            }                                                           \
+            else                                                        \
+            {                                                           \
+                DEBUG_OK_TO_RETURN_BEGIN(CONTRACT)                      \
+              ___run_return:                                            \
+                return _returnexp;                                      \
+                DEBUG_OK_TO_RETURN_END(CONTRACT)                        \
+            }                                                           \
+        }                                                               \
+        if (0)                                                          \
+        {                                                               \
+        ___run_preconditions:                                           \
+            ___op = Contract::Preconditions;                            \
+        }                                                               \
+        UINT ___testmask = 0;                                           \
+
+#define CONTRACTL_SETUP(_contracttype)                                  \
+    _contracttype ___contract;                                          \
+    BOOL ___contract_enabled = Contract::EnforceContract();             \
+    enum {___disabled = 0};                                             \
+    if (!___contract_enabled)                                           \
+        ___contract.Disable();                                          \
+    else                                                                \
+    {                                                                   \
+        typedef __YouCannotUseAPostConditionHere __PostConditionOK;     \
+        enum { ___CheckMustBeInside_CONTRACT = 1 };                     \
+        Contract::Operation ___op = Contract::Setup;                    \
+        enum {___disabled = 0};                                         \
+        if (0)                                                          \
+        {                                                               \
+          ___run_preconditions:                                         \
+            ___op = Contract::Preconditions;                            \
+        }                                                               \
+        if (0)                                                          \
+        {                                                               \
+        /* define for CONTRACT_END even though we can't get here */     \
+          ___run_return:                                                \
+            UNREACHABLE();                                              \
+        }                                                               \
+        UINT ___testmask = 0;                                           \
+
+#else // #ifndef __FORCE_NORUNTIME_CONTRACTS__
+
+#define CONTRACT_SETUP(_contracttype, _returntype, _returnexp)              \
+        _returntype RETVAL;                                                 \
+        Contract::Returner<_returntype> ___returner(RETVAL);                \
+        Contract::RanPostconditions ___ran(__FUNCTION__);                   \
+        Contract::Operation ___op = Contract::Setup;                        \
+        DEBUG_ASSURE_NO_RETURN_BEGIN(CONTRACT)                              \
+        BOOL ___contract_enabled = Contract::EnforceContract();             \
+        enum {___disabled = 0};                                             \
+        {                                                                   \
+            enum { ___CheckMustBeInside_CONTRACT = 1 };                     \
+            if (0)                                                          \
+            {                                                               \
+            /* If you see an "unreferenced label" warning with this name, */\
+            /* Be sure that you have a RETURN at the end of your */         \
+            /* CONTRACT_VOID function */                                    \
+            ___run_postconditions_DID_YOU_FORGET_A_RETURN:                  \
+                if (___contract_enabled)                                    \
+                {                                                           \
+                    ___op = Contract::Postconditions;                       \
+                    ___ran.ran = true;                                      \
+                }                                                           \
+                else                                                        \
+                {                                                           \
+                    DEBUG_OK_TO_RETURN_BEGIN(CONTRACT)                      \
+                  ___run_return:                                            \
+                    return _returnexp;                                      \
+                    DEBUG_OK_TO_RETURN_END(CONTRACT)                        \
+                }                                                           \
+            }                                                               \
+            if (0)                                                          \
+            {                                                               \
+            ___run_preconditions:                                           \
+                ___op = Contract::Preconditions;                            \
+            }                                                               \
+            UINT ___testmask = 0;                                           \
+
+
+
+
+#define CONTRACTL_SETUP(_contracttype)                                  \
+    BOOL ___contract_enabled = Contract::EnforceContract();             \
+    enum {___disabled = 0};                                             \
+    {                                                                   \
+        typedef __YouCannotUseAPostConditionHere __PostConditionOK;     \
+            enum { ___CheckMustBeInside_CONTRACT = 1 };                 \
+        Contract::Operation ___op = Contract::Setup;                    \
+        enum {___disabled = 0};                                         \
+        if (0)                                                          \
+        {                                                               \
+          ___run_preconditions:                                         \
+            ___op = Contract::Preconditions;                            \
+        }                                                               \
+        if (0)                                                          \
+        {                                                               \
+        /* define for CONTRACT_END even though we can't get here */     \
+          ___run_return:                                                \
+            UNREACHABLE();                                              \
+        }                                                               \
+        UINT ___testmask = 0;                                           \
+
+#endif // __FORCE_NORUNTIME_CONTRACTS__
+
+
+#define CUSTOM_CONTRACT(_contracttype, _returntype)                     \
+        typedef Contract::PseudoTemplate<_returntype> ___maybetemplate; \
+        CONTRACT_SETUP(_contracttype, _returntype, RETVAL)
+
+#define CUSTOM_CONTRACT_VOID(_contracttype)                             \
+        CONTRACT_SETUP(_contracttype, int, ;)
+
+#define CUSTOM_CONTRACTL(_contracttype)                                 \
+        CONTRACTL_SETUP(_contracttype)
+
+// Although this thing only needs to run in the Setup phase, we'll let it
+// run unconditionally. This way, the compiler will see a sequence like this:
+//
+//    THROWS; GC_TRIGGERS; FORBID_FAULT ==>
+//
+//    ___testmask |= constant
+//    ___testmask |= constant
+//    ___testmask |= constant
+//
+// and be able to fold all these into a single constant at runtime.
+//
+#define REQUEST_TEST(thetest, todisable)   (___testmask |= (___CheckMustBeInside_CONTRACT, (___disabled ? (todisable) : (thetest))))
+
+
+#define INJECT_FAULT(_statement)                                                            \
+        do                                                                                  \
+        {                                                                                   \
+            STATIC_CONTRACT_FAULT;                                                          \
+            REQUEST_TEST(Contract::FAULT_Inject, Contract::FAULT_Disabled);                 \
+            if (0)                                                                          \
+        {                                                                                   \
+            _statement;                                                                     \
+            }                                                                               \
+        }                                                                                   \
+        while(0)                                                                            \
+
+
+#define FORBID_FAULT  do { STATIC_CONTRACT_FORBID_FAULT; REQUEST_TEST(Contract::FAULT_Forbid, Contract::FAULT_Disabled); } while(0)
+
+#define THROWS        do { STATIC_CONTRACT_THROWS; REQUEST_TEST(Contract::THROWS_Yes, Contract::THROWS_Disabled); } while(0)
+
+#define NOTHROW       do { STATIC_CONTRACT_NOTHROW; REQUEST_TEST(Contract::THROWS_No,  Contract::THROWS_Disabled); } while(0)                                                               \
+
+#define ENTRY_POINT   STATIC_CONTRACT_ENTRY_POINT
+
+#define LOADS_TYPE(maxlevel)  do { REQUEST_TEST( ((maxlevel) + 1) << Contract::LOADS_TYPE_Shift, Contract::LOADS_TYPE_Disabled ); } while(0)
+
+#define CAN_TAKE_LOCK    do { STATIC_CONTRACT_CAN_TAKE_LOCK; REQUEST_TEST(Contract::CAN_TAKE_LOCK_Yes, Contract::CAN_TAKE_LOCK_Disabled); } while(0)
+
+#define CANNOT_TAKE_LOCK   do { STATIC_CONTRACT_CANNOT_TAKE_LOCK; REQUEST_TEST(Contract::CAN_TAKE_LOCK_No,  Contract::CAN_TAKE_LOCK_Disabled); } while(0)
+
+#define CANNOT_RETAKE_LOCK   do { REQUEST_TEST(Contract::CAN_RETAKE_LOCK_No,  Contract::CAN_RETAKE_LOCK_No_Disabled); } while(0)
+
+#define DEBUG_ONLY do { STATIC_CONTRACT_DEBUG_ONLY; REQUEST_TEST(Contract::DEBUG_ONLY_Yes, 0);  } while (0)
+
+#ifndef __DISABLE_PREPOST_CONDITIONS__
+#define PRECONDITION_MSG(_expression, _message)                                             \
+        do                                                                                  \
+        {                                                                                   \
+                   enum { ___CheckMustBeInside_CONTRACT = 1 };                                     \
+            REQUEST_TEST(Contract::PRECONDITION_Used, 0);                                   \
+            if ((___op&Contract::Preconditions) && !___disabled)                            \
+                ASSERT_CHECK(_expression, _message, "Precondition failure");                \
+        }                                                                                   \
+        while(0)
+
+
+#define PRECONDITION(_expression)                                                           \
+        PRECONDITION_MSG(_expression, NULL)
+
+#define POSTCONDITION_MSG(_expression, _message)                                            \
+        ++___ran;                                                                           \
+        if ((!(0 && __PostConditionOK::safe_to_use_postcondition())) &&                     \
+            (___op&Contract::Postconditions) &&                                             \
+            !___disabled)                                                                   \
+        {                                                                                   \
+            ASSERT_CHECK(_expression, _message, "Postcondition failure");                   \
+        }
+
+#define POSTCONDITION(_expression)                                                          \
+        POSTCONDITION_MSG(_expression, NULL)
+
+#define INSTANCE_CHECK                                                                      \
+        ___CheckMustBeInside_CONTRACT;                                                      \
+        if ((___op&Contract::Preconditions) && !___disabled)                                \
+            ASSERT_CHECK(CheckPointer(this), NULL, "Instance precheck failure");            \
+        ++___ran;                                                                           \
+        if ((___op&Contract::Postconditions) && !___disabled)                               \
+            ASSERT_CHECK(CheckPointer(this), NULL, "Instance postcheck failure");
+
+#define INSTANCE_CHECK_NULL                                                                 \
+        ___CheckMustBeInside_CONTRACT;                                                      \
+        if ((___op&Contract::Preconditions) && !___disabled)                                \
+            ASSERT_CHECK(CheckPointer(this, NULL_OK), NULL, "Instance precheck failure");   \
+        ++___ran;                                                                           \
+        if ((___op&Contract::Postconditions) && !___disabled)                               \
+            ASSERT_CHECK(CheckPointer(this, NULL_OK), NULL, "Instance postcheck failure");
+
+#define CONSTRUCTOR_CHECK                                                                   \
+        ___CheckMustBeInside_CONTRACT;                                                      \
+        ++___ran;                                                                           \
+        if ((___op&Contract::Postconditions) && !___disabled)                               \
+            ASSERT_CHECK(CheckPointer(this), NULL, "Instance postcheck failure");
+
+#define DESTRUCTOR_CHECK                                                                    \
+        ___CheckMustBeInside_CONTRACT;                                                      \
+        NOTHROW;                                                                            \
+        if ((___op&Contract::Preconditions) && !___disabled)                                \
+            ASSERT_CHECK(CheckPointer(this), NULL, "Instance precheck failure");
+#else // __DISABLE_PREPOST_CONDITIONS__
+
+
+#define PRECONDITION_MSG(_expression, _message)     do { } while(0)
+#define PRECONDITION(_expression)                   do { } while(0)
+#define POSTCONDITION_MSG(_expression, _message)    do { } while(0)
+#define POSTCONDITION(_expression)                  do { } while(0)
+#define INSTANCE_CHECK
+#define INSTANCE_CHECK_NULL
+#define CONSTRUCTOR_CHECK
+#define DESTRUCTOR_CHECK
+
+#endif // __DISABLE_PREPOST_CONDITIONS__
+
+#define UNCHECKED(thecheck)                                                                 \
+        do {                                                                                \
+            ANNOTATION_UNCHECKED(thecheck);                                                 \
+            enum {___disabled = 1 };                                                        \
+            thecheck;                                                                       \
+        } while(0)
+
+#define DISABLED(thecheck) UNCHECKED(thecheck)
+
+#define WRAPPER(thecheck) UNCHECKED(thecheck)
+
+// This keyword is redundant but it's handy for reducing the nuisance editing you
+// have to when repeatedly enabling and disabling contract items while debugging.
+// You shouldn't check in code that explicitly uses ENABLED.
+#define ENABLED(_check) _check
+
+
+#ifndef __FORCE_NORUNTIME_CONTRACTS__
+#define CONTRACTL_END                                                                       \
+        if (___op & Contract::Setup)                                                        \
+        {                                                                                   \
+            ___contract.DoChecks(___testmask, __FUNCTION__, __FILE__, __LINE__);            \
+            if (___testmask & Contract::PRECONDITION_Used)                                  \
+            {                                                                               \
+                goto ___run_preconditions;                                                  \
+            }                                                                               \
+        }                                                                                   \
+        else if (___op & Contract::Postconditions)                                          \
+        {                                                                                   \
+            goto ___run_return;                                                             \
+        }                                                                                   \
+        ___CheckMustBeInside_CONTRACT;                                                      \
+   }
+
+#else
+
+#define CONTRACTL_END                                                                       \
+        if (___op & Contract::Setup)                                                        \
+        {                                                                                   \
+            if (___testmask & Contract::PRECONDITION_Used)                                  \
+            {                                                                               \
+                goto ___run_preconditions;                                                  \
+            }                                                                               \
+        }                                                                                   \
+        else if (___op & Contract::Postconditions)                                          \
+        {                                                                                   \
+            goto ___run_return;                                                             \
+        }                                                                                   \
+        ___CheckMustBeInside_CONTRACT;                                                      \
+   }                                                                                        \
+
+#endif // __FORCE_NORUNTIME_CONTRACTS__
+
+#define CONTRACT_END   CONTRACTL_END                                                        \
+   DEBUG_ASSURE_NO_RETURN_END(CONTRACT)                                                     \
+
+
+// The final expression in the RETURN macro deserves special explanation (or something.)
+// The expression is constructed so as to be syntactically ambiguous, depending on whether
+// __maybetemplate is a template or not.  If it is a template, the expression is syntactically
+// correct as-is.  If it is not, the angle brackets are interpreted as
+// less than & greater than, and the expression is incomplete.  This is the point - we can
+// choose whether we need an expression or not based on the context in which the macro is used.
+// This allows the same RETURN macro to be used both in value-returning and void-returning
+// contracts.
+//
+// The "__returner ," portion of the expression is used instead of "RETVAL =", since ","
+// has lower precedence than "=". (Ain't overloaded operators fun.)
+//
+// Also note that the < and > operators on the non-template version of __maybetemplate
+// are overridden to "box" the return value in a special type and pass it
+// through to the __returner's "," operator.  This is so we can detect a case where an
+// operator with lower precedence than ">" is in the return expression - in such a case we
+// will get a type error message, which instructs that parens be placed around the return
+// value expression.
+
+#define RETURN_BODY                                                                         \
+    if (___returner.GotReturn())                                                            \
+        goto ___run_postconditions_DID_YOU_FORGET_A_RETURN;                                 \
+    else                                                                                    \
+        ___returner, * new ___maybetemplate < 0 >
+
+
+// We have two versions of the RETURN macro.  CONTRACT_RETURN is for use inside the CONTRACT
+// scope where it is OK to return this way, even though the CONTRACT macro itself does not
+// allow a return.  RETURN is for use inside the function body where it might not be OK
+// to return and we need to ensure that we don't allow a return where one should not happen
+//
+#define RETURN                                                                              \
+    while (DEBUG_ASSURE_SAFE_TO_RETURN, TRUE)                                               \
+        RETURN_BODY                                                                         \
+
+#define RETURN_VOID                                                                         \
+    RETURN
+
+#define CONTRACT_RETURN                                                                     \
+    while (___CheckMustBeInside_CONTRACT, TRUE)                                             \
+        RETURN_BODY                                                                         \
+
+#define CONTRACT_RETURN_VOID                                                                \
+    CONTRACT_RETURN                                                                         \
+
+#if 0
+#define CUSTOM_LIMITED_METHOD_CONTRACT(_contracttype)                                                 \
+    {                                                                                       \
+        _contracttype ___contract;                                                          \
+        STATIC_CONTRACT_LEAF;                                                               \
+        ___contract.DoChecks(Contract::THROWS_No|Contract::GC_NoTrigger|Contract::MODE_Disabled|Contract::FAULT_Disabled);     \
+        /* Should add some assertion mechanism to ensure no other contracts are called */   \
+    }
+#else
+#define CUSTOM_LIMITED_METHOD_CONTRACT(_contracttype)                                                 \
+    {                                                                                       \
+        STATIC_CONTRACT_LEAF;                                                               \
+    }
+#endif
+
+#define CUSTOM_WRAPPER_NO_CONTRACT(_contracttype)                                              \
+    {                                                                                       \
+        /* Should add some assertion mechanism to ensure one other contract is called */    \
+        STATIC_CONTRACT_WRAPPER;                                                            \
+    }
+
+#define CONTRACT_THROWS()                                                                   \
+    {                                                                                       \
+        ::GetClrDebugState()->CheckOkayToThrow(__FUNCTION__, __FILE__, __LINE__);           \
+    }
+
+#define CONTRACT_THROWSEX(__func, __file, __line)                                           \
+    {                                                                                       \
+        ::GetClrDebugState()->CheckOkayToThrow(__func, __file, __line);                     \
+    }
+
+#else // ENABLE_CONTRACTS_IMPL
+#define CUSTOM_CONTRACT(_contracttype, _returntype)         if (0) {  struct YouCannotUseThisHere { int x; };   // This temporary typedef allows retail use of
+#define CUSTOM_CONTRACT_VOID(_contracttype)                 if (0) {  struct YouCannotUseThisHere { int x; };   // FORBIDGC_LOADER_USE_ENABLED
+#define CUSTOM_CONTRACTL(_contracttype)                     if (0) {  struct YouCannotUseThisHere { int x; };   // inside contracts and asserts but nowhere else.
+
+#define INJECT_FAULT(_statement)
+#define FORBID_FAULT
+#define THROWS
+#define NOTHROW
+#define CAN_TAKE_LOCK
+#define CANNOT_TAKE_LOCK
+#define CANNOT_RETAKE_LOCK
+#define LOADS_TYPE(maxlevel)
+#define ENTRY_POINT
+
+#ifdef _DEBUG
+// This can only appear in a debug function so don't define it non-debug
+#define DEBUG_ONLY STATIC_CONTRACT_DEBUG_ONLY
+#else
+#define DEBUG_ONLY
+#endif
+
+#define PRECONDITION_MSG(_expression, _message)     do { } while(0)
+#define PRECONDITION(_expression)                   do { } while(0)
+#define POSTCONDITION_MSG(_expression, _message)    do { } while(0)
+#define POSTCONDITION(_expression)                  do { } while(0)
+#define INSTANCE_CHECK
+#define INSTANCE_CHECK_NULL
+#define CONSTRUCTOR_CHECK
+#define DESTRUCTOR_CHECK
+#define UNCHECKED(thecheck)
+#define DISABLED(thecheck)
+#define WRAPPER(thecheck)
+#define ENABLED(_check)
+#define CONTRACT_END                                        }
+#define CONTRACTL_END                                       }
+
+#define CUSTOM_LIMITED_METHOD_CONTRACT(_contracttype) \
+    {                                                                                       \
+        /* Should add some assertion mechanism to ensure one other contract is called */    \
+        STATIC_CONTRACT_LEAF;                                                            \
+    }
+#define CUSTOM_WRAPPER_NO_CONTRACT(_contracttype) \
+    {                                                                                       \
+        /* Should add some assertion mechanism to ensure one other contract is called */    \
+        STATIC_CONTRACT_WRAPPER;                                                            \
+    }
+
+
+#define RETURN return
+#define RETURN_VOID RETURN
+
+#define CONTRACT_THROWS()
+#define CONTRACT_THROWSEX(__func, __file, __line)
+
+#endif  // ENABLE_CONTRACTS_IMPL
+
+
+#define CONTRACT(_returntype)  CUSTOM_CONTRACT(Contract, _returntype)
+#define CONTRACT_VOID  CUSTOM_CONTRACT_VOID(Contract)
+#define CONTRACTL CUSTOM_CONTRACTL(Contract)
+
+// See description near the top of the file
+#define LIMITED_METHOD_CONTRACT CUSTOM_LIMITED_METHOD_CONTRACT(Contract)
+
+#define WRAPPER_NO_CONTRACT CUSTOM_WRAPPER_NO_CONTRACT(Contract)
+
+// GC_NOTRIGGER allowed but not currently enforced at runtime
+#define GC_NOTRIGGER STATIC_CONTRACT_GC_NOTRIGGER
+#define GC_TRIGGERS static_assert(false, "TriggersGC not supported in utilcode contracts")
+
+#ifdef ENABLE_CONTRACTS_IMPL
+template <UINT_PTR VIOLATION_MASK>
+class ContractViolationHolder
+{
+public:
+    ContractViolationHolder()
+    {
+        m_pviolationmask = NULL;
+        m_oldviolationmask = 0;
+    }
+
+    DEBUG_NOINLINE void Enter();
+
+    DEBUG_NOINLINE void Leave()
+    {
+        SCAN_SCOPE_END;
+        LeaveInternal();
+    };
+
+protected:
+    // We require that violationMask is passed as a parameter here to hopefully defeat the
+    // compiler's desire to fold all the Enter and Ctor implementations together.
+    FORCEINLINE void EnterInternal(UINT_PTR violationMask)
+    {
+        _ASSERTE(0 == (violationMask & ~(ThrowsViolation | GCViolation | ModeViolation | FaultViolation |
+            FaultNotFatal | HostViolation |
+            TakesLockViolation | LoadsTypeViolation)) ||
+            violationMask == AllViolation);
+
+        m_pviolationmask = GetClrDebugState()->ViolationMaskPtr();
+        m_oldviolationmask = *m_pviolationmask;
+        *m_pviolationmask = (m_oldviolationmask | violationMask);
+    };
+
+    FORCEINLINE void LeaveInternal()
+    {
+        // This can be used in places where our debug state has been destroyed, so check for it first.
+        if (CheckClrDebugState())
+        {
+            _ASSERTE(m_pviolationmask != NULL);
+            *m_pviolationmask = m_oldviolationmask;
+        }
+    };
+
+    UINT_PTR *m_pviolationmask;
+    UINT_PTR m_oldviolationmask;
+};
+
+template <UINT_PTR VIOLATION_MASK>
+class AutoCleanupContractViolationHolder : ContractViolationHolder<VIOLATION_MASK>
+{
+public:
+    DEBUG_NOINLINE AutoCleanupContractViolationHolder(BOOL fEnterViolation = TRUE);
+
+    DEBUG_NOINLINE ~AutoCleanupContractViolationHolder()
+    {
+        SCAN_SCOPE_END;
+        this->LeaveInternal();
+    };
+};
+
+#endif  // ENABLE_CONTRACTS_IMPL
+
+#ifdef ENABLE_CONTRACTS_IMPL
+#define BEGIN_CONTRACT_VIOLATION(violationmask)                             \
+    {                                                                       \
+        ContractViolationHolder<violationmask> __violationHolder_onlyOneAllowedPerScope;   \
+        __violationHolder_onlyOneAllowedPerScope.Enter();                   \
+        DEBUG_ASSURE_NO_RETURN_BEGIN(CONTRACT)                              \
+
+// Use this to jump out prematurely from a violation.  Used for EH
+// when the function might not return
+#define RESET_CONTRACT_VIOLATION()                                          \
+        __violationHolder_onlyOneAllowedPerScope.Leave();                   \
+
+#define END_CONTRACT_VIOLATION                                              \
+        DEBUG_ASSURE_NO_RETURN_END(CONTRACT)                                \
+        __violationHolder_onlyOneAllowedPerScope.Leave();                   \
+    }                                                                       \
+
+// See description near the top of the file
+#define CONTRACT_VIOLATION(violationMask)                                   \
+    AutoCleanupContractViolationHolder<violationMask> __violationHolder_onlyOneAllowedPerScope;
+
+
+// Reasons for having the violation.  Use one of these values as an additional parameter to
+// E.g. PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonContractInfrastructure)
+// New values and explanations can be added when needed.
+enum PermanentContractViolationReason
+{
+    ReasonContractInfrastructure,        // This violation is there for contract test or infrastructure purposes.
+    ReasonDebugOnly,                     // Code path doesn't occur on retail builds
+    ReasonNonShippingCode,               // Code runs in undocumented non-shipping feature
+    ReasonIBC,                           // Code runs in IBC scenarios only and the violation is safe.
+    ReasonNGEN,                          // Code runs in NGEN scenarios only and the violation is safe.
+    ReasonProfilerCallout,               // Profiler implementers are guaranteed not to throw.
+    ReasonUnsupportedForSQLF1Profiling,  // This code path violates HOST_NOCALLS, but that's ok b/c SQL will never
+                                         // invoke it, and thus SQL/F1 profiling (the primary reason to enforce
+                                         // HOST_NOCALLS) is not in danger.
+    ReasonRuntimeReentrancy,             // e.g. SafeQueryInterface
+    ReasonShutdownOnly,                  // Code path only runs as part of Shutdown and the violation is safe.
+    ReasonSOTolerance,                   // We would like to redesign SO contracts anyways
+    ReasonStartupOnly,                   // Code path only runs as part of Startup and the violation is safe.
+    ReasonWorkaroundForScanBug,          // Violation is needed because of a bug in SCAN
+    ReasonProfilerAsyncCannotRetakeLock, // Profiler may call this from redirected thread, causing a CANNOT_TAKE_LOCK
+                                         // violation, but the scope is still protected with CANNOT_RETAKE_LOCK
+    ReasonILStubWillNotThrow,            // Specially-crafted reverse COM IL stubs will not throw
+};
+
+// See the discussion near the top of the file on the use of PERMANENT_CONTRACT_VIOLATION
+// The reasonEnum is currently only used for documentation and searchability.  Here
+// we have the compiler check for a typo.
+#define PERMANENT_CONTRACT_VIOLATION(violationMask, reasonEnum)            \
+    if (0)                                                                 \
+        PermanentContractViolationReason reason = reasonEnum;              \
+    CONTRACT_VIOLATION(violationMask)
+
+#define CONDITIONAL_CONTRACT_VIOLATION(violationMask, condition)            \
+    AutoCleanupContractViolationHolder<violationMask> __violationHolder_onlyOneAllowedPerScope((condition));
+
+#else
+#define BEGIN_CONTRACT_VIOLATION(violationmask)
+#define RESET_CONTRACT_VIOLATION()
+#define END_CONTRACT_VIOLATION
+#define CONTRACT_VIOLATION(violationmask)
+#define CONDITIONAL_CONTRACT_VIOLATION(violationMask, condition)
+#define PERMANENT_CONTRACT_VIOLATION(violationMask, reasonEnum)
+#endif
+
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// Holder for setting up a faultforbid region
+class FaultForbidHolder
+{
+ public:
+    DEBUG_NOINLINE FaultForbidHolder(BOOL fConditional, BOOL fAlloc, const char *szFunction, const char *szFile, int lineNum)
+    {
+        SCAN_SCOPE_BEGIN;
+        STATIC_CONTRACT_FORBID_FAULT;
+
+        m_fConditional = fConditional;
+        if (m_fConditional)
+        {
+            m_pClrDebugState = GetClrDebugState(fAlloc);
+
+            //
+            // If we fail to get a debug state, then we must not be allocating and
+            // we simply no-op this holder.
+            //
+            if (m_pClrDebugState == NULL)
+            {
+                _ASSERTE(!fAlloc);
+                m_fConditional = FALSE;
+                return;
+            }
+
+            m_oldClrDebugState = *m_pClrDebugState;
+
+            m_pClrDebugState->ViolationMaskReset( FaultViolation|FaultNotFatal );
+            m_pClrDebugState->SetFaultForbid();
+
+            m_ContractStackRecord.m_szFunction = szFunction;
+            m_ContractStackRecord.m_szFile     = szFile;
+            m_ContractStackRecord.m_lineNum    = lineNum;
+            m_ContractStackRecord.m_testmask   = (Contract::ALL_Disabled & ~((UINT)(Contract::FAULT_Mask))) | Contract::FAULT_Forbid;
+            m_ContractStackRecord.m_construct  = "FAULT_FORBID";
+            m_pClrDebugState->LinkContractStackTrace( &m_ContractStackRecord );
+        }
+    }
+
+    DEBUG_NOINLINE ~FaultForbidHolder()
+    {
+        SCAN_SCOPE_END;
+
+        if (m_fConditional)
+        {
+            *m_pClrDebugState = m_oldClrDebugState;
+        }
+    }
+
+ private:
+    ClrDebugState      *m_pClrDebugState;
+    ClrDebugState       m_oldClrDebugState;
+    BOOL m_fConditional;
+    ContractStackRecord m_ContractStackRecord;
+
+};
+#endif  // ENABLE_CONTRACTS_IMPL
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+#define FAULT_FORBID() FaultForbidHolder _ffh(TRUE, TRUE, __FUNCTION__, __FILE__, __LINE__);
+#define FAULT_FORBID_NO_ALLOC() FaultForbidHolder _ffh(TRUE, FALSE, __FUNCTION__, __FILE__, __LINE__);
+#define MAYBE_FAULT_FORBID(cond) FaultForbidHolder _ffh(cond, TRUE, __FUNCTION__, __FILE__, __LINE__);
+#define MAYBE_FAULT_FORBID_NO_ALLOC(cond) FaultForbidHolder _ffh(cond, FALSE, __FUNCTION__, __FILE__, __LINE__);
+
+#else   // ENABLE_CONTRACTS_IMPL
+
+#define FAULT_FORBID() ;
+#define FAULT_FORBID_NO_ALLOC() ;
+#define MAYBE_FAULT_FORBID(cond) ;
+#define MAYBE_FAULT_FORBID_NO_ALLOC(cond) ;
+
+#endif  // ENABLE_CONTRACTS_IMPL
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+inline BOOL AreFaultsForbiddenHelper()
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+
+    ClrDebugState *pClrDebugState = CheckClrDebugState();
+    if (!pClrDebugState)
+    {
+        // By default, faults are not forbidden. Not the most desirable default
+        // but we'd never get this debug infrastructure bootstrapped otherwise.
+        return FALSE;
+    }
+    else
+    {
+        return pClrDebugState->IsFaultForbid() && (!(pClrDebugState->ViolationMask() & (FaultViolation|FaultNotFatal|BadDebugState)));
+    }
+}
+
+#define ARE_FAULTS_FORBIDDEN() AreFaultsForbiddenHelper()
+#else
+
+// If you got an error about ARE_FAULTS_FORBIDDEN being undefined, it's because you tried
+// to use this predicate in a free build outside of a CONTRACT or ASSERT.
+//
+#define ARE_FAULTS_FORBIDDEN() (sizeof(YouCannotUseThisHere) != 0)
+#endif
+
+
+// This allows a fault-forbid region to invoke a non-mandatory allocation, such as for the
+// purpose of growing a lookaside cache (if the allocation fails, the code can abandon the
+// cache growing operation without negative effect.)
+//
+// Although it's implemented using CONTRACT_VIOLATION(), it's not a bug to have this in the code.
+//
+// It *is* a bug to use this to hide a situation where an OOM is genuinely fatal but not handled.
+#define FAULT_NOT_FATAL() CONTRACT_VIOLATION(FaultNotFatal)
+
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+//------------------------------------------------------------------------------------
+// Underlying class support for TRIGGERS_TYPE_LOAD and OVERRIDE_TYPE_LOAD_LEVEL_LIMIT.
+// Don't reference this class directly. Use the macros.
+//------------------------------------------------------------------------------------
+class LoadsTypeHolder
+{
+ public:
+    LoadsTypeHolder(BOOL     fConditional,
+                    UINT     newLevel,
+                    BOOL     fEnforceLevelChangeDirection,
+                    const char    *szFunction,
+                    const char    *szFile,
+                    int      lineNum
+                   );
+
+    ~LoadsTypeHolder();
+
+ private:
+    ClrDebugState      *m_pClrDebugState;
+    ClrDebugState       m_oldClrDebugState;
+    BOOL                m_fConditional;
+    ContractStackRecord m_contractStackRecord;
+
+};
+
+#endif  // ENABLE_CONTRACTS_IMPL
+
+
+//------------------------------------------------------------------------------------
+// TRIGGERS_TYPE_LOAD(newLevel)
+//    Works just LOADS_TYPE in contracts but lets you protect individual scopes
+//
+// OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel)
+//    Sets a new limit just like TRIGGERS_TYPE_LOAD but does not restrict you
+//    to decreasing the limit. Only the loader should use this and only when it
+//    can prove structurally that no recursion will occur as a result.
+//------------------------------------------------------------------------------------
+#ifdef ENABLE_CONTRACTS_IMPL
+
+#define TRIGGERS_TYPE_LOAD(newLevel)                            LoadsTypeHolder _lth(TRUE,    newLevel, TRUE,  __FUNCTION__, __FILE__, __LINE__);
+#define MAYBE_TRIGGERS_TYPE_LOAD(newLevel, fEnable)             LoadsTypeHolder _lth(fEnable, newLevel, TRUE,  __FUNCTION__, __FILE__, __LINE__);
+#define OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel)                LoadsTypeHolder _lth(TRUE,    newLevel, FALSE, __FUNCTION__, __FILE__, __LINE__);
+#define MAYBE_OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel, fEnable) LoadsTypeHolder _lth(fEnable, newLevel, FALSE, __FUNCTION__, __FILE__, __LINE__);
+
+#else   // ENABLE_CONTRACTS_IMPL
+
+#define TRIGGERS_TYPE_LOAD(newLevel)
+#define MAYBE_TRIGGERS_TYPE_LOAD(newLevel, fEnable)
+#define OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel)
+#define MAYBE_OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel, fEnable)
+
+#endif  // ENABLE_CONTRACTS_IMPL
+
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+// This sets up a marker that says its okay to throw on this thread. This is not a public macro, and should only be
+// used from within the implementation of various try/catch macros.
+class ClrTryMarkerHolder
+{
+public:
+    DEBUG_NOINLINE ClrTryMarkerHolder()
+    {
+        SCAN_SCOPE_BEGIN;
+        STATIC_CONTRACT_THROWS;
+
+        m_pClrDebugState = GetClrDebugState();
+        m_oldOkayToThrowValue = m_pClrDebugState->IsOkToThrow();
+        m_pClrDebugState->SetOkToThrow();
+    }
+
+    DEBUG_NOINLINE ~ClrTryMarkerHolder()
+    {
+        SCAN_SCOPE_END;
+
+        m_pClrDebugState->SetOkToThrow( m_oldOkayToThrowValue );
+    }
+
+private:
+    BOOL           m_oldOkayToThrowValue;
+    ClrDebugState *m_pClrDebugState;
+};
+
+#define CLR_TRY_MARKER() ClrTryMarkerHolder ___tryMarkerHolder;
+
+#else // ENABLE_CONTRACTS_IMPL
+
+#define CLR_TRY_MARKER()
+
+#endif
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// Note: This routine will create a ClrDebugState if called for the first time.
+// It cannot return NULL (see comment for InitClrDebugState).
+inline ClrDebugState *GetClrDebugState(BOOL fAlloc)
+{
+    STATIC_CONTRACT_LIMITED_METHOD;
+
+    ClrDebugState *pState = CheckClrDebugState();
+
+    if (pState)
+    {
+        return pState;
+    }
+
+    if (fAlloc)
+    {
+        return CLRInitDebugState();
+    }
+
+    return NULL;
+}
+#endif // ENABLE_CONTRACTS_IMPL
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+class HostNoCallHolder
+{
+    public:
+    DEBUG_NOINLINE HostNoCallHolder()
+        {
+        SCAN_SCOPE_BEGIN;
+        STATIC_CONTRACT_HOST_NOCALLS;
+
+            m_clrDebugState = GetClrDebugState();
+            m_previousState = m_clrDebugState->SetHostCaller(FALSE);
+        }
+
+    DEBUG_NOINLINE ~HostNoCallHolder()
+        {
+        SCAN_SCOPE_END;
+
+            m_clrDebugState->SetHostCaller(m_previousState);
+        }
+
+     private:
+        BOOL m_previousState;
+        ClrDebugState* m_clrDebugState;
+
+};
+
+#define BEGIN_HOST_NOCALL_CODE \
+    {                             \
+        HostNoCallHolder __hostNoCallHolder;        \
+        CantAllocHolder __cantAlloc;
+
+#define END_HOST_NOCALL_CODE   \
+    }
+
+#else // ENABLE_CONTRACTS_IMPL
+#define BEGIN_HOST_NOCALL_CODE                      \
+    {                                               \
+        CantAllocHolder __cantAlloc;                \
+
+#define END_HOST_NOCALL_CODE                        \
+    }
+#endif
+
+
+#if defined(ENABLE_CONTRACTS_IMPL)
+
+// Macros to indicate we're taking or releasing locks
+
+// Most general macros, not used directly
+#define LOCK_TAKEN_MULTIPLE(dbgStateLockType, cEntrances, pvLock)    \
+    ::GetClrDebugState()->LockTaken((dbgStateLockType), (cEntrances), (void*) (pvLock), __FUNCTION__, __FILE__, __LINE__)
+#define LOCK_RELEASED_MULTIPLE(dbgStateLockType, cExits, pvLock)     \
+    ::GetClrDebugState()->LockReleased((dbgStateLockType), (cExits), (void*) (pvLock))
+
+// Use these only if you need to force multiple entrances or exits in a single
+// line (e.g., to restore the lock to a previous state). CRWLock in vm\rwlock.cpp does this
+#define EE_LOCK_TAKEN_MULTIPLE(cEntrances, pvLock)                          \
+    LOCK_TAKEN_MULTIPLE(kDbgStateLockType_EE, cEntrances, pvLock)
+#define EE_LOCK_RELEASED_MULTIPLE(cExits, pvLock)                           \
+    LOCK_RELEASED_MULTIPLE(kDbgStateLockType_EE, cExits, pvLock)
+#define HOST_BREAKABLE_CRST_TAKEN_MULTIPLE(cEntrances, pvLock)              \
+    LOCK_TAKEN_MULTIPLE(kDbgStateLockType_HostBreakableCrst, cEntrances, pvLock)
+#define HOST_BREAKABLE_CRST_RELEASED_MULTIPLE(cExits, pvLock)               \
+    LOCK_RELEASED_MULTIPLE(kDbgStateLockType_HostBreakableCrst, cExits, pvLock)
+#define USER_LOCK_TAKEN_MULTIPLE(cEntrances, pvLock)                        \
+    LOCK_TAKEN_MULTIPLE(kDbgStateLockType_User, cEntrances, pvLock)
+#define USER_LOCK_RELEASED_MULTIPLE(cExits, pvLock)                         \
+    LOCK_RELEASED_MULTIPLE(kDbgStateLockType_User, cExits, pvLock)
+
+// These are most typically used
+#define EE_LOCK_TAKEN(pvLock)                   \
+    LOCK_TAKEN_MULTIPLE(kDbgStateLockType_EE, 1, pvLock)
+#define EE_LOCK_RELEASED(pvLock)                \
+    LOCK_RELEASED_MULTIPLE(kDbgStateLockType_EE, 1, pvLock)
+#define HOST_BREAKABLE_CRST_TAKEN(pvLock)       \
+    LOCK_TAKEN_MULTIPLE(kDbgStateLockType_HostBreakableCrst, 1, pvLock)
+#define HOST_BREAKABLE_CRST_RELEASED(pvLock)    \
+    LOCK_RELEASED_MULTIPLE(kDbgStateLockType_HostBreakableCrst, 1, pvLock)
+#define USER_LOCK_TAKEN(pvLock)                 \
+    LOCK_TAKEN_MULTIPLE(kDbgStateLockType_User, 1, pvLock)
+#define USER_LOCK_RELEASED(pvLock)              \
+    LOCK_RELEASED_MULTIPLE(kDbgStateLockType_User, 1, pvLock)
+
+#else // defined(ENABLE_CONTRACTS_IMPL)
+
+#define LOCK_TAKEN_MULTIPLE(dbgStateLockType, cEntrances, pvLock)
+#define LOCK_RELEASED_MULTIPLE(dbgStateLockType, cExits, pvLock)
+#define EE_LOCK_TAKEN_MULTIPLE(cEntrances, pvLock)
+#define EE_LOCK_RELEASED_MULTIPLE(cExits, pvLock)
+#define HOST_BREAKABLE_CRST_TAKEN_MULTIPLE(cEntrances, pvLock)
+#define HOST_BREAKABLE_CRST_RELEASED_MULTIPLE(cExits, pvLock)
+#define USER_LOCK_TAKEN_MULTIPLE(cEntrances, pvLock)
+#define USER_LOCK_RELEASED_MULTIPLE(cExits, pvLock)
+#define EE_LOCK_TAKEN(pvLock)
+#define EE_LOCK_RELEASED(pvLock)
+#define HOST_BREAKABLE_CRST_TAKEN(pvLock)
+#define HOST_BREAKABLE_CRST_RELEASED(pvLock)
+#define USER_LOCK_TAKEN(pvLock)
+#define USER_LOCK_RELEASED(pvLock)
+
+#endif // defined(ENABLE_CONTRACTS_IMPL)
+
+#if defined(ENABLE_CONTRACTS_IMPL)
+
+// Abbreviation for an assert that is only considered if there is a valid
+// ClrDebugState available.  Useful if you want to assert based on the value
+// of GetDbgStateLockCount(), where a return of 0 (the default if there is no
+// valid ClrDebugState available) would cause your assert to fire.  The variable
+// __pClrDebugState is set to the current ClrDebugState, and may be used within
+// your assert expression
+#define ASSERT_UNLESS_NO_DEBUG_STATE(e)                                                 \
+    {                                                                                   \
+        ClrDebugState * __pClrDebugState = GetClrDebugState();                          \
+        _ASSERTE(((__pClrDebugState->ViolationMask() & BadDebugState) != 0) || (e));    \
+    }
+
+#else // defined(ENABLE_CONTRACTS_IMPL)
+
+#define ASSERT_UNLESS_NO_DEBUG_STATE(e)
+
+#endif // defined(ENABLE_CONTRACTS_IMPL)
+
+
+//-----------------------------------------------------------------------------
+// Debug support to ensure that nobody calls New on the helper thread.
+// This is for interop debugging.
+// They should be using the InteropSafe heap.
+// Having this in the meantime allows us to
+// assert that the helper thread never calls new, and maintain a finite list of
+// exceptions (bugs).
+// Eventually, all those bugs should be fixed this holder can be completely removed.
+//
+// It is also the case that we disallow allocations when any thread is OS suspended
+// This happens for a short time when we are suspending the EE.   We supress both
+// of these.
+//
+// @todo- ideally this would be rolled into the ContractViolation.
+// also, we'd have contract bit for whether APIs can be called on the helper thread.
+// @todo - if we really wanted to be strict, we should make this per-thread.
+//-----------------------------------------------------------------------------
+#ifdef ENABLE_CONTRACTS_IMPL
+extern Volatile<LONG> g_DbgSuppressAllocationAsserts;
+#define SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE CounterHolder _AllowNewOnHelperHolder(&g_DbgSuppressAllocationAsserts);
+#else
+// Nothing in retail since this holder just disabled an assert.
+#define SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Support for contracts in DAC builds
+//
+// At the moment, most of the contract system is disabled in DAC builds.
+// We do however want some simple static contracts in order to support static
+// analysis tools that run on mscordacwks.dll like DacCop.
+// Note that we want these static contracts in both DEBUG and retail builds.
+// We also already get simple static contracts like WRAPPER and LEAF.
+//
+//-----------------------------------------------------------------------------
+#if defined(DACCESS_COMPILE)
+
+// SUPPORTS_DAC is an annotation that says the function is designed to be used in DAC builds.
+// This enables full DacCop analysis on the function, including verifying that all functions that are
+// called also support DAC.
+#define SUPPORTS_DAC do { STATIC_CONTRACT_SUPPORTS_DAC; } while(0)
+
+// Normally a function can be annotated just with WRAPPER_NO_CONTRACT, which (in addition to the normal
+// contract meaning) indicates to DacCop that the function should be considered to support DAC when
+// it is called from a supports-dac function.  This is to avoid having to add a DAC-specific contract
+// to all the trivial one-line wrapper functions we have.
+// However, we occasionally want these semantics even for functions which are not appropriate to label
+// as WRAPPER_NO_CONTRACT.  For example, a template function may support DAC for certain template arguments,
+// but not others (due to the functions it calls).  We want to ensure that when such a function is called
+// in a DAC code path, analysis is enabled on that particular instantiation including checking all of the
+// call targets specific to this template instantiation.  But we don't want to require that the call targets
+// for ALL instantiations support dac, since we may not even be using them in DAC code paths.  Ideally we'd
+// remove any such code from the DAC build, but this will take time.
+#define SUPPORTS_DAC_WRAPPER do { STATIC_CONTRACT_WRAPPER;  } while(0)
+
+// SUPPORTS_DAC_HOST_ONLY indicates that a function is allowed to be called in DAC builds, but rather
+// than being a normal DAC function which operates on marshalled data, it is a host-only utility function
+// that knows nothing about DAC and operates solely on the host.  For example, DbgAssertDialog is a utility
+// function for popping assert dialogs - there is nothing DAC-specific about this.  Ideally such utility
+// functions would be confined to their own library which had no access to DAC functionality, and which
+// is not analyzed by DacCop.  At the moment splitting utilcode into two variations like this is too
+// painful, but we hope to do it in the future (primarily to support functions which can be used in either
+// DAC or host-only mode).
+// WARNING: This contract disables DacCop analysis  on the function and any functions it calls, so it
+// should be used very carefully.
+#define SUPPORTS_DAC_HOST_ONLY do { STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY; } while(0)
+
+#else
+#define SUPPORTS_DAC
+#define SUPPORTS_DAC_HOST_ONLY
+#define SUPPORTS_DAC_WRAPPER
+#endif // DACCESS_COMPILE
+
+// LIMITED_METHOD_DAC_CONTRACT is a shortcut for LIMITED_METHOD_CONTRACT and SUPPORTS_DAC. Usefull for one-line inline functions.
+#define LIMITED_METHOD_DAC_CONTRACT LIMITED_METHOD_CONTRACT; SUPPORTS_DAC
+
+//
+// The default contract is the recommended contract for ordinary code.
+// The ordinary code can throw or trigger GC any time, does not operate
+// on raw object refs, etc.
+//
+
+#define STANDARD_VM_CHECK           \
+    THROWS;
+
+#define STANDARD_VM_CONTRACT        \
+    CONTRACTL                   \
+    {                           \
+        STANDARD_VM_CHECK;          \
+    }                           \
+    CONTRACTL_END;              \
+
+#define STATIC_STANDARD_VM_CONTRACT         \
+    STATIC_CONTRACT_THROWS;             \
+    STATIC_CONTRACT_GC_TRIGGERS;        \
+    STATIC_CONTRACT_MODE_PREEMPTIVE;
+
+#define AFTER_CONTRACTS
+#include "volatile.h"
+
+#endif  // CONTRACT_H_
diff --git a/src/inc/contract.inl b/src/inc/contract.inl
new file mode 100644 (file)
index 0000000..06ee1ef
--- /dev/null
@@ -0,0 +1,635 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// Contract.inl
+//
+
+// ! I am the owner for issues in the contract *infrastructure*, not for every
+// ! CONTRACT_VIOLATION dialog that comes up. If you interrupt my work for a routine
+// ! CONTRACT_VIOLATION, you will become the new owner of this file.
+// ---------------------------------------------------------------------------
+
+#ifndef CONTRACT_INL_
+#define CONTRACT_INL_
+
+#include "contract.h"
+#include <string.h>
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+inline void BaseContract::DoChecks(UINT testmask, _In_z_ const char *szFunction, _In_z_ const char *szFile, int lineNum)
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    // Cache the pointer to our ClrDebugState if it's not already cached.
+    // Derived types could set up this ptr before calling BaseContract::DoChecks if they have access to the Thread ptr
+    if (m_pClrDebugState == NULL)
+    {
+        m_pClrDebugState = GetClrDebugState();
+    }
+
+    // Save the incoming contents for restoration in the destructor
+    m_IncomingClrDebugState = *m_pClrDebugState;
+
+    m_testmask = testmask;  // Save the testmask for destructor
+
+    // Setup the new stack record.
+    m_contractStackRecord.m_szFunction = szFunction;
+    m_contractStackRecord.m_szFile     = szFile;
+    m_contractStackRecord.m_lineNum    = lineNum;
+    m_contractStackRecord.m_testmask   = testmask;
+    m_contractStackRecord.m_construct  = "CONTRACT";
+
+    // Link the new ContractStackRecord into the chain for this thread.
+    m_pClrDebugState->LinkContractStackTrace( &m_contractStackRecord );
+
+    if (testmask & DEBUG_ONLY_Yes)
+    {
+        m_pClrDebugState->SetDebugOnly();
+    }
+
+    switch (testmask & FAULT_Mask)
+    {
+        case FAULT_Forbid:
+            m_pClrDebugState->ViolationMaskReset( FaultViolation|FaultNotFatal );
+            m_pClrDebugState->SetFaultForbid();
+            break;
+
+        case FAULT_Inject:
+            if (m_pClrDebugState->IsFaultForbid() &&
+                !(m_pClrDebugState->ViolationMask() & (FaultViolation|FaultNotFatal|BadDebugState)))
+            {
+                CONTRACT_ASSERT("INJECT_FAULT called in a FAULTFORBID region.",
+                                BaseContract::FAULT_Forbid,
+                                BaseContract::FAULT_Mask,
+                                m_contractStackRecord.m_szFunction,
+                                m_contractStackRecord.m_szFile,
+                                m_contractStackRecord.m_lineNum);
+            }
+            break;
+
+        case FAULT_Disabled:
+            // Nothing
+            break;
+
+        default:
+            UNREACHABLE();
+    }
+
+    switch (testmask & THROWS_Mask)
+    {
+        case THROWS_Yes:
+            m_pClrDebugState->CheckOkayToThrow(m_contractStackRecord.m_szFunction,
+                                               m_contractStackRecord.m_szFile,
+                                               m_contractStackRecord.m_lineNum);
+            break;
+
+        case THROWS_No:
+            m_pClrDebugState->ViolationMaskReset( ThrowsViolation );
+            m_pClrDebugState->ResetOkToThrow();
+            break;
+
+        case THROWS_Disabled:
+            // Nothing
+            break;
+
+        default:
+            UNREACHABLE();
+    }
+
+    // LOADS_TYPE check
+    switch (testmask & LOADS_TYPE_Mask)
+    {
+        case LOADS_TYPE_Disabled:
+            // Nothing
+            break;
+
+        default:
+            {
+                UINT newTypeLoadLevel = ((testmask & LOADS_TYPE_Mask) >> LOADS_TYPE_Shift) - 1;
+                if (newTypeLoadLevel > m_pClrDebugState->GetMaxLoadTypeLevel())
+                {
+                    if (!((LoadsTypeViolation|BadDebugState) & m_pClrDebugState->ViolationMask()))
+                    {
+                        CONTRACT_ASSERT("A function tried to load a type past the current level limit.",
+                                        (m_pClrDebugState->GetMaxLoadTypeLevel() + 1) << LOADS_TYPE_Shift,
+                                        Contract::LOADS_TYPE_Mask,
+                                        m_contractStackRecord.m_szFunction,
+                                        m_contractStackRecord.m_szFile,
+                                        m_contractStackRecord.m_lineNum
+                                        );
+                    }
+                }
+                m_pClrDebugState->SetMaxLoadTypeLevel(newTypeLoadLevel);
+                m_pClrDebugState->ViolationMaskReset(LoadsTypeViolation);
+
+            }
+            break;
+    }
+
+    if (testmask & CAN_RETAKE_LOCK_No)
+    {
+        m_pClrDebugState->OnEnterCannotRetakeLockFunction();
+        m_pClrDebugState->ResetOkToRetakeLock();
+    }
+
+    switch (testmask & CAN_TAKE_LOCK_Mask)
+    {
+        case CAN_TAKE_LOCK_Yes:
+            m_pClrDebugState->CheckOkayToLock(m_contractStackRecord.m_szFunction,
+                                              m_contractStackRecord.m_szFile,
+                                              m_contractStackRecord.m_lineNum);
+            break;
+
+        case CAN_TAKE_LOCK_No:
+            m_pClrDebugState->ViolationMaskReset(TakesLockViolation);
+            m_pClrDebugState->ResetOkToLock();
+            break;
+
+        case CAN_TAKE_LOCK_Disabled:
+            // Nothing
+            break;
+
+        default:
+            UNREACHABLE();
+    }
+
+}
+
+FORCEINLINE BOOL BaseContract::CheckFaultInjection()
+{
+    // ??? use m_tag to see if we should trigger an injection
+    return FALSE;
+}
+
+inline BOOL ClrDebugState::CheckOkayToThrowNoAssert()
+{
+    if (!IsOkToThrow() && !(m_violationmask & (ThrowsViolation|BadDebugState)))
+    {
+        return FALSE;
+    }
+    return TRUE;
+}
+
+inline void ClrDebugState::CheckOkayToThrow(_In_z_ const char *szFunction, _In_z_ const char *szFile, int lineNum)
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    if (!CheckOkayToThrowNoAssert())
+    {
+        CONTRACT_ASSERT("THROWS called in a NOTHROW region.",
+                        BaseContract::THROWS_No,
+                        BaseContract::THROWS_Mask,
+                        szFunction,
+                        szFile,
+                        lineNum);
+    }
+}
+
+inline BOOL ClrDebugState::CheckOkayToLockNoAssert()
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    if (!IsOkToLock() && !(m_violationmask & (TakesLockViolation|BadDebugState)))
+    {
+        return FALSE;
+    }
+    return TRUE;
+}
+
+inline void ClrDebugState::CheckOkayToLock(_In_z_ const char *szFunction, _In_z_ const char *szFile, int lineNum)
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    if (!CheckOkayToLockNoAssert())
+    {
+
+        CONTRACT_ASSERT("CAN_TAKE_LOCK called in a CANNOT_TAKE_LOCK region.",
+                        BaseContract::CAN_TAKE_LOCK_No,
+                        BaseContract::CAN_TAKE_LOCK_Mask,
+                        szFunction,
+                        szFile,
+                        lineNum);
+
+    }
+}
+
+
+inline void ClrDebugState::LockTaken(DbgStateLockType dbgStateLockType,
+                                     UINT cTakes,
+                                     void * pvLock,
+                                     _In_z_ const char * szFunction,
+                                     _In_z_ const char * szFile,
+                                     int lineNum)
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    if ((m_violationmask & BadDebugState) != 0)
+    {
+        return;
+    }
+
+    // Assert if we're taking a lock in a CANNOT_TAKE_LOCK scope.  Even if this asserts, we'll
+    // continue to the following lines to track the lock
+    CheckOkayToLock(szFunction, szFile, lineNum);
+
+    _ASSERTE(GetDbgStateLockData() != NULL);
+
+    if (!IsOkToRetakeLock())
+    {
+        if (m_LockState.IsLockRetaken(pvLock))
+        {
+            CONTRACT_ASSERT("You cannot take a lock which is already being held in a CANNOT_RETAKE_LOCK scope.",
+                     BaseContract::CAN_RETAKE_LOCK_No,
+                     BaseContract::CAN_RETAKE_LOCK_No,
+                     szFunction,
+                     szFile,
+                     lineNum);
+        }
+    }
+
+    GetDbgStateLockData()->LockTaken(dbgStateLockType, cTakes, pvLock, szFunction, szFile, lineNum);
+}
+
+inline void ClrDebugState::LockReleased(DbgStateLockType dbgStateLockType, UINT cReleases, void * pvLock)
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    if ((m_violationmask & BadDebugState) != 0)
+    {
+        return;
+    }
+
+    _ASSERTE(GetDbgStateLockData() != NULL);
+
+    if (!IsOkToRetakeLock())
+    {
+        // It is very suspicious to release any locks being hold at the time this function was
+        // called in a CANNOT_RETAKE_LOCK scope
+        _ASSERTE(m_LockState.IsSafeToRelease(cReleases));
+    }
+
+    GetDbgStateLockData()->LockReleased(dbgStateLockType, cReleases, pvLock);
+}
+
+inline UINT ClrDebugState::GetLockCount(DbgStateLockType dbgStateLockType)
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    if ((m_violationmask & BadDebugState) != 0)
+    {
+        return 0;
+    }
+
+    _ASSERTE(GetDbgStateLockData() != NULL);
+    return GetDbgStateLockData()->GetLockCount(dbgStateLockType);
+}
+
+inline UINT ClrDebugState::GetCombinedLockCount()
+{
+    STATIC_CONTRACT_DEBUG_ONLY;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    if ((m_violationmask & BadDebugState) != 0)
+    {
+        return 0;
+    }
+
+    _ASSERTE(GetDbgStateLockData() != NULL);
+    return GetDbgStateLockData()->GetCombinedLockCount();
+}
+
+inline void DbgStateLockData::LockTaken(DbgStateLockType dbgStateLockType,
+                                        UINT cTakes,      // # times we're taking this lock (usually 1)
+                                        void * pvLock,
+                                        _In_z_ const char * szFunction,
+                                        _In_z_ const char * szFile,
+                                        int lineNum)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    // Technically the lock's already been taken before we're called, but it's
+    // handy to have this contract here at the leaf end of the call chain, as it
+    // ensures SCAN will enforce that no use of the LOCK_TAKEN macros occurs
+    // in a CANNOT_TAKE_LOCK scope (as LOCK_TAKEN macros just call this function).
+    STATIC_CONTRACT_CAN_TAKE_LOCK;
+
+    // Valid enum?
+    _ASSERTE(UINT(dbgStateLockType) < kDbgStateLockType_Count);
+
+    UINT cCombinedLocks = GetCombinedLockCount();
+
+    // Are we exceeding the threshold for what we can store in m_rgTakenLockInfos?
+    // If so, assert a warning, but we'll deal with it.
+    if ((cCombinedLocks <= ARRAY_SIZE(m_rgTakenLockInfos)) &&
+        (cCombinedLocks + cTakes > ARRAY_SIZE(m_rgTakenLockInfos)))
+    {
+        // Actually, for now we are NOT asserting until I can dedicate more time
+        // to this.  Some class loader code paths legally hold many simultaneous
+        // locks (>10).  Need to do further analysis on reasonable value to set
+        // for kMaxAllowedSimultaneousLocks.  Since lock order checking is turned
+        // off for the moment anyway, exceeding kMaxAllowedSimultaneousLocks
+        // has no consequences for now anyway.
+    }
+
+    m_rgcLocksTaken[dbgStateLockType] += cTakes;
+
+    // Remember as many of these new entrances in m_rgTakenLockInfos as we can
+    for (UINT i = cCombinedLocks;
+         i < min (ARRAY_SIZE(m_rgTakenLockInfos), cCombinedLocks + cTakes);
+         i++)
+    {
+        m_rgTakenLockInfos[i].m_pvLock = pvLock;
+        m_rgTakenLockInfos[i].m_szFile = szFile;
+        m_rgTakenLockInfos[i].m_lineNum = lineNum;
+    }
+}
+
+inline void DbgStateLockData::LockReleased(DbgStateLockType dbgStateLockType, UINT cReleases, void * pvLock)
+{
+    // Valid enum?
+    _ASSERTE(UINT(dbgStateLockType) < kDbgStateLockType_Count);
+
+    if (cReleases > m_rgcLocksTaken[dbgStateLockType])
+    {
+        _ASSERTE(!"Releasing lock(s) that were never taken");
+        cReleases = m_rgcLocksTaken[dbgStateLockType];
+    }
+
+    UINT cCombinedLocks = GetCombinedLockCount();
+
+    // If lock count is within range of our m_rgTakenLockInfos buffer size, then
+    // make sure we're releasing locks in reverse order of how we took them
+    for (UINT i = cCombinedLocks - cReleases;
+         i < min (ARRAY_SIZE(m_rgTakenLockInfos), cCombinedLocks);
+         i++)
+    {
+        if (m_rgTakenLockInfos[i].m_pvLock != pvLock)
+        {
+            // Ok, I lied.  We're not really checking that we're releasing locks in reverse
+            // order, because sometimes we legally release them out of order.  (The loader
+            // does this intentionally in a few places.) We should consider whether those
+            // places can be changed, or whether we can add some kind of macro to declare
+            // that we're releasing out of order, and that it's ok & intentional.  At that
+            // point, we can place a nice ASSERTE right here.  Until then, do nothing.
+        }
+
+        // We may be clearing out the wrong entry in m_rgTakenLockInfos here, if the locks
+        // were released out of order.  However, it will eventually correct itself once all
+        // the out-of-order locks have been released.  And our count
+        // (i.e., m_rgcLocksTaken[dbgStateLockType]) will always be accurate
+        memset(&(m_rgTakenLockInfos[i]),
+               0,
+               sizeof(m_rgTakenLockInfos[i]));
+    }
+
+    m_rgcLocksTaken[dbgStateLockType] -= cReleases;
+}
+
+inline void DbgStateLockData::SetStartingValues()
+{
+    memset(this, 0, sizeof(*this));
+}
+
+inline UINT DbgStateLockData::GetLockCount(DbgStateLockType dbgStateLockType)
+{
+    _ASSERTE(UINT(dbgStateLockType) < kDbgStateLockType_Count);
+    return m_rgcLocksTaken[dbgStateLockType];
+}
+
+inline UINT DbgStateLockData::GetCombinedLockCount()
+{
+    // If this fires, the set of lock types must have changed.  You'll need to
+    // fix the sum below to include all lock types
+    _ASSERTE(kDbgStateLockType_Count == 3);
+
+    return m_rgcLocksTaken[0] + m_rgcLocksTaken[1] + m_rgcLocksTaken[2];
+}
+
+inline void DbgStateLockState::SetStartingValues()
+{
+    m_cLocksEnteringCannotRetakeLock = 0;
+    m_pLockData = NULL;     // Will get filled in by CLRInitDebugState()
+}
+
+// We set a marker to record the number of locks that have been taken when
+// CANNOT_RETAKE_LOCK contract is constructed.
+inline void DbgStateLockState::OnEnterCannotRetakeLockFunction()
+{
+    m_cLocksEnteringCannotRetakeLock = m_pLockData->GetCombinedLockCount();
+}
+
+inline BOOL DbgStateLockState::IsLockRetaken(void * pvLock)
+{
+    // m_cLocksEnteringCannotRetakeLock must be in valid range
+    _ASSERTE(m_cLocksEnteringCannotRetakeLock <= m_pLockData->GetCombinedLockCount());
+
+    // m_cLocksEnteringCannotRetakeLock records the number of locks that were taken
+    // when CANNOT_RETAKE_LOCK contract was constructed.
+    for (UINT i = 0;
+        i < min(ARRAY_SIZE(m_pLockData->m_rgTakenLockInfos), m_cLocksEnteringCannotRetakeLock);
+        ++i)
+    {
+        if (m_pLockData->m_rgTakenLockInfos[i].m_pvLock == pvLock)
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+inline BOOL DbgStateLockState::IsSafeToRelease(UINT cReleases)
+{
+    return m_cLocksEnteringCannotRetakeLock <= (m_pLockData->GetCombinedLockCount() - cReleases);
+}
+
+inline void DbgStateLockState::SetDbgStateLockData(DbgStateLockData * pDbgStateLockData)
+{
+    m_pLockData = pDbgStateLockData;
+}
+
+inline DbgStateLockData * DbgStateLockState::GetDbgStateLockData()
+{
+    return m_pLockData;
+}
+
+inline
+void CONTRACT_ASSERT(const char *szElaboration,
+                     UINT  whichTest,
+                     UINT  whichTestMask,
+                     const char *szFunction,
+                     const char *szFile,
+                     int   lineNum)
+{
+    if (CheckClrDebugState() && ( CheckClrDebugState()->ViolationMask() & BadDebugState))
+    {
+        _ASSERTE(!"Someone tried to assert a contract violation although the contracts were disabled in this thread due to"
+                  " an OOM or a shim/mscorwks mismatch. You can probably safely ignore this assert - however, whoever"
+                  " called CONTRACT_ASSERT was supposed to checked if the current violationmask had the BadDebugState set."
+                  " Look up the stack, see who called CONTRACT_ASSERT and file a bug against the owner.");
+        return;
+    }
+
+    // prevent recursion - we use the same mechanism as CHECK, so this will
+    // also prevent mutual recursion involving ASSERT_CHECKs
+    CHECK _check;
+    if (_check.EnterAssert())
+    {
+        char Buf[512*20 + 2048 + 1024];
+
+        sprintf_s(Buf,ARRAY_SIZE(Buf), "CONTRACT VIOLATION by %s at \"%s\" @ %d\n\n%s\n", szFunction, szFile, lineNum, szElaboration);
+
+        int count = 20;
+        ContractStackRecord *pRec = CheckClrDebugState() ? CheckClrDebugState()->GetContractStackTrace() : NULL;
+        BOOL foundconflict = FALSE;
+        BOOL exceptionBuildingStack = FALSE;
+
+        PAL_TRY_NAKED
+        {
+            while (pRec != NULL)
+            {
+                char tmpbuf[512];
+                BOOL fshowconflict = FALSE;
+
+                if (!foundconflict)
+                {
+                    if (whichTest == (pRec->m_testmask & whichTestMask))
+                    {
+                        foundconflict = TRUE;
+                        fshowconflict = TRUE;
+                    }
+                }
+
+                if (count != 0 || fshowconflict)
+                {
+                    if (count != 0)
+                    {
+                        count--;
+                    }
+                    else
+                    {
+                        // Show that some lines have been skipped
+                        strcat_s(Buf, ARRAY_SIZE(Buf), "\n                        ...");
+
+                    }
+
+                    sprintf_s(tmpbuf,ARRAY_SIZE(tmpbuf),
+                            "\n%s  %s in %s at \"%s\" @ %d",
+                            fshowconflict ? "VIOLATED-->" : "                      ",
+                            pRec->m_construct,
+                            pRec->m_szFunction,
+                            pRec->m_szFile,
+                            pRec->m_lineNum
+                            );
+
+                    strcat_s(Buf, ARRAY_SIZE(Buf), tmpbuf);
+                }
+
+                pRec = pRec->m_pNext;
+            }
+        }
+        PAL_EXCEPT_NAKED(EXCEPTION_EXECUTE_HANDLER)
+        {
+            // We're done trying to walk the stack of contracts. We faulted trying to form the contract stack trace,
+            // and that usually means that its corrupted. A common cause of this is having CONTRACTs in functions that
+            // never return, but instead do a non-local goto.
+            count = 0;
+            exceptionBuildingStack = TRUE;
+        }
+        PAL_ENDTRY_NAKED;
+
+        if (count == 0)
+        {
+            strcat_s(Buf,ARRAY_SIZE(Buf), "\n                        ...");
+        }
+
+        if (exceptionBuildingStack)
+        {
+            strcat_s(Buf,ARRAY_SIZE(Buf),
+                   "\n"
+                   "\nError forming contract stack. Any contract stack displayed above is correct,"
+                   "\nbut it's most probably truncated. This is probably due to a CONTRACT in a"
+                   "\nfunction that does a non-local goto. There are two bugs here:"
+                   "\n"
+                   "\n    1) the CONTRACT violation, and"
+                   "\n    2) the CONTRACT in the function with the non-local goto."
+                   "\n"
+                   "\nPlease fix both bugs!"
+                   "\n"
+                   );
+        }
+
+        strcat_s(Buf,ARRAY_SIZE(Buf), "\n\n");
+
+        if (!foundconflict && count != 0)
+        {
+            if (whichTest == BaseContract::THROWS_No)
+            {
+                strcat_s(Buf,ARRAY_SIZE(Buf), "You can't throw here because there is no handler on the stack.\n");
+            }
+            else
+            {
+                strcat_s(Buf,ARRAY_SIZE(Buf), "We can't find the violated contract. Look for an old-style non-holder-based contract.\n");
+            }
+        }
+
+        DbgAssertDialog((char *)szFile, lineNum, Buf);
+        _check.LeaveAssert();
+    }
+}
+
+
+FORCEINLINE BOOL BaseContract::EnforceContract()
+{
+    if (s_alwaysEnforceContracts)
+        return TRUE;
+    else
+        return CHECK::EnforceAssert();
+}
+
+inline void BaseContract::SetUnconditionalContractEnforcement(BOOL value)
+{
+    s_alwaysEnforceContracts = value;
+}
+
+inline UINT GetDbgStateCombinedLockCount()
+{
+    return GetClrDebugState()->GetCombinedLockCount();
+}
+inline UINT GetDbgStateLockCount(DbgStateLockType dbgStateLockType)
+{
+    return GetClrDebugState()->GetLockCount(dbgStateLockType);
+}
+
+#define ASSERT_NO_USER_LOCKS_HELD()   \
+    _ASSERTE(GetDbgStateLockCount(kDbgStateLockType_User) == 0)
+#define ASSERT_NO_HOST_BREAKABLE_CRSTS_HELD()   \
+    _ASSERTE(GetDbgStateLockCount(kDbgStateLockType_HostBreakableCrst) == 0)
+#define ASSERT_NO_EE_LOCKS_HELD()   \
+    _ASSERTE(GetDbgStateLockCount(kDbgStateLockType_EE) == 0)
+
+#else  // ENABLE_CONTRACTS_IMPL
+
+#define ASSERT_NO_USER_LOCKS_HELD()
+#define ASSERT_NO_HOST_BREAKABLE_CRSTS_HELD()
+#define ASSERT_NO_EE_LOCKS_HELD()
+
+#endif  // ENABLE_CONTRACTS_IMPL
+
+#endif  // CONTRACT_INL_
diff --git a/src/inc/corhlprpriv.h b/src/inc/corhlprpriv.h
new file mode 100644 (file)
index 0000000..38faa6f
--- /dev/null
@@ -0,0 +1,789 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*****************************************************************************
+ **                                                                         **
+ ** Corhlprpriv.h -                                                                 **
+ **                                                                         **
+ *****************************************************************************/
+
+#ifndef __CORHLPRPRIV_H__
+#define __CORHLPRPRIV_H__
+
+#include "corhlpr.h"
+#include "fstring.h"
+
+#if defined(_MSC_VER) && defined(HOST_X86)
+#pragma optimize("y", on)              // If routines don't get inlined, don't pay the EBP frame penalty
+#endif
+
+//*****************************************************************************
+//
+//***** Utility helpers
+//
+//*****************************************************************************
+
+#ifndef SOS_INCLUDE
+
+//*****************************************************************************
+//
+// **** CQuickBytes
+// This helper class is useful for cases where 90% of the time you allocate 512
+// or less bytes for a data structure.  This class contains a 512 byte buffer.
+// Alloc() will return a pointer to this buffer if your allocation is small
+// enough, otherwise it asks the heap for a larger buffer which is freed for
+// you.  No mutex locking is required for the small allocation case, making the
+// code run faster, less heap fragmentation, etc...  Each instance will allocate
+// 520 bytes, so use accordinly.
+//
+//*****************************************************************************
+namespace NSQuickBytesHelper
+{
+    template <BOOL bThrow>
+    struct _AllocBytes;
+
+    template <>
+    struct _AllocBytes<TRUE>
+    {
+        static BYTE *Invoke(SIZE_T iItems)
+        {
+            return NEW_THROWS(iItems);
+        }
+    };
+
+    template <>
+    struct _AllocBytes<FALSE>
+    {
+        static BYTE *Invoke(SIZE_T iItems)
+        {
+            return NEW_NOTHROW(iItems);
+        }
+    };
+};
+
+void DECLSPEC_NORETURN ThrowHR(HRESULT hr);
+
+template <SIZE_T SIZE, SIZE_T INCREMENT>
+class CQuickMemoryBase
+{
+protected:
+    template <typename ELEM_T>
+    static ELEM_T Min(ELEM_T a, ELEM_T b)
+        { return a < b ? a : b; }
+
+    template <typename ELEM_T>
+    static ELEM_T Max(ELEM_T a, ELEM_T b)
+        { return a < b ? b : a; }
+
+    // bGrow  - indicates that this is a resize and that the original data
+    //          needs to be copied over.
+    // bThrow - indicates whether or not memory allocations will throw.
+    template <BOOL bGrow, BOOL bThrow>
+    void *_Alloc(SIZE_T iItems)
+    {
+#if defined(_BLD_CLR) && defined(_DEBUG)
+        {  // Exercise heap for OOM-fault injection purposes
+            BYTE * pb = NSQuickBytesHelper::_AllocBytes<bThrow>::Invoke(iItems);
+            _ASSERTE(!bThrow || pb != NULL); // _AllocBytes would have thrown if bThrow == TRUE
+            if (pb == NULL) return NULL; // bThrow == FALSE and we failed to allocate memory
+            delete [] pb; // Success, delete allocated memory.
+        }
+#endif
+        if (iItems <= cbTotal)
+        {   // Fits within existing memory allocation
+            iSize = iItems;
+        }
+        else if (iItems <= SIZE)
+        {   // Will fit in internal buffer.
+            if (pbBuff == NULL)
+            {   // Any previous allocation is in the internal buffer and the new
+                // allocation fits in the internal buffer, so just update the size.
+                iSize = iItems;
+                cbTotal = SIZE;
+            }
+            else
+            {   // There was a previous allocation, sitting in pbBuff
+                if (bGrow)
+                {   // If growing, need to copy any existing data over.
+                    memcpy(&rgData[0], pbBuff, Min(cbTotal, SIZE));
+                }
+
+                delete [] pbBuff;
+                pbBuff = NULL;
+                iSize = iItems;
+                cbTotal = SIZE;
+            }
+        }
+        else
+        {   // Need to allocate a new buffer
+            SIZE_T cbTotalNew = iItems + (bGrow ? INCREMENT : 0);
+            BYTE * pbBuffNew = NSQuickBytesHelper::_AllocBytes<bThrow>::Invoke(cbTotalNew);
+
+            if (!bThrow && pbBuffNew == NULL)
+            {   // Allocation failed. Zero out structure.
+                if (pbBuff != NULL)
+                {   // Delete old buffer
+                    delete [] pbBuff;
+                }
+                pbBuff = NULL;
+                iSize = 0;
+                cbTotal = 0;
+                return NULL;
+            }
+
+            if (bGrow && cbTotal > 0)
+            {   // If growing, need to copy any existing data over.
+                memcpy(pbBuffNew, (BYTE *)Ptr(), Min(cbTotal, cbTotalNew));
+            }
+
+            if (pbBuff != NULL)
+            {   // Delete old pre-existing buffer
+                delete [] pbBuff;
+                pbBuff = NULL;
+            }
+
+            pbBuff = pbBuffNew;
+            cbTotal = cbTotalNew;
+            iSize = iItems;
+        }
+
+        return Ptr();
+    }
+
+public:
+    void Init()
+    {
+        pbBuff = 0;
+        iSize = 0;
+        cbTotal = SIZE;
+    }
+
+    void Destroy()
+    {
+        if (pbBuff)
+        {
+            delete [] pbBuff;
+            pbBuff = 0;
+        }
+    }
+
+    void *AllocThrows(SIZE_T iItems)
+    {
+        return _Alloc<FALSE /*bGrow*/, TRUE /*bThrow*/>(iItems);
+    }
+
+    void *AllocNoThrow(SIZE_T iItems)
+    {
+        return _Alloc<FALSE /*bGrow*/, FALSE /*bThrow*/>(iItems);
+    }
+
+    void ReSizeThrows(SIZE_T iItems)
+    {
+        _Alloc<TRUE /*bGrow*/, TRUE /*bThrow*/>(iItems);
+    }
+
+#ifdef __GNUC__
+    // This makes sure that we will not get an undefined symbol
+    // when building a release version of libcoreclr using LLVM/GCC.
+    __attribute__((used))
+#endif // __GNUC__
+    HRESULT ReSizeNoThrow(SIZE_T iItems);
+
+    void Shrink(SIZE_T iItems)
+    {
+        _ASSERTE(iItems <= cbTotal);
+        iSize = iItems;
+    }
+
+    operator PVOID()
+    {
+        return ((pbBuff) ? pbBuff : (PVOID)&rgData[0]);
+    }
+
+    void *Ptr()
+    {
+        return ((pbBuff) ? pbBuff : (PVOID)&rgData[0]);
+    }
+
+    const void *Ptr() const
+    {
+        return ((pbBuff) ? pbBuff : (PVOID)&rgData[0]);
+    }
+
+    SIZE_T Size() const
+    {
+        return (iSize);
+    }
+
+    SIZE_T MaxSize() const
+    {
+        return (cbTotal);
+    }
+
+    void Maximize()
+    {
+        iSize = cbTotal;
+    }
+
+
+    // Convert UTF8 string to UNICODE string, optimized for speed
+    HRESULT ConvertUtf8_UnicodeNoThrow(const char * utf8str)
+    {
+        bool allAscii;
+        DWORD length;
+
+        HRESULT hr = FString::Utf8_Unicode_Length(utf8str, & allAscii, & length);
+
+        if (SUCCEEDED(hr))
+        {
+            LPWSTR buffer = (LPWSTR) AllocNoThrow((length + 1) * sizeof(WCHAR));
+
+            if (buffer == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+            }
+            else
+            {
+                hr = FString::Utf8_Unicode(utf8str, allAscii, buffer, length);
+            }
+        }
+
+        return hr;
+    }
+
+    // Convert UTF8 string to UNICODE string, optimized for speed
+    void ConvertUtf8_Unicode(const char * utf8str)
+    {
+        bool allAscii;
+        DWORD length;
+
+        HRESULT hr = FString::Utf8_Unicode_Length(utf8str, & allAscii, & length);
+
+        if (SUCCEEDED(hr))
+        {
+            LPWSTR buffer = (LPWSTR) AllocThrows((length + 1) * sizeof(WCHAR));
+
+            hr = FString::Utf8_Unicode(utf8str, allAscii, buffer, length);
+        }
+
+        if (FAILED(hr))
+        {
+            ThrowHR(hr);
+        }
+    }
+
+    // Convert UNICODE string to UTF8 string, optimized for speed
+    void ConvertUnicode_Utf8(const WCHAR * pString)
+    {
+        bool allAscii;
+        DWORD length;
+
+        HRESULT hr = FString::Unicode_Utf8_Length(pString, & allAscii, & length);
+
+        if (SUCCEEDED(hr))
+        {
+            LPSTR buffer = (LPSTR) AllocThrows((length + 1) * sizeof(char));
+
+            hr = FString::Unicode_Utf8(pString, allAscii, buffer, length);
+        }
+
+        if (FAILED(hr))
+        {
+            ThrowHR(hr);
+        }
+    }
+
+    // Copy single byte string and hold it
+    const char * SetStringNoThrow(const char * pStr, SIZE_T len)
+    {
+        LPSTR buffer = (LPSTR) AllocNoThrow(len + 1);
+
+        if (buffer != NULL)
+        {
+            memcpy(buffer, pStr, len);
+            buffer[len] = 0;
+        }
+
+        return buffer;
+    }
+
+#ifdef DACCESS_COMPILE
+    void
+    EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+    {
+        // Assume that 'this' is enumerated, either explicitly
+        // or because this class is embedded in another.
+        DacEnumMemoryRegion(dac_cast<TADDR>(pbBuff), iSize);
+    }
+#endif // DACCESS_COMPILE
+
+    BYTE       *pbBuff;
+    SIZE_T      iSize;              // number of bytes used
+    SIZE_T      cbTotal;            // total bytes allocated in the buffer
+    // use UINT64 to enforce the alignment of the memory
+    UINT64 rgData[(SIZE+sizeof(UINT64)-1)/sizeof(UINT64)];
+};
+
+// These should be multiples of 8 so that data can be naturally aligned.
+#define     CQUICKBYTES_BASE_SIZE           512
+#define     CQUICKBYTES_INCREMENTAL_SIZE    128
+
+class CQuickBytesBase : public CQuickMemoryBase<CQUICKBYTES_BASE_SIZE, CQUICKBYTES_INCREMENTAL_SIZE>
+{
+};
+
+
+class CQuickBytes : public CQuickBytesBase
+{
+public:
+    CQuickBytes()
+    {
+        Init();
+    }
+
+    ~CQuickBytes()
+    {
+        Destroy();
+    }
+};
+
+/* to be used as static variable - no constructor/destructor, assumes zero
+   initialized memory */
+class CQuickBytesStatic : public CQuickBytesBase
+{
+};
+
+template <SIZE_T CQUICKBYTES_BASE_SPECIFY_SIZE>
+class CQuickBytesSpecifySizeBase : public CQuickMemoryBase<CQUICKBYTES_BASE_SPECIFY_SIZE, CQUICKBYTES_INCREMENTAL_SIZE>
+{
+};
+
+template <SIZE_T CQUICKBYTES_BASE_SPECIFY_SIZE>
+class CQuickBytesSpecifySize : public CQuickBytesSpecifySizeBase<CQUICKBYTES_BASE_SPECIFY_SIZE>
+{
+public:
+    CQuickBytesSpecifySize()
+    {
+        this->Init();
+    }
+
+    ~CQuickBytesSpecifySize()
+    {
+        this->Destroy();
+    }
+};
+
+/* to be used as static variable - no constructor/destructor, assumes zero
+   initialized memory */
+template <SIZE_T CQUICKBYTES_BASE_SPECIFY_SIZE>
+class CQuickBytesSpecifySizeStatic : public CQuickBytesSpecifySizeBase<CQUICKBYTES_BASE_SPECIFY_SIZE>
+{
+};
+
+template <class T> class CQuickArrayBase : public CQuickBytesBase
+{
+public:
+    T* AllocThrows(SIZE_T iItems)
+    {
+        CheckOverflowThrows(iItems);
+        return (T*)CQuickBytesBase::AllocThrows(iItems * sizeof(T));
+    }
+
+    void ReSizeThrows(SIZE_T iItems)
+    {
+        CheckOverflowThrows(iItems);
+        CQuickBytesBase::ReSizeThrows(iItems * sizeof(T));
+    }
+
+    T* AllocNoThrow(SIZE_T iItems)
+    {
+        if (!CheckOverflowNoThrow(iItems))
+        {
+            return NULL;
+        }
+        return (T*)CQuickBytesBase::AllocNoThrow(iItems * sizeof(T));
+    }
+
+    HRESULT ReSizeNoThrow(SIZE_T iItems)
+    {
+        if (!CheckOverflowNoThrow(iItems))
+        {
+            return E_OUTOFMEMORY;
+        }
+        return CQuickBytesBase::ReSizeNoThrow(iItems * sizeof(T));
+    }
+
+    void Shrink(SIZE_T iItems)
+    {
+        CQuickBytesBase::Shrink(iItems * sizeof(T));
+    }
+
+    T* Ptr()
+    {
+        return (T*) CQuickBytesBase::Ptr();
+    }
+
+    const T* Ptr() const
+    {
+        return (T*) CQuickBytesBase::Ptr();
+    }
+
+    SIZE_T Size() const
+    {
+        return CQuickBytesBase::Size() / sizeof(T);
+    }
+
+    SIZE_T MaxSize() const
+    {
+        return CQuickBytesBase::cbTotal / sizeof(T);
+    }
+
+    T& operator[] (SIZE_T ix)
+    {
+        _ASSERTE(ix < Size());
+        return *(Ptr() + ix);
+    }
+
+    const T& operator[] (SIZE_T ix) const
+    {
+        _ASSERTE(ix < Size());
+        return *(Ptr() + ix);
+    }
+
+private:
+    inline
+    BOOL CheckOverflowNoThrow(SIZE_T iItems)
+    {
+        SIZE_T totalSize = iItems * sizeof(T);
+
+        if (totalSize / sizeof(T) != iItems)
+        {
+            return FALSE;
+        }
+
+        return TRUE;
+    }
+
+    inline
+    void CheckOverflowThrows(SIZE_T iItems)
+    {
+        if (!CheckOverflowNoThrow(iItems))
+        {
+            THROW_OUT_OF_MEMORY();
+        }
+    }
+};
+
+template <class T> class CQuickArray : public CQuickArrayBase<T>
+{
+public:
+    CQuickArray<T>()
+    {
+        this->Init();
+    }
+
+    ~CQuickArray<T>()
+    {
+        this->Destroy();
+    }
+};
+
+// This is actually more of a stack with array access. Essentially, you can
+// only add elements through Push and remove them through Pop, but you can
+// access and modify any random element with the index operator. You cannot
+// access elements that have not been added.
+
+template <class T>
+class CQuickArrayList : protected CQuickArray<T>
+{
+private:
+    SIZE_T m_curSize;
+
+public:
+    // Make these specific functions public.
+    using CQuickArray<T>::AllocThrows;
+    using CQuickArray<T>::ReSizeThrows;
+    using CQuickArray<T>::AllocNoThrow;
+    using CQuickArray<T>::ReSizeNoThrow;
+    using CQuickArray<T>::MaxSize;
+    using CQuickArray<T>::Ptr;
+
+    CQuickArrayList()
+        : m_curSize(0)
+    {
+        this->Init();
+    }
+
+    ~CQuickArrayList()
+    {
+        this->Destroy();
+    }
+
+    // Can only access values that have been pushed.
+    T& operator[] (SIZE_T ix)
+    {
+        _ASSERTE(ix < m_curSize);
+        return CQuickArray<T>::operator[](ix);
+    }
+
+    // Can only access values that have been pushed.
+    const T& operator[] (SIZE_T ix) const
+    {
+        _ASSERTE(ix < m_curSize);
+        return CQuickArray<T>::operator[](ix);
+    }
+
+    // THROWS: Resizes if necessary.
+    void Push(const T & value)
+    {
+        // Resize if necessary - thows.
+        if (m_curSize + 1 >= CQuickArray<T>::Size())
+            ReSizeThrows((m_curSize + 1) * 2);
+
+        // Append element to end of array.
+        _ASSERTE(m_curSize + 1 < CQuickArray<T>::Size());
+        SIZE_T ix = m_curSize++;
+        (*this)[ix] = value;
+    }
+
+    // NOTHROW: Resizes if necessary.
+    BOOL PushNoThrow(const T & value)
+    {
+        // Resize if necessary - nothow.
+        if (m_curSize + 1 >= CQuickArray<T>::Size()) {
+            if (ReSizeNoThrow((m_curSize + 1) * 2) != NOERROR)
+                return FALSE;
+        }
+
+        // Append element to end of array.
+        _ASSERTE(m_curSize + 1 < CQuickArray<T>::Size());
+        SIZE_T ix = m_curSize++;
+        (*this)[ix] = value;
+        return TRUE;
+    }
+
+    T Pop()
+    {
+        _ASSERTE(m_curSize > 0);
+        T retval = (*this)[m_curSize - 1];
+        INDEBUG(ZeroMemory(&(this->Ptr()[m_curSize - 1]), sizeof(T));)
+        --m_curSize;
+        return retval;
+    }
+
+    SIZE_T Size() const
+    {
+        return m_curSize;
+    }
+
+    void Shrink()
+    {
+        CQuickArray<T>::Shrink(m_curSize);
+    }
+};
+
+
+/* to be used as static variable - no constructor/destructor, assumes zero
+   initialized memory */
+template <class T> class CQuickArrayStatic : public CQuickArrayBase<T>
+{
+};
+
+typedef CQuickArrayBase<WCHAR> CQuickWSTRBase;
+typedef CQuickArray<WCHAR> CQuickWSTR;
+typedef CQuickArrayStatic<WCHAR> CQuickWSTRStatic;
+
+typedef CQuickArrayBase<CHAR> CQuickSTRBase;
+typedef CQuickArray<CHAR> CQuickSTR;
+typedef CQuickArrayStatic<CHAR> CQuickSTRStatic;
+
+class RidBitmap
+{
+public:
+    HRESULT InsertToken(mdToken token)
+    {
+        HRESULT  hr     = S_OK;
+        mdToken  rid    = RidFromToken(token);
+        SIZE_T   index  = rid / 8;
+        BYTE     bit    = (1 << (rid % 8));
+
+        if (index >= buffer.Size())
+        {
+            SIZE_T oldSize = buffer.Size();
+            SIZE_T newSize = index+1+oldSize/8;
+            IfFailRet(buffer.ReSizeNoThrow(newSize));
+            memset(&buffer[oldSize], 0, newSize-oldSize);
+        }
+
+        buffer[index] |= bit;
+        return hr;
+    }
+
+    bool IsTokenInBitmap(mdToken token)
+    {
+        mdToken rid   = RidFromToken(token);
+        SIZE_T  index = rid / 8;
+        BYTE    bit   = (1 << (rid % 8));
+
+        return ((index < buffer.Size()) && (buffer[index] & bit));
+    }
+
+    void Reset()
+    {
+        if (buffer.Size())
+        {
+            memset(&buffer[0], 0, buffer.Size());
+        }
+    }
+
+private:
+    CQuickArray<BYTE> buffer;
+};
+
+//*****************************************************************************
+//
+//***** Signature helpers
+//
+//*****************************************************************************
+
+HRESULT _CountBytesOfOneArg(
+    PCCOR_SIGNATURE pbSig,
+    ULONG       *pcbTotal);
+
+HRESULT _GetFixedSigOfVarArg(           // S_OK or error.
+    PCCOR_SIGNATURE pvSigBlob,          // [IN] point to a blob of CLR signature
+    ULONG   cbSigBlob,                  // [IN] size of signature
+    CQuickBytes *pqbSig,                // [OUT] output buffer for fixed part of VarArg Signature
+    ULONG   *pcbSigBlob);               // [OUT] number of bytes written to the above output buffer
+
+#endif //!SOS_INCLUDE
+
+#if defined(_MSC_VER) && defined(TARGET_X86)
+#pragma optimize("", on)               // restore command line default optimizations
+#endif
+
+
+//---------------------------------------------------------------------------------------
+//
+// Reads compressed integer from buffer pData, fills the result to *pnDataOut. Advances buffer pointer.
+// Doesn't read behind the end of the buffer (the end starts at pDataEnd).
+//
+inline
+__checkReturn
+HRESULT
+CorSigUncompressData_EndPtr(
+    PCCOR_SIGNATURE & pData,        // [IN,OUT] Buffer
+    PCCOR_SIGNATURE   pDataEnd,     // End of buffer
+    DWORD *           pnDataOut)    // [OUT] Compressed integer read from the buffer
+{
+    _ASSERTE(pData <= pDataEnd);
+    HRESULT hr = S_OK;
+
+    INT_PTR cbDataSize = pDataEnd - pData;
+    if (cbDataSize > 4)
+    {   // Compressed integer cannot be bigger than 4 bytes
+        cbDataSize = 4;
+    }
+    DWORD dwDataSize = (DWORD)cbDataSize;
+
+    ULONG cbDataOutLength;
+    IfFailRet(CorSigUncompressData(
+        pData,
+        dwDataSize,
+        pnDataOut,
+        &cbDataOutLength));
+    pData += cbDataOutLength;
+
+    return hr;
+} // CorSigUncompressData_EndPtr
+
+//---------------------------------------------------------------------------------------
+//
+// Reads CorElementType (1 byte) from buffer pData, fills the result to *pTypeOut. Advances buffer pointer.
+// Doesn't read behind the end of the buffer (the end starts at pDataEnd).
+//
+inline
+__checkReturn
+HRESULT
+CorSigUncompressElementType_EndPtr(
+    PCCOR_SIGNATURE & pData,    // [IN,OUT] Buffer
+    PCCOR_SIGNATURE   pDataEnd, // End of buffer
+    CorElementType *  pTypeOut) // [OUT] ELEMENT_TYPE_* value read from the buffer
+{
+    _ASSERTE(pData <= pDataEnd);
+    // We don't expect pData > pDataEnd, but the runtime check doesn't cost much and it is more secure in
+    // case caller has a bug
+    if (pData >= pDataEnd)
+    {   // No data
+        return META_E_BAD_SIGNATURE;
+    }
+    // Read 'type' as 1 byte
+    *pTypeOut = (CorElementType)*pData;
+    pData++;
+
+    return S_OK;
+} // CorSigUncompressElementType_EndPtr
+
+//---------------------------------------------------------------------------------------
+//
+// Reads pointer (4/8 bytes) from buffer pData, fills the result to *ppvPointerOut. Advances buffer pointer.
+// Doesn't read behind the end of the buffer (the end starts at pDataEnd).
+//
+inline
+__checkReturn
+HRESULT
+CorSigUncompressPointer_EndPtr(
+    PCCOR_SIGNATURE & pData,            // [IN,OUT] Buffer
+    PCCOR_SIGNATURE   pDataEnd,         // End of buffer
+    void **           ppvPointerOut)    // [OUT] Pointer value read from the buffer
+{
+    _ASSERTE(pData <= pDataEnd);
+    // We could just skip this check as pointers should be only in trusted (and therefore correct)
+    // signatures and we check for that on the caller side, but it won't hurt to have this check and it will
+    // make it easier to catch invalid signatures in trusted code (e.g. IL stubs, NGEN images, etc.)
+    if (pData + sizeof(void *) > pDataEnd)
+    {   // Not enough data in the buffer
+        _ASSERTE(!"This signature is invalid. Note that caller should check that it is not comming from untrusted source!");
+        return META_E_BAD_SIGNATURE;
+    }
+    *ppvPointerOut = *(void * UNALIGNED *)pData;
+    pData += sizeof(void *);
+
+    return S_OK;
+} // CorSigUncompressPointer_EndPtr
+
+//---------------------------------------------------------------------------------------
+//
+// Reads compressed TypeDef/TypeRef/TypeSpec token, fills the result to *pnDataOut. Advances buffer pointer.
+// Doesn't read behind the end of the buffer (the end starts at pDataEnd).
+//
+inline
+__checkReturn
+HRESULT
+CorSigUncompressToken_EndPtr(
+    PCCOR_SIGNATURE & pData,        // [IN,OUT] Buffer
+    PCCOR_SIGNATURE   pDataEnd,     // End of buffer
+    mdToken *         ptkTokenOut)  // [OUT] Token read from the buffer
+{
+    _ASSERTE(pData <= pDataEnd);
+    HRESULT hr = S_OK;
+
+    INT_PTR cbDataSize = pDataEnd - pData;
+    if (cbDataSize > 4)
+    {   // Compressed token cannot be bigger than 4 bytes
+        cbDataSize = 4;
+    }
+    DWORD dwDataSize = (DWORD)cbDataSize;
+
+    uint32_t cbTokenOutLength;
+    IfFailRet(CorSigUncompressToken(
+        pData,
+        dwDataSize,
+        ptkTokenOut,
+        &cbTokenOutLength));
+    pData += cbTokenOutLength;
+
+    return hr;
+} // CorSigUncompressToken_EndPtr
+
+#endif // __CORHLPRPRIV_H__
diff --git a/src/inc/crsttypes.h b/src/inc/crsttypes.h
new file mode 100644 (file)
index 0000000..d462cbd
--- /dev/null
@@ -0,0 +1,410 @@
+//
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+#ifndef __CRST_TYPES_INCLUDED
+#define __CRST_TYPES_INCLUDED
+
+// **** THIS IS AN AUTOMATICALLY GENERATED HEADER FILE -- DO NOT EDIT!!! ****
+
+// This file describes the range of Crst types available and their mapping to a numeric level (used by the
+// runtime in debug mode to validate we're deadlock free). To modify these settings edit the
+// file:CrstTypes.def file and run the clr\artifacts\CrstTypeTool utility to generate a new version of this file.
+
+// Each Crst type is declared as a value in the following CrstType enum.
+enum CrstType
+{
+    CrstAppDomainCache = 0,
+    CrstAppDomainHandleTable = 1,
+    CrstArgBasedStubCache = 2,
+    CrstAssemblyList = 3,
+    CrstAssemblyLoader = 4,
+    CrstAvailableClass = 5,
+    CrstAvailableParamTypes = 6,
+    CrstBaseDomain = 7,
+    CrstCCompRC = 8,
+    CrstClassFactInfoHash = 9,
+    CrstClassInit = 10,
+    CrstClrNotification = 11,
+    CrstCodeFragmentHeap = 12,
+    CrstCodeVersioning = 13,
+    CrstCOMCallWrapper = 14,
+    CrstCOMWrapperCache = 15,
+    CrstDataTest1 = 16,
+    CrstDataTest2 = 17,
+    CrstDbgTransport = 18,
+    CrstDeadlockDetection = 19,
+    CrstDebuggerController = 20,
+    CrstDebuggerFavorLock = 21,
+    CrstDebuggerHeapExecMemLock = 22,
+    CrstDebuggerHeapLock = 23,
+    CrstDebuggerJitInfo = 24,
+    CrstDebuggerMutex = 25,
+    CrstDelegateToFPtrHash = 26,
+    CrstDomainLocalBlock = 27,
+    CrstDynamicIL = 28,
+    CrstDynamicMT = 29,
+    CrstEtwTypeLogHash = 30,
+    CrstEventPipe = 31,
+    CrstEventStore = 32,
+    CrstException = 33,
+    CrstExecutableAllocatorLock = 34,
+    CrstExecuteManRangeLock = 35,
+    CrstExternalObjectContextCache = 36,
+    CrstFCall = 37,
+    CrstFuncPtrStubs = 38,
+    CrstFusionAppCtx = 39,
+    CrstGCCover = 40,
+    CrstGlobalStrLiteralMap = 41,
+    CrstHandleTable = 42,
+    CrstIbcProfile = 43,
+    CrstIJWFixupData = 44,
+    CrstIJWHash = 45,
+    CrstILStubGen = 46,
+    CrstInlineTrackingMap = 47,
+    CrstInstMethodHashTable = 48,
+    CrstInterop = 49,
+    CrstInteropData = 50,
+    CrstIsJMCMethod = 51,
+    CrstISymUnmanagedReader = 52,
+    CrstJit = 53,
+    CrstJitGenericHandleCache = 54,
+    CrstJitInlineTrackingMap = 55,
+    CrstJitPatchpoint = 56,
+    CrstJitPerf = 57,
+    CrstJumpStubCache = 58,
+    CrstLeafLock = 59,
+    CrstListLock = 60,
+    CrstLoaderAllocator = 61,
+    CrstLoaderAllocatorReferences = 62,
+    CrstLoaderHeap = 63,
+    CrstManagedObjectWrapperMap = 64,
+    CrstMethodDescBackpatchInfoTracker = 65,
+    CrstModule = 66,
+    CrstModuleFixup = 67,
+    CrstModuleLookupTable = 68,
+    CrstMulticoreJitHash = 69,
+    CrstMulticoreJitManager = 70,
+    CrstNativeImageEagerFixups = 71,
+    CrstNativeImageLoad = 72,
+    CrstNls = 73,
+    CrstNotifyGdb = 74,
+    CrstObjectList = 75,
+    CrstPEImage = 76,
+    CrstPendingTypeLoadEntry = 77,
+    CrstPgoData = 78,
+    CrstPinnedByrefValidation = 79,
+    CrstProfilerGCRefDataFreeList = 80,
+    CrstProfilingAPIStatus = 81,
+    CrstRCWCache = 82,
+    CrstRCWCleanupList = 83,
+    CrstReadyToRunEntryPointToMethodDescMap = 84,
+    CrstReflection = 85,
+    CrstReJITGlobalRequest = 86,
+    CrstRetThunkCache = 87,
+    CrstSavedExceptionInfo = 88,
+    CrstSaveModuleProfileData = 89,
+    CrstSecurityStackwalkCache = 90,
+    CrstSigConvert = 91,
+    CrstSingleUseLock = 92,
+    CrstSpecialStatics = 93,
+    CrstStackSampler = 94,
+    CrstStressLog = 95,
+    CrstStubCache = 96,
+    CrstStubDispatchCache = 97,
+    CrstStubUnwindInfoHeapSegments = 98,
+    CrstSyncBlockCache = 99,
+    CrstSyncHashLock = 100,
+    CrstSystemBaseDomain = 101,
+    CrstSystemDomain = 102,
+    CrstSystemDomainDelayedUnloadList = 103,
+    CrstThreadIdDispenser = 104,
+    CrstThreadpoolTimerQueue = 105,
+    CrstThreadpoolWaitThreads = 106,
+    CrstThreadpoolWorker = 107,
+    CrstThreadStore = 108,
+    CrstTieredCompilation = 109,
+    CrstTypeEquivalenceMap = 110,
+    CrstTypeIDMap = 111,
+    CrstUMEntryThunkCache = 112,
+    CrstUMEntryThunkFreeListLock = 113,
+    CrstUniqueStack = 114,
+    CrstUnresolvedClassLock = 115,
+    CrstUnwindInfoTableLock = 116,
+    CrstVSDIndirectionCellLock = 117,
+    CrstWrapperTemplate = 118,
+    kNumberOfCrstTypes = 119
+};
+
+#endif // __CRST_TYPES_INCLUDED
+
+// Define some debug data in one module only -- vm\crst.cpp.
+#if defined(__IN_CRST_CPP) && defined(_DEBUG)
+
+// An array mapping CrstType to level.
+int g_rgCrstLevelMap[] =
+{
+    10,         // CrstAppDomainCache
+    14,         // CrstAppDomainHandleTable
+    3,          // CrstArgBasedStubCache
+    0,          // CrstAssemblyList
+    12,         // CrstAssemblyLoader
+    4,          // CrstAvailableClass
+    5,          // CrstAvailableParamTypes
+    7,          // CrstBaseDomain
+    -1,         // CrstCCompRC
+    13,         // CrstClassFactInfoHash
+    11,         // CrstClassInit
+    -1,         // CrstClrNotification
+    6,          // CrstCodeFragmentHeap
+    9,          // CrstCodeVersioning
+    0,          // CrstCOMCallWrapper
+    5,          // CrstCOMWrapperCache
+    3,          // CrstDataTest1
+    0,          // CrstDataTest2
+    0,          // CrstDbgTransport
+    0,          // CrstDeadlockDetection
+    -1,         // CrstDebuggerController
+    3,          // CrstDebuggerFavorLock
+    0,          // CrstDebuggerHeapExecMemLock
+    0,          // CrstDebuggerHeapLock
+    4,          // CrstDebuggerJitInfo
+    10,         // CrstDebuggerMutex
+    0,          // CrstDelegateToFPtrHash
+    16,         // CrstDomainLocalBlock
+    0,          // CrstDynamicIL
+    3,          // CrstDynamicMT
+    0,          // CrstEtwTypeLogHash
+    18,         // CrstEventPipe
+    0,          // CrstEventStore
+    0,          // CrstException
+    0,          // CrstExecutableAllocatorLock
+    0,          // CrstExecuteManRangeLock
+    0,          // CrstExternalObjectContextCache
+    4,          // CrstFCall
+    7,          // CrstFuncPtrStubs
+    10,         // CrstFusionAppCtx
+    10,         // CrstGCCover
+    13,         // CrstGlobalStrLiteralMap
+    1,          // CrstHandleTable
+    0,          // CrstIbcProfile
+    8,          // CrstIJWFixupData
+    0,          // CrstIJWHash
+    7,          // CrstILStubGen
+    3,          // CrstInlineTrackingMap
+    17,         // CrstInstMethodHashTable
+    20,         // CrstInterop
+    5,          // CrstInteropData
+    0,          // CrstIsJMCMethod
+    7,          // CrstISymUnmanagedReader
+    11,         // CrstJit
+    0,          // CrstJitGenericHandleCache
+    16,         // CrstJitInlineTrackingMap
+    4,          // CrstJitPatchpoint
+    -1,         // CrstJitPerf
+    6,          // CrstJumpStubCache
+    0,          // CrstLeafLock
+    -1,         // CrstListLock
+    15,         // CrstLoaderAllocator
+    16,         // CrstLoaderAllocatorReferences
+    3,          // CrstLoaderHeap
+    3,          // CrstManagedObjectWrapperMap
+    14,         // CrstMethodDescBackpatchInfoTracker
+    5,          // CrstModule
+    15,         // CrstModuleFixup
+    4,          // CrstModuleLookupTable
+    0,          // CrstMulticoreJitHash
+    13,         // CrstMulticoreJitManager
+    0,          // CrstNativeImageEagerFixups
+    0,          // CrstNativeImageLoad
+    0,          // CrstNls
+    0,          // CrstNotifyGdb
+    2,          // CrstObjectList
+    5,          // CrstPEImage
+    19,         // CrstPendingTypeLoadEntry
+    4,          // CrstPgoData
+    0,          // CrstPinnedByrefValidation
+    0,          // CrstProfilerGCRefDataFreeList
+    13,         // CrstProfilingAPIStatus
+    4,          // CrstRCWCache
+    0,          // CrstRCWCleanupList
+    10,         // CrstReadyToRunEntryPointToMethodDescMap
+    8,          // CrstReflection
+    17,         // CrstReJITGlobalRequest
+    4,          // CrstRetThunkCache
+    3,          // CrstSavedExceptionInfo
+    0,          // CrstSaveModuleProfileData
+    0,          // CrstSecurityStackwalkCache
+    4,          // CrstSigConvert
+    5,          // CrstSingleUseLock
+    0,          // CrstSpecialStatics
+    0,          // CrstStackSampler
+    -1,         // CrstStressLog
+    5,          // CrstStubCache
+    0,          // CrstStubDispatchCache
+    4,          // CrstStubUnwindInfoHeapSegments
+    3,          // CrstSyncBlockCache
+    0,          // CrstSyncHashLock
+    5,          // CrstSystemBaseDomain
+    13,         // CrstSystemDomain
+    0,          // CrstSystemDomainDelayedUnloadList
+    0,          // CrstThreadIdDispenser
+    7,          // CrstThreadpoolTimerQueue
+    7,          // CrstThreadpoolWaitThreads
+    13,         // CrstThreadpoolWorker
+    12,         // CrstThreadStore
+    8,          // CrstTieredCompilation
+    4,          // CrstTypeEquivalenceMap
+    10,         // CrstTypeIDMap
+    4,          // CrstUMEntryThunkCache
+    3,          // CrstUMEntryThunkFreeListLock
+    4,          // CrstUniqueStack
+    7,          // CrstUnresolvedClassLock
+    3,          // CrstUnwindInfoTableLock
+    4,          // CrstVSDIndirectionCellLock
+    3,          // CrstWrapperTemplate
+};
+
+// An array mapping CrstType to a stringized name.
+LPCSTR g_rgCrstNameMap[] =
+{
+    "CrstAppDomainCache",
+    "CrstAppDomainHandleTable",
+    "CrstArgBasedStubCache",
+    "CrstAssemblyList",
+    "CrstAssemblyLoader",
+    "CrstAvailableClass",
+    "CrstAvailableParamTypes",
+    "CrstBaseDomain",
+    "CrstCCompRC",
+    "CrstClassFactInfoHash",
+    "CrstClassInit",
+    "CrstClrNotification",
+    "CrstCodeFragmentHeap",
+    "CrstCodeVersioning",
+    "CrstCOMCallWrapper",
+    "CrstCOMWrapperCache",
+    "CrstDataTest1",
+    "CrstDataTest2",
+    "CrstDbgTransport",
+    "CrstDeadlockDetection",
+    "CrstDebuggerController",
+    "CrstDebuggerFavorLock",
+    "CrstDebuggerHeapExecMemLock",
+    "CrstDebuggerHeapLock",
+    "CrstDebuggerJitInfo",
+    "CrstDebuggerMutex",
+    "CrstDelegateToFPtrHash",
+    "CrstDomainLocalBlock",
+    "CrstDynamicIL",
+    "CrstDynamicMT",
+    "CrstEtwTypeLogHash",
+    "CrstEventPipe",
+    "CrstEventStore",
+    "CrstException",
+    "CrstExecutableAllocatorLock",
+    "CrstExecuteManRangeLock",
+    "CrstExternalObjectContextCache",
+    "CrstFCall",
+    "CrstFuncPtrStubs",
+    "CrstFusionAppCtx",
+    "CrstGCCover",
+    "CrstGlobalStrLiteralMap",
+    "CrstHandleTable",
+    "CrstIbcProfile",
+    "CrstIJWFixupData",
+    "CrstIJWHash",
+    "CrstILStubGen",
+    "CrstInlineTrackingMap",
+    "CrstInstMethodHashTable",
+    "CrstInterop",
+    "CrstInteropData",
+    "CrstIsJMCMethod",
+    "CrstISymUnmanagedReader",
+    "CrstJit",
+    "CrstJitGenericHandleCache",
+    "CrstJitInlineTrackingMap",
+    "CrstJitPatchpoint",
+    "CrstJitPerf",
+    "CrstJumpStubCache",
+    "CrstLeafLock",
+    "CrstListLock",
+    "CrstLoaderAllocator",
+    "CrstLoaderAllocatorReferences",
+    "CrstLoaderHeap",
+    "CrstManagedObjectWrapperMap",
+    "CrstMethodDescBackpatchInfoTracker",
+    "CrstModule",
+    "CrstModuleFixup",
+    "CrstModuleLookupTable",
+    "CrstMulticoreJitHash",
+    "CrstMulticoreJitManager",
+    "CrstNativeImageEagerFixups",
+    "CrstNativeImageLoad",
+    "CrstNls",
+    "CrstNotifyGdb",
+    "CrstObjectList",
+    "CrstPEImage",
+    "CrstPendingTypeLoadEntry",
+    "CrstPgoData",
+    "CrstPinnedByrefValidation",
+    "CrstProfilerGCRefDataFreeList",
+    "CrstProfilingAPIStatus",
+    "CrstRCWCache",
+    "CrstRCWCleanupList",
+    "CrstReadyToRunEntryPointToMethodDescMap",
+    "CrstReflection",
+    "CrstReJITGlobalRequest",
+    "CrstRetThunkCache",
+    "CrstSavedExceptionInfo",
+    "CrstSaveModuleProfileData",
+    "CrstSecurityStackwalkCache",
+    "CrstSigConvert",
+    "CrstSingleUseLock",
+    "CrstSpecialStatics",
+    "CrstStackSampler",
+    "CrstStressLog",
+    "CrstStubCache",
+    "CrstStubDispatchCache",
+    "CrstStubUnwindInfoHeapSegments",
+    "CrstSyncBlockCache",
+    "CrstSyncHashLock",
+    "CrstSystemBaseDomain",
+    "CrstSystemDomain",
+    "CrstSystemDomainDelayedUnloadList",
+    "CrstThreadIdDispenser",
+    "CrstThreadpoolTimerQueue",
+    "CrstThreadpoolWaitThreads",
+    "CrstThreadpoolWorker",
+    "CrstThreadStore",
+    "CrstTieredCompilation",
+    "CrstTypeEquivalenceMap",
+    "CrstTypeIDMap",
+    "CrstUMEntryThunkCache",
+    "CrstUMEntryThunkFreeListLock",
+    "CrstUniqueStack",
+    "CrstUnresolvedClassLock",
+    "CrstUnwindInfoTableLock",
+    "CrstVSDIndirectionCellLock",
+    "CrstWrapperTemplate",
+};
+
+// Define a special level constant for unordered locks.
+#define CRSTUNORDERED (-1)
+
+// Define inline helpers to map Crst types to names and levels.
+inline static int GetCrstLevel(CrstType crstType)
+{
+    LIMITED_METHOD_CONTRACT;
+    _ASSERTE(crstType >= 0 && crstType < kNumberOfCrstTypes);
+    return g_rgCrstLevelMap[crstType];
+}
+inline static LPCSTR GetCrstName(CrstType crstType)
+{
+    LIMITED_METHOD_CONTRACT;
+    _ASSERTE(crstType >= 0 && crstType < kNumberOfCrstTypes);
+    return g_rgCrstNameMap[crstType];
+}
+
+#endif // defined(__IN_CRST_CPP) && defined(_DEBUG)
diff --git a/src/inc/crtwrap.h b/src/inc/crtwrap.h
new file mode 100644 (file)
index 0000000..3a54ccf
--- /dev/null
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// CrtWrap.h
+//
+// Wrapper code for the C runtime library.
+//
+//*****************************************************************************
+
+#ifndef __CrtWrap_h__
+#define __CrtWrap_h__
+
+#include <stdint.h>
+#include <windows.h>
+#include <objbase.h>
+#include <tchar.h>
+#include "debugmacros.h"
+#include <stdlib.h>
+#include <malloc.h>
+#include <wchar.h>
+#include <stdio.h>
+
+#ifdef HOST_WINDOWS
+// CoreCLR.dll uses linker .def files to control the exported symbols.
+// Define DLLEXPORT macro as empty on Windows.
+#define DLLEXPORT
+#endif
+
+#endif // __CrtWrap_h__
index 4ba48f7e03e1893762f2a721826075339f8ae119..5c41b9e06fb75f5176c02970cc57542416654e60 100644 (file)
@@ -15,6 +15,9 @@
 
 #ifdef PAL_STDCPP_COMPAT
 #include <type_traits>
+#else
+#include "clr_std/type_traits"
+#include "crosscomp.h"
 #endif
 
 //
@@ -35,6 +38,13 @@ typedef ULONG_PTR TADDR;
 // target pointer.  For cross-plat, this may be different than SIZE_T
 // which reflects the host pointer size.
 typedef SIZE_T TSIZE_T;
+#define VPTR_CLASS_METHODS(name)
+// Used for base classes that can be instantiated directly.
+// The fake vfn is still used to force a vtable even when
+// all the normal vfns are ifdef'ed out.
+#define VPTR_BASE_CONCRETE_VTABLE_CLASS(name)                   \
+public: name(TADDR addr, TADDR vtAddr) {}                       \
+        VPTR_CLASS_METHODS(name)
 
 //
 // This version of the macros turns into normal pointers
@@ -67,6 +77,17 @@ typedef const void* PTR_CVOID;
 #define S8PTRMAX(type, maxChars) type*
 #define S16PTR(type) type*
 #define S16PTRMAX(type, maxChars) type*
+#define _SPTR_DECL(acc_type, store_type, var) \
+    static store_type var
+#define _SPTR_IMPL(acc_type, store_type, cls, var) \
+    store_type cls::var
+
+#define GVAL_DECL(type, var) \
+    extern type var
+#define GVAL_IMPL(type, var) \
+    type var
+#define GVAL_IMPL_INIT(type, var, init) \
+    type var = init
 
 //----------------------------------------------------------------------------
 // dac_cast
@@ -131,6 +152,8 @@ inline Tgt dac_cast(Src src)
     // Perhaps we should more precisely restrict it's usage, but we get the precise
     // restrictions in DAC builds, so it wouldn't buy us much.
     return (Tgt)(src);
+#define SPTR_DECL(type, var) _SPTR_DECL(type*, PTR_##type, var)
+#define SPTR_IMPL(type, cls, var) _SPTR_IMPL(type*, PTR_##type, cls, var)
 }
 
 //----------------------------------------------------------------------------
@@ -192,6 +215,7 @@ typedef DPTR(IMAGE_NT_HEADERS)      PTR_IMAGE_NT_HEADERS;
 typedef DPTR(IMAGE_NT_HEADERS32)    PTR_IMAGE_NT_HEADERS32;
 typedef DPTR(IMAGE_NT_HEADERS64)    PTR_IMAGE_NT_HEADERS64;
 typedef DPTR(IMAGE_SECTION_HEADER)  PTR_IMAGE_SECTION_HEADER;
+typedef DPTR(IMAGE_EXPORT_DIRECTORY)  PTR_IMAGE_EXPORT_DIRECTORY;
 typedef DPTR(IMAGE_TLS_DIRECTORY)   PTR_IMAGE_TLS_DIRECTORY;
 
 //----------------------------------------------------------------------------
@@ -204,4 +228,22 @@ typedef TADDR PCODE;
 typedef DPTR(PCODE) PTR_PCODE;
 typedef DPTR(PTR_PCODE) PTR_PTR_PCODE;
 
+// TARGET_CONSISTENCY_CHECK represents a condition that should not fail unless the DAC target is corrupt.
+// This is in contrast to ASSERTs in DAC infrastructure code which shouldn't fail regardless of the memory
+// read from the target.  At the moment we treat these the same, but in the future we will want a mechanism
+// for disabling just the target consistency checks (eg. for tests that intentionally use corrupted targets).
+// @dbgtodo : Separating asserts and target consistency checks is tracked by DevDiv Bugs 31674
+#define TARGET_CONSISTENCY_CHECK(expr,msg) _ASSERTE_MSG(expr,msg)
+
+// For cross compilation, controlling type layout is important
+// We add a simple macro here which defines DAC_ALIGNAS to the C++11 alignas operator
+// This helps force the alignment of the next member
+// For most cross compilation cases the layout of types simply works
+// There are a few cases (where this macro is helpful) which are not consistent across platforms:
+// - Base class whose size is padded to its align size.  On Linux the gcc/clang
+//   layouts will reuse this padding in the derived class for the first member
+// - Class with an vtable pointer and an alignment greater than the pointer size.
+//   The Windows compilers will align the first member to the alignment size of the
+//   class.  Linux will align the first member to its natural alignment
+#define DAC_ALIGNAS(a) alignas(a)
 #endif // #ifndef __daccess_h__
diff --git a/src/inc/dbgenginemetrics.h b/src/inc/dbgenginemetrics.h
new file mode 100644 (file)
index 0000000..ebb7fc1
--- /dev/null
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// DbgEngineMetrics.h
+//
+// This file contains the defintion of CLR_ENGINE_METRICS.  This struct is used for Silverlight debugging.
+//
+// ======================================================================================
+
+
+
+#ifndef __DbgEngineMetrics_h__
+#define __DbgEngineMetrics_h__
+
+//---------------------------------------------------------------------------------------
+//
+// This struct contains information necessary for Silverlight debugging.  coreclr.dll has a static struct
+// of this type.  It is read by dbgshim.dll to help synchronize the debugger and coreclr.dll in launch
+// and early attach scenarios.
+//
+
+typedef struct tagCLR_ENGINE_METRICS
+{
+    DWORD   cbSize;                 // the size of the struct; also identifies the format of the struct
+    DWORD   dwDbiVersion;           // the version of the debugging interface expected by this CoreCLR
+    LPVOID  phContinueStartupEvent; // pointer to the continue startup event handle
+} CLR_ENGINE_METRICS;
+
+#endif // __DbgEngineMetrics_h__
index e6124828d769bcf1cba5abdd34e26031888e54c2..99cfd60b1c2603110ee011e23518f1c60cc54080 100644 (file)
@@ -10,7 +10,6 @@
 #ifndef __DebugMacros_h__
 #define __DebugMacros_h__
 
-#include "stacktrace.h"
 #include "debugmacrosext.h"
 #include "palclr.h"
 
@@ -31,9 +30,6 @@ bool _DbgBreakCheck(LPCSTR szFile, int iLine, LPCSTR szExpr, BOOL fConstrained =
 
 extern VOID ANALYZER_NORETURN DbgAssertDialog(const char *szFile, int iLine, const char *szExpr);
 
-#define TRACE_BUFF_SIZE (cchMaxAssertStackLevelStringLen * cfrMaxAssertStackLevels + cchMaxAssertExprLen + 1)
-extern char g_szExprWithStack[TRACE_BUFF_SIZE];
-
 extern int _DbgBreakCount;
 
 #define PRE_ASSERTE         /* if you need to change modes before doing asserts override */
@@ -199,31 +195,4 @@ do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); goto LA
 #undef _ASSERT
 #define _ASSERT _ASSERTE
 
-
-#if defined(_DEBUG) && defined(HOST_WINDOWS)
-
-// This function returns the EXE time stamp (effectively a random number)
-// Under retail it always returns 0.  This is meant to be used in the
-// RandomOnExe macro
-unsigned DbgGetEXETimeStamp();
-
-// returns true 'fractionOn' amount of the time using the EXE timestamp
-// as the random number seed.  For example DbgRandomOnExe(.1) returns true 1/10
-// of the time.  We use the line number so that different uses of DbgRandomOnExe
-// will not be coorelated with each other (9973 is prime).  Returns false on a retail build
-#define DbgRandomOnHashAndExe(hash, fractionOn) \
-    (((DbgGetEXETimeStamp() * __LINE__ * ((hash) ? (hash) : 1)) % 9973) < \
-     unsigned((fractionOn) * 9973))
-#define DbgRandomOnExe(fractionOn) DbgRandomOnHashAndExe(0, fractionOn)
-#define DbgRandomOnStringAndExe(string, fractionOn) DbgRandomOnHashAndExe(HashStringA(string), fractionOn)
-
-#else
-
-#define DbgGetEXETimeStamp() 0
-#define DbgRandomOnHashAndExe(hash, fractionOn)  0
-#define DbgRandomOnExe(fractionOn)  0
-#define DbgRandomOnStringAndExe(fractionOn)  0
-
-#endif // _DEBUG && !FEATUREPAL
-
 #endif
diff --git a/src/inc/debugreturn.h b/src/inc/debugreturn.h
new file mode 100644 (file)
index 0000000..d052364
--- /dev/null
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#ifndef _DEBUGRETURN_H_
+#define _DEBUGRETURN_H_
+
+// Note that with OACR Prefast is run over checked (_DEBUG is defined) sources
+// so we have to first check the _PREFAST_ define followed by the _DEBUG define
+//
+#ifdef _PREFAST_
+
+// Use prefast to detect gotos out of no-return blocks. The gotos out of no-return blocks
+// should be reported as memory leaks by prefast.  The (nothrow) is because PREfix sees the
+// throw from the new statement, and doesn't like these macros used in a destructor (and
+// the NULL returned by failure works just fine in delete[])
+
+#define DEBUG_ASSURE_NO_RETURN_BEGIN(arg)    { char* __noReturnInThisBlock_##arg = ::new (nothrow) char[1];
+#define DEBUG_ASSURE_NO_RETURN_END(arg)      ::delete[] __noReturnInThisBlock_##arg; }
+
+#define DEBUG_OK_TO_RETURN_BEGIN(arg)        { ::delete[] __noReturnInThisBlock_##arg;
+#define DEBUG_OK_TO_RETURN_END(arg)          __noReturnInThisBlock_##arg = ::new (nothrow) char[1]; }
+
+#define DEBUG_ASSURE_SAFE_TO_RETURN TRUE
+#define return return
+
+#else // !_PREFAST_
+
+// This is disabled in build 190024315 (a pre-release build after VS 2015 Update 3) and
+// earlier because those builds only support C++11 constexpr,  which doesn't allow the
+// use of 'if' statements within the body of a constexpr function.  Later builds support
+// C++14 constexpr.
+#if defined(_DEBUG) && !defined(JIT_BUILD) && (!defined(_MSC_FULL_VER) || _MSC_FULL_VER > 190024315)
+
+// Code to generate a compile-time error if return statements appear where they
+// shouldn't.
+//
+// Here's the way it works...
+//
+// We create two classes with a safe_to_return() method.  The method is static,
+// returns void, and does nothing.  One class has the method as public, the other
+// as private.  We introduce a global scope typedef for __ReturnOK that refers to
+// the class with the public method.  So, by default, the expression
+//
+//      __ReturnOK::safe_to_return()
+//
+// quietly compiles and does nothing.  When we enter a block in which we want to
+// inhibit returns, we introduce a new typedef that defines __ReturnOK as the
+// class with the private method.  Inside this scope,
+//
+//      __ReturnOK::safe_to_return()
+//
+// generates a compile-time error.
+//
+// To cause the method to be called, we have to #define the return keyword.
+// The simplest working version would be
+//
+//   #define return if (0) __ReturnOK::safe_to_return(); else return
+//
+// but we've used
+//
+//   #define return for (;1;__ReturnOK::safe_to_return()) return
+//
+// because it happens to generate somewhat faster code in a checked build.  (They
+// both introduce no overhead in a fastchecked build.)
+//
+class __SafeToReturn {
+public:
+    static int safe_to_return() {return 0;};
+    static int used() {return 0;};
+};
+
+class __YouCannotUseAReturnStatementHere {
+private:
+    // If you got here, and you're wondering what you did wrong -- you're using
+    // a return statement where it's not allowed.  Likely, it's inside one of:
+    //     GCPROTECT_BEGIN ... GCPROTECT_END
+    //     HELPER_METHOD_FRAME_BEGIN ... HELPER_METHOD_FRAME_END
+    //
+    static int safe_to_return() {return 0;};
+public:
+    // 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;
+
+// Use this to ensure that it is safe to return from a given scope
+#define DEBUG_ASSURE_SAFE_TO_RETURN     __ReturnOK::safe_to_return()
+
+// Unfortunately, the only way to make this work is to #define all return statements --
+// even the ones at global scope.  This actually generates better code that appears.
+// The call is dead, and does not appear in the generated code, even in a checked
+// build.  (And, in fastchecked, there is no penalty at all.)
+//
+#ifdef _MSC_VER
+#define return if (0 && __ReturnOK::safe_to_return()) { } else return
+#else // _MSC_VER
+#define return for (;1;__ReturnOK::safe_to_return()) return
+#endif // _MSC_VER
+
+#define DEBUG_ASSURE_NO_RETURN_BEGIN(arg) { typedef __YouCannotUseAReturnStatementHere __ReturnOK; if (0 && __ReturnOK::used()) { } else {
+#define DEBUG_ASSURE_NO_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 // defined(_DEBUG) && !defined(JIT_BUILD) && (!defined(_MSC_FULL_VER) || _MSC_FULL_VER > 190024315)
+
+#define DEBUG_ASSURE_SAFE_TO_RETURN TRUE
+
+#define DEBUG_ASSURE_NO_RETURN_BEGIN(arg) {
+#define DEBUG_ASSURE_NO_RETURN_END(arg) }
+
+#define DEBUG_OK_TO_RETURN_BEGIN(arg) {
+#define DEBUG_OK_TO_RETURN_END(arg) }
+
+#endif // defined(_DEBUG) && !defined(JIT_BUILD) && (!defined(_MSC_FULL_VER) || _MSC_FULL_VER > 190024315)
+
+#endif // !_PREFAST_
+
+#endif  // _DEBUGRETURN_H_
diff --git a/src/inc/entrypoints.h b/src/inc/entrypoints.h
new file mode 100644 (file)
index 0000000..dcd6cb5
--- /dev/null
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//-----------------------------------------------------------------------------
+// Entrypoint markers
+// Used to identify all external entrypoints into the CLR (via COM, exports, etc)
+// and perform various tasks on all of them
+//-----------------------------------------------------------------------------
+
+
+#ifndef __ENTRYPOINTS_h__
+#define __ENTRYPOINTS_h__
+
+#define BEGIN_ENTRYPOINT_THROWS
+#define END_ENTRYPOINT_THROWS
+#define BEGIN_ENTRYPOINT_THROWS_WITH_THREAD(____thread)
+#define END_ENTRYPOINT_THROWS_WITH_THREAD
+#define BEGIN_ENTRYPOINT_NOTHROW_WITH_THREAD(___thread)
+#define END_ENTRYPOINT_NOTHROW_WITH_THREAD
+#define BEGIN_ENTRYPOINT_NOTHROW
+#define END_ENTRYPOINT_NOTHROW
+#define BEGIN_ENTRYPOINT_VOIDRET
+#define END_ENTRYPOINT_VOIDRET
+#define BEGIN_CLEANUP_ENTRYPOINT
+#define END_CLEANUP_ENTRYPOINT
+
+#endif  // __ENTRYPOINTS_h__
+
+
diff --git a/src/inc/ex.h b/src/inc/ex.h
new file mode 100644 (file)
index 0000000..7fbc927
--- /dev/null
@@ -0,0 +1,1332 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#if !defined(_EX_H_)
+#define _EX_H_
+
+#define EX_TRY_HOLDER
+
+#include "sstring.h"
+#include "crtwrap.h"
+#include "winwrap.h"
+#include "corerror.h"
+#include "stresslog.h"
+#include "staticcontract.h"
+#include "entrypoints.h"
+
+#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
+#define _DEBUG_IMPL 1
+#endif
+
+
+//===========================================================================================
+// These abstractions hide the difference between legacy desktop CLR's (that don't support
+// side-by-side-inproc and rely on a fixed SEH code to identify managed exceptions) and
+// new CLR's that support side-by-side inproc.
+//
+// The new CLR's use a different set of SEH codes to avoid conflicting with the legacy CLR's.
+// In addition, to distinguish between EH's raised by different inproc instances of the CLR,
+// the module handle of the owning CLR is stored in ExceptionRecord.ExceptionInformation[4].
+//
+// (Note: all existing SEH's use either only slot [0] or no slots at all. We are leaving
+//  slots [1] thru [3] open for future expansion.)
+//===========================================================================================
+
+// Is this exception code one of the special CLR-specific SEH codes that participate in the
+// instance-tagging scheme?
+BOOL IsInstanceTaggedSEHCode(DWORD dwExceptionCode);
+
+
+// This set of overloads generates the NumberParameters and ExceptionInformation[] array to
+// pass to RaiseException().
+//
+// Parameters:
+//    exceptionArgs:   a fixed-size array of size INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE.
+//                     This will get filled in by this function. (The module handle goes
+//                     in the last slot if this is a side-by-side-inproc enabled build.)
+//
+//    exceptionArg1... up to four arguments that go in slots [0]..[3]. These depends
+//                     the specific requirements of your exception code.
+//
+// Returns:
+//    The NumberParameters to pass to RaiseException().
+//
+//    Basically, this is  either INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE or the count of your
+//    fixed arguments depending on whether this tagged-SEH-enabled build.
+//
+// This function is not permitted to fail.
+
+#define INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE 5
+DWORD MarkAsThrownByUs(/*out*/ ULONG_PTR exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE]);
+DWORD MarkAsThrownByUs(/*out*/ ULONG_PTR exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE], ULONG_PTR arg0);
+// (the existing system can support more overloads up to 4 fixed arguments but we don't need them at this time.)
+
+
+// Given an exception record, checks if it's exception code matches a specific exception code
+// *and* whether it was tagged by the calling instance of the CLR.
+//
+// If this is a non-tagged-SEH-enabled build, it is blindly assumed to be tagged by the
+// calling instance of the CLR.
+BOOL WasThrownByUs(const EXCEPTION_RECORD *pcER, DWORD dwExceptionCode);
+
+
+//-----------------------------------------------------------------------------------
+// The following group wraps the basic abstracts specifically for EXCEPTION_COMPLUS.
+//-----------------------------------------------------------------------------------
+BOOL IsComPlusException(const EXCEPTION_RECORD *pcER);
+
+
+//===========================================================================================
+//===========================================================================================
+
+
+//-------------------------------------------------------------------------------------------
+// This routine will generate the most descriptive possible error message for an hresult.
+// It will generate at minimum the hex value. It will also try to generate the symbolic name
+// (E_POINTER) and the friendly description (from the message tables.)
+//
+// bNoGeekStuff suppresses hex HR codes. Use this sparingly as most error strings generated by the
+// CLR are aimed at developers, not end-users.
+//-------------------------------------------------------------------------------------------
+void GetHRMsg(HRESULT hresult, SString &result, BOOL bNoGeekStuff = FALSE);
+
+
+//-------------------------------------------------------------------------------------------
+// Similar to GetHRMsg but phrased for top-level exception message.
+//-------------------------------------------------------------------------------------------
+void GenerateTopLevelHRExceptionMessage(HRESULT hresult, SString &result);
+
+
+// ---------------------------------------------------------------------------
+//   We save current ExceptionPointers using VectoredExceptionHandler.  The save data is only valid
+//   duing exception handling.  GetCurrentExceptionPointers returns the saved data.
+// ---------------------------------------------------------------------------
+void GetCurrentExceptionPointers(PEXCEPTION_POINTERS pExceptionInfo DEBUG_ARG(bool checkExceptionRecordLocation));
+
+// ---------------------------------------------------------------------------
+//   We save current ExceptionPointers using VectoredExceptionHandler.  The save data is only valid
+//   duing exception handling.  GetCurrentExceptionCode returns the current exception code.
+// ---------------------------------------------------------------------------
+DWORD GetCurrentExceptionCode();
+
+// ---------------------------------------------------------------------------
+//   Standard exception hierarchy & infrastructure for library code & EE
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// Exception class.  Abstract root exception of our hierarchy.
+// ---------------------------------------------------------------------------
+
+class Exception;
+class SEHException;
+
+
+// Exception hierarchy:
+/*                                               GetInstanceType
+Exception
+    |
+    |-> HRException                                     Y
+    |        |
+    |        |-> HRMsgException
+    |        |-> COMException
+    |
+    |-> SEHException                                    Y
+    |
+    |-> DelegatingException                             Y
+    |
+    |-> OutOfMemoryException                            Y
+    |
+    |-> CLRException                                    Y
+              |
+              |-> EEException                           Y
+              |        |
+              |        |-> EEMessageException
+              |        |
+              |        |-> EEResourceException
+              |        |
+              |        |-> EECOMException
+              |        |
+              |        |-> EEFieldException
+              |        |
+              |        |-> EEMethodException
+              |        |
+              |        |-> EEArgumentException
+              |        |
+              |        |-> EETypeLoadException
+              |        |
+              |        |-> EEFileLoadException
+              |
+              |-> ObjrefException                          Y
+              |
+              |-> CLRLastThrownObjectException             Y
+*/
+
+class Exception
+{
+    friend bool DebugIsEECxxExceptionPointer(void* pv);
+
+ private:
+    static const int c_type = 0x524f4f54;   // 'ROOT'
+    static Exception * g_OOMException;
+    static Exception * g_SOException;
+
+ protected:
+    Exception           *m_innerException;
+
+ public:
+    Exception() {LIMITED_METHOD_DAC_CONTRACT; m_innerException = NULL;}
+    virtual ~Exception() {LIMITED_METHOD_DAC_CONTRACT; if (m_innerException != NULL) Exception::Delete(m_innerException); }
+    virtual BOOL IsDomainBound() {return m_innerException!=NULL && m_innerException->IsDomainBound();} ;
+    virtual HRESULT GetHR() = 0;
+    virtual void GetMessage(SString &s);
+    virtual IErrorInfo *GetErrorInfo() { LIMITED_METHOD_CONTRACT; return NULL; }
+    virtual HRESULT SetErrorInfo() { LIMITED_METHOD_CONTRACT; return S_OK; }
+    void SetInnerException(Exception * pInnerException) { LIMITED_METHOD_CONTRACT; m_innerException = pInnerException; }
+
+    // Dynamic type query for catchers
+    static int GetType() { LIMITED_METHOD_CONTRACT; return c_type; }
+    // !!! If GetInstanceType is implemented, IsSameInstanceType should be implemented
+    virtual int GetInstanceType() = 0;
+    virtual BOOL IsType(int type) {LIMITED_METHOD_CONTRACT;  return type == c_type; }
+
+    // This is used in CLRException::GetThrowable to detect if we are in a recursive situation.
+    virtual BOOL IsSameInstanceType(Exception *pException) = 0;
+
+    // Will create a new instance of the Exception.  Note that this will
+    // be free of app domain or thread affinity.  Not every type of exception
+    // can be cloned with full fidelity.
+    virtual Exception *Clone();
+
+    // DomainBoundClone is a specialized form of cloning which is guaranteed
+    // to provide full fidelity.  However, the result is bound to the current
+    // app domain and should not be leaked.
+    Exception *DomainBoundClone();
+
+    class HandlerState
+    {
+        enum CaughtFlags
+        {
+            Caught = 1,
+            CaughtSO = 2,
+            CaughtCxx = 4,
+        };
+
+        DWORD               m_dwFlags;
+    public:
+        Exception*          m_pExceptionPtr;
+
+        HandlerState();
+
+        void CleanupTry();
+        void SetupCatch(INDEBUG_COMMA(_In_z_ const char * szFile) int lineNum);
+        void SucceedCatch();
+
+        BOOL DidCatch() { return (m_dwFlags & Caught); }
+        void SetCaught() { m_dwFlags |= Caught; }
+
+        BOOL DidCatchCxx() { return (m_dwFlags & CaughtCxx); }
+        void SetCaughtCxx() { m_dwFlags |= CaughtCxx; }
+    };
+
+    // Is this exception type considered "uncatchable"?
+    BOOL IsTerminal();
+
+    // Is this exception type considered "transient" (would a retry possibly succeed)?
+    BOOL IsTransient();
+    static BOOL IsTransient(HRESULT hr);
+
+    // Get an HRESULT's source representation, if known
+    static LPCSTR GetHRSymbolicName(HRESULT hr);
+
+    static Exception* GetOOMException();
+
+    // Preallocated exceptions:  If there is a preallocated instance of some
+    //  subclass of Exception, override this function and return a correct
+    //  value.  The default implementation returns constant FALSE
+    virtual BOOL IsPreallocatedException();
+    BOOL IsPreallocatedOOMException();
+
+    static void Delete(Exception* pvMemory);
+
+protected:
+
+    // This virtual method must be implemented by any non abstract Exception
+    // derived class. It must allocate a NEW exception of the identical type and
+    // copy all the relevant fields from the current exception to the new one.
+    // It is NOT responsible however for copying the inner exception. This
+    // will be handled by the base Exception class.
+    virtual Exception *CloneHelper();
+
+    // This virtual method must be implemented by Exception subclasses whose
+    // DomainBoundClone behavior is different than their normal clone behavior.
+    // It must allocate a NEW exception of the identical type and
+    // copy all the relevant fields from the current exception to the new one.
+    // It is NOT responsible however for copying the inner exception. This
+    // will be handled by the base Exception class.
+    virtual Exception *DomainBoundCloneHelper() { return CloneHelper(); }
+};
+
+#if 1
+
+inline void Exception__Delete(Exception* pvMemory)
+{
+  Exception::Delete(pvMemory);
+}
+
+using ExceptionHolder = SpecializedWrapper<Exception, Exception__Delete>;
+#else
+
+//------------------------------------------------------------------------------
+// class ExceptionHolder
+//
+// This is a very lightweight holder class for use inside the EX_TRY family
+//  of macros.  It is based on the standard Holder classes, but has been
+//  highly specialized for this one function, so that extra code can be
+//  removed, and the resulting code can be simple enough for all of the
+//  non-exceptional-case code to be inlined.
+class ExceptionHolder
+{
+private:
+    Exception *m_value;
+    BOOL      m_acquired;
+
+public:
+    FORCEINLINE ExceptionHolder(Exception *pException = NULL, BOOL take = TRUE)
+      : m_value(pException)
+    {
+        m_acquired = pException && take;
+    }
+
+    FORCEINLINE ~ExceptionHolder()
+    {
+        if (m_acquired)
+        {
+            Exception::Delete(m_value);
+        }
+    }
+
+    Exception* operator->() { return m_value; }
+
+    void operator=(Exception *p)
+    {
+        Release();
+        m_value = p;
+        Acquire();
+    }
+
+    BOOL IsNull() { return m_value == NULL; }
+
+    operator Exception*() { return m_value; }
+
+    Exception* GetValue() { return m_value; }
+
+    void SuppressRelease() { m_acquired = FALSE; }
+
+private:
+    void Acquire()
+    {
+        _ASSERTE(!m_acquired);
+
+        if (!IsNull())
+        {
+            m_acquired = TRUE;
+        }
+    }
+    void Release()
+    {
+        if (m_acquired)
+        {
+            _ASSERTE(!IsNull());
+            Exception::Delete(m_value);
+            m_acquired = FALSE;
+        }
+    }
+
+};
+
+#endif
+
+// ---------------------------------------------------------------------------
+// HRException class.  Implements exception API for exceptions generated from HRESULTs
+// ---------------------------------------------------------------------------
+
+class HRException : public Exception
+{
+    friend bool DebugIsEECxxExceptionPointer(void* pv);
+
+ protected:
+    HRESULT             m_hr;
+
+ public:
+    HRException();
+    HRException(HRESULT hr);
+
+    static const int c_type = 0x48522020;   // 'HR  '
+
+    // Dynamic type query for catchers
+    static int GetType() {LIMITED_METHOD_DAC_CONTRACT;  return c_type; }
+    virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; }
+    virtual BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type);  }
+    // Virtual overrides
+    HRESULT GetHR();
+
+    BOOL IsSameInstanceType(Exception *pException)
+    {
+        WRAPPER_NO_CONTRACT;
+        return pException->GetInstanceType() == GetType() && pException->GetHR() == m_hr;
+    }
+
+ protected:
+    virtual Exception *CloneHelper()
+    {
+        WRAPPER_NO_CONTRACT;
+        return new HRException(m_hr);
+    }
+};
+
+// ---------------------------------------------------------------------------
+// HRMessageException class.  Implements exception API for exceptions
+// generated from HRESULTs, and includes in info message.
+// ---------------------------------------------------------------------------
+
+class HRMsgException : public HRException
+{
+    friend bool DebugIsEECxxExceptionPointer(void* pv);
+
+ protected:
+    SString             m_msg;
+
+ public:
+    HRMsgException();
+    HRMsgException(HRESULT hr, SString const &msg);
+
+    // Virtual overrides
+    void GetMessage(SString &s);
+
+ protected:
+    virtual Exception *CloneHelper()
+    {
+        WRAPPER_NO_CONTRACT;
+        return new HRMsgException(m_hr, m_msg);
+    }
+};
+
+// ---------------------------------------------------------------------------
+// COMException class.  Implements exception API for standard COM-based error info
+// ---------------------------------------------------------------------------
+
+class COMException : public HRException
+{
+    friend bool DebugIsEECxxExceptionPointer(void* pv);
+
+ private:
+    IErrorInfo          *m_pErrorInfo;
+
+ public:
+    COMException();
+    COMException(HRESULT hr) ;
+    COMException(HRESULT hr, IErrorInfo *pErrorInfo);
+    ~COMException();
+
+    // Virtual overrides
+    IErrorInfo *GetErrorInfo();
+    void GetMessage(SString &result);
+
+ protected:
+    virtual Exception *CloneHelper()
+    {
+        WRAPPER_NO_CONTRACT;
+        return new COMException(m_hr, m_pErrorInfo);
+    }
+};
+
+// ---------------------------------------------------------------------------
+// SEHException class.  Implements exception API for SEH exception info
+// ---------------------------------------------------------------------------
+
+class SEHException : public Exception
+{
+    friend bool DebugIsEECxxExceptionPointer(void* pv);
+
+ public:
+    EXCEPTION_RECORD        m_exception;
+
+    SEHException();
+    SEHException(EXCEPTION_RECORD *pRecord, T_CONTEXT *pContext = NULL);
+
+    static const int c_type = 0x53454820;   // 'SEH '
+
+    // Dynamic type query for catchers
+    static int GetType() {LIMITED_METHOD_CONTRACT;  return c_type; }
+    virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; }
+    virtual BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type);  }
+
+    BOOL IsSameInstanceType(Exception *pException)
+    {
+        WRAPPER_NO_CONTRACT;
+        return pException->GetInstanceType() == GetType() && pException->GetHR() == GetHR();
+    }
+
+    // Virtual overrides
+    HRESULT GetHR();
+    IErrorInfo *GetErrorInfo();
+    void GetMessage(SString &result);
+
+ protected:
+    virtual Exception *CloneHelper()
+    {
+        WRAPPER_NO_CONTRACT;
+        return new SEHException(&m_exception);
+    }
+};
+
+// ---------------------------------------------------------------------------
+// DelegatingException class.  Implements exception API for "foreign" exceptions.
+// ---------------------------------------------------------------------------
+
+class DelegatingException : public Exception
+{
+    Exception *m_delegatedException;
+    Exception* GetDelegate();
+
+    enum {DELEGATE_NOT_YET_SET = -1};
+    bool IsDelegateSet() {LIMITED_METHOD_DAC_CONTRACT; return m_delegatedException != (Exception*)DELEGATE_NOT_YET_SET; }
+    bool IsDelegateValid() {LIMITED_METHOD_DAC_CONTRACT; return IsDelegateSet() && m_delegatedException != NULL; }
+
+ public:
+
+    DelegatingException();
+    ~DelegatingException();
+
+    static const int c_type = 0x44454C20;   // 'DEL '
+
+    // Dynamic type query for catchers
+    static int GetType() {LIMITED_METHOD_CONTRACT; return c_type; }
+    virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; }
+    virtual BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type);  }
+
+    BOOL IsSameInstanceType(Exception *pException)
+    {
+        WRAPPER_NO_CONTRACT;
+        return pException->GetInstanceType() == GetType() && pException->GetHR() == GetHR();
+    }
+
+    // Virtual overrides
+    virtual BOOL IsDomainBound() {return Exception::IsDomainBound() ||(m_delegatedException!=NULL && m_delegatedException->IsDomainBound());} ;
+    HRESULT GetHR();
+    IErrorInfo *GetErrorInfo();
+    void GetMessage(SString &result);
+    virtual Exception *Clone();
+
+ protected:
+    virtual Exception *CloneHelper()
+    {
+        WRAPPER_NO_CONTRACT;
+        return new DelegatingException();
+    }
+};
+
+//------------------------------------------------------------------------------
+// class OutOfMemoryException
+//
+//   While there could be any number of instances of this class, there is one
+//    special instance, the pre-allocated OOM exception.  Storage for that
+//    instance is allocated in the image, so we can always obtain it, even
+//    in low memory situations.
+//   Note that, in fact, there is only one instance.
+//------------------------------------------------------------------------------
+class OutOfMemoryException : public Exception
+{
+ private:
+    static const int c_type = 0x4F4F4D20;   // 'OOM '
+    BOOL    bIsPreallocated;
+
+ public:
+     OutOfMemoryException() : bIsPreallocated(FALSE) {}
+     OutOfMemoryException(BOOL b) : bIsPreallocated(b) {}
+
+    // Dynamic type query for catchers
+    static int GetType() {LIMITED_METHOD_CONTRACT;  return c_type; }
+    virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; }
+    BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type);  }
+
+    BOOL IsSameInstanceType(Exception *pException)
+    {
+        WRAPPER_NO_CONTRACT;
+        return pException->GetInstanceType() == GetType();
+    }
+
+    HRESULT GetHR() {LIMITED_METHOD_DAC_CONTRACT;  return E_OUTOFMEMORY; }
+    void GetMessage(SString &result) { WRAPPER_NO_CONTRACT; result.SetASCII("Out Of Memory"); }
+
+    virtual Exception *Clone();
+
+    virtual BOOL IsPreallocatedException() { return bIsPreallocated; }
+};
+
+template <typename STATETYPE>
+class CAutoTryCleanup
+{
+public:
+    DEBUG_NOINLINE CAutoTryCleanup(STATETYPE& refState) :
+        m_refState(refState)
+    {
+        SCAN_SCOPE_BEGIN;
+        STATIC_CONTRACT_THROWS;
+        STATIC_CONTRACT_SUPPORTS_DAC;
+
+#ifdef ENABLE_CONTRACTS_IMPL
+        // This is similar to ClrTryMarkerHolder. We're marking that its okay to throw on this thread now because
+        // we're within a try block. We fold this into here strictly for performance reasons... we have one
+        // stack-allocated object do the work.
+        m_pClrDebugState = GetClrDebugState();
+        m_oldOkayToThrowValue = m_pClrDebugState->IsOkToThrow();
+        m_pClrDebugState->SetOkToThrow();
+#endif
+    }
+
+    DEBUG_NOINLINE ~CAutoTryCleanup()
+    {
+        SCAN_SCOPE_END;
+        WRAPPER_NO_CONTRACT;
+
+        m_refState.CleanupTry();
+
+#ifdef ENABLE_CONTRACTS_IMPL
+        // Restore the original OkayToThrow value since we're leaving the try block.
+
+        m_pClrDebugState->SetOkToThrow( m_oldOkayToThrowValue );
+#endif // ENABLE_CONTRACTS_IMPL
+    }
+
+protected:
+    STATETYPE& m_refState;
+
+#ifdef ENABLE_CONTRACTS_DATA
+private:
+    BOOL           m_oldOkayToThrowValue;
+    ClrDebugState *m_pClrDebugState;
+#endif
+};
+
+// ---------------------------------------------------------------------------
+// Throw/Catch macros
+//
+// Usage:
+//
+// EX_TRY
+// {
+//      EX_THROW(HRException, (E_FAIL));
+// }
+// EX_CATCH
+// {
+//      Exception *e = GET_EXCEPTION();
+//      EX_RETHROW;
+// }
+// EX_END_CATCH(RethrowTerminalExceptions, RethrowTransientExceptions or SwallowAllExceptions)
+//
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// #NO_HOST_CPP_EH_ONLY
+//
+// The EX_CATCH* macros defined below can work one of two ways:
+//   1. They catch all exceptions, both C++ and SEH exceptions.
+//   2. They catch only C++ exceptions.
+//
+// Which way they are defined depends on what sort of handling of SEH
+// exceptions, like AV's, you wish to have in your DLL. In general we
+// do not typically want to catch and swallow AV's.
+//
+// By default, the macros catch all exceptions. This is how they work when
+// compiled into the primary runtime DLL (clr.dll). This is reasonable for
+// the CLR becuase it needs to also catch managed exceptions, which are SEH
+// exceptions, and because that DLL also includes a vectored exception
+// handler that will take down the process on any AV within clr.dll.
+//
+// But for uses of these macros outside of the CLR DLL there are other
+// possibilities. If a DLL only uses facilities in Utilcode that throw the
+// C++ exceptions defined above, and never needs to catch a managed exception,
+// then that DLL should setup the macros to only catch C++ exceptions. That
+// way, AV's are not accidentally swallowed and hidden.
+//
+// On the other hand, if a DLL needs to catch managed exceptions, then it has
+// no choice but to also catch all SEH exceptions, including AV's. In that case
+// the DLL should also include a vectored handler, like CLR.dll, to take the
+// process down on an AV.
+//
+// The behavior difference is controled by NO_HOST_CPP_EH_ONLY. When defined,
+// the EX_CATCH* macros only catch C++ exceptions. When not defined, they catch
+// C++ and SEH exceptions.
+//
+// Note: use of NO_HOST_CPP_EH_ONLY is only valid outside the primary CLR DLLs.
+// Thus it is an error to attempt to define it without also defining SELF_NO_HOST.
+// ---------------------------------------------------------------------------
+
+#if defined(NO_HOST_CPP_EH_ONLY) && !defined(SELF_NO_HOST)
+#error It is incorrect to attempt to have C++-only EH macros when hosted. This is only valid for components outside the runtime DLLs.
+#endif
+
+//-----------------------------------------------------------------------
+// EX_END_CATCH has a mandatory argument which is one of "RethrowTerminalExceptions",
+// "RethrowTransientExceptions", or "SwallowAllExceptions".
+//
+// If an exception is considered "terminal" (e->IsTerminal()), it should normally
+// be allowed to proceed. Hence, most of the time, you should use RethrowTerminalExceptions.
+//
+// In some cases you will want transient exceptions (terminal plus things like
+// resource exhaustion) to proceed as well.  Use RethrowTransientExceptions for this cas.
+//
+// If you have a good reason to use SwallowAllExceptions, (e.g. a hard COM interop boundary)
+// use one of the higher level macros for this if available, or consider developing one.
+// Otherwise, clearly document why you're swallowing terminal exceptions. Raw uses of
+// SwallowAllExceptions will cause the cleanup police to come knocking on your door
+// at some point.
+//
+// A lot of existing TRY's swallow terminals right now simply because there is
+// backout code following the END_CATCH that has to be executed. The solution is
+// to replace that backout code with holder objects.
+
+//-----------------------------------------------------------------------
+
+#define RethrowTransientExceptions                                      \
+    if (GET_EXCEPTION()->IsTransient())                                 \
+    {                                                                   \
+        EX_RETHROW;                                                     \
+    }                                                                   \
+
+#define SwallowAllExceptions ;
+
+// When applied to EX_END_CATCH, this policy will always rethrow Terminal exceptions if they are
+// encountered.
+#define RethrowTerminalExceptions                                       \
+    if (GET_EXCEPTION()->IsTerminal())                                  \
+    {                                                                   \
+        STATIC_CONTRACT_THROWS_TERMINAL;                                \
+        EX_RETHROW;                                                     \
+    }                                                                   \
+
+// Special define to be used in EEStartup that will also check for VM initialization before
+// commencing on a path that may use the managed thread object.
+#define RethrowTerminalExceptionsWithInitCheck  \
+    if ((g_fEEStarted == TRUE) && (GetThreadNULLOk() != NULL))    \
+    {                                                       \
+        RethrowTerminalExceptions                           \
+    }
+
+#ifdef _DEBUG
+
+void ExThrowTrap(const char *fcn, const char *file, int line, const char *szType, HRESULT hr, const char *args);
+
+#define EX_THROW_DEBUG_TRAP(fcn, file, line, szType, hr, args) ExThrowTrap(fcn, file, line, szType, hr, args)
+
+#else
+
+#define EX_THROW_DEBUG_TRAP(fcn, file, line, szType, hr, args)
+
+#endif
+
+#define EX_THROW(_type, _args)                                                          \
+    {                                                                                   \
+        FAULT_NOT_FATAL();                                                              \
+                                                                                        \
+        _type * ___pExForExThrow =  new _type _args ;                                   \
+                /* don't embed file names in retail to save space and avoid IP */       \
+                /* a findstr /n will allow you to locate it in a pinch */               \
+        STRESS_LOG3(LF_EH, LL_INFO100, "EX_THROW Type = 0x%x HR = 0x%x, "               \
+                    INDEBUG(__FILE__) " line %d\n", _type::GetType(),                   \
+                    ___pExForExThrow->GetHR(), __LINE__);                               \
+        EX_THROW_DEBUG_TRAP(__FUNCTION__, __FILE__, __LINE__, #_type, ___pExForExThrow->GetHR(), #_args);          \
+        PAL_CPP_THROW(_type *, ___pExForExThrow);                                       \
+    }
+
+//--------------------------------------------------------------------------------
+// Clones an exception into the current domain. Also handles special cases for
+// OOM and other stuff. Making this a function so we don't inline all this logic
+// every place we call EX_THROW_WITH_INNER.
+//--------------------------------------------------------------------------------
+Exception *ExThrowWithInnerHelper(Exception *inner);
+
+// This macro will set the m_innerException into the newly created exception
+// The passed in _type has to be derived from CLRException. You cannot put OOM
+// as the inner exception. If we are throwing in OOM case, allocate more memory (this macro will clone)
+// does not make any sense.
+//
+#define EX_THROW_WITH_INNER(_type, _args, _inner)                                       \
+    {                                                                                   \
+        FAULT_NOT_FATAL();                                                              \
+                                                                                        \
+        Exception *_inner2 = ExThrowWithInnerHelper(_inner);                            \
+        _type *___pExForExThrow =  new _type _args ;                                    \
+        ___pExForExThrow->SetInnerException(_inner2);                                   \
+        STRESS_LOG3(LF_EH, LL_INFO100, "EX_THROW_WITH_INNER Type = 0x%x HR = 0x%x, "    \
+                    INDEBUG(__FILE__) " line %d\n", _type::GetType(),                   \
+                    ___pExForExThrow->GetHR(), __LINE__);                               \
+        EX_THROW_DEBUG_TRAP(__FUNCTION__, __FILE__, __LINE__, #_type, ___pExForExThrow->GetHR(), #_args);          \
+        PAL_CPP_THROW(_type *, ___pExForExThrow);                                       \
+    }
+
+//#define IsCLRException(ex) ((ex !=NULL) && ex->IsType(CLRException::GetType())
+
+#define EX_TRY_IMPL EX_TRY_CUSTOM(Exception::HandlerState, , DelegatingException /* was SEHException*/)
+
+#define EX_TRY_CPP_ONLY EX_TRY_CUSTOM_CPP_ONLY(Exception::HandlerState, , DelegatingException /* was SEHException*/)
+
+#ifndef INCONTRACT
+#ifdef ENABLE_CONTRACTS
+#define INCONTRACT(x)          x
+#else
+#define INCONTRACT(x)
+#endif
+#endif
+
+#define EX_TRY_CUSTOM(STATETYPE, STATEARG, DEFAULT_EXCEPTION_TYPE)                      \
+    {                                                                                   \
+        STATETYPE               __state STATEARG;                                       \
+        typedef DEFAULT_EXCEPTION_TYPE  __defaultException_t;                           \
+        SCAN_EHMARKER();                                                                \
+        PAL_CPP_TRY                                                                     \
+        {                                                                               \
+            SCAN_EHMARKER_TRY();                                                        \
+            SCAN_EHMARKER();                                                            \
+            PAL_CPP_TRY                                                                 \
+            {                                                                           \
+                SCAN_EHMARKER_TRY();                                                    \
+                CAutoTryCleanup<STATETYPE> __autoCleanupTry(__state);                   \
+                /* prevent annotations from being dropped by optimizations in debug */  \
+                INDEBUG(static bool __alwayszero;)                                      \
+                INDEBUG(VolatileLoad(&__alwayszero);)                                   \
+                {                                                                       \
+                    /* Disallow returns to make exception handling work. */             \
+                    /* Some work is done after the catch, see EX_ENDTRY. */             \
+                    DEBUG_ASSURE_NO_RETURN_BEGIN(EX_TRY)                                \
+                    EX_TRY_HOLDER                                                       \
+
+
+#define EX_CATCH_IMPL_EX(DerivedExceptionClass)                                         \
+                    DEBUG_ASSURE_NO_RETURN_END(EX_TRY)                                  \
+                }                                                                       \
+                SCAN_EHMARKER_END_TRY();                                                \
+            }                                                                           \
+            PAL_CPP_CATCH_DERIVED (DerivedExceptionClass, __pExceptionRaw)              \
+            {                                                                           \
+                SCAN_EHMARKER_CATCH();                                                  \
+                __state.SetCaughtCxx();                                                 \
+                __state.m_pExceptionPtr = __pExceptionRaw;                              \
+                SCAN_EHMARKER_END_CATCH();                                              \
+                SCAN_IGNORE_THROW_MARKER;                                               \
+                PAL_CPP_RETHROW;                                                        \
+            }                                                                           \
+            PAL_CPP_ENDTRY                                                              \
+            SCAN_EHMARKER_END_TRY();                                                    \
+        }                                                                               \
+        PAL_CPP_CATCH_ALL                                                               \
+        {                                                                               \
+            SCAN_EHMARKER_CATCH();                                                      \
+            __defaultException_t __defaultException;                                    \
+            CHECK::ResetAssert();                                                       \
+            ExceptionHolder __pException(__state.m_pExceptionPtr);                      \
+            /* work around unreachable code warning */                                  \
+            if (true) {                                                                 \
+                DEBUG_ASSURE_NO_RETURN_BEGIN(EX_CATCH)                                  \
+                /* don't embed file names in retail to save space and avoid IP */       \
+                /* a findstr /n will allow you to locate it in a pinch */               \
+                __state.SetupCatch(INDEBUG_COMMA(__FILE__) __LINE__);                   \
+
+#define EX_CATCH_IMPL EX_CATCH_IMPL_EX(Exception)
+
+#define EX_TRY_CUSTOM_CPP_ONLY(STATETYPE, STATEARG, DEFAULT_EXCEPTION_TYPE)         \
+    {                                                                               \
+        STATETYPE               __state STATEARG;                                   \
+        typedef DEFAULT_EXCEPTION_TYPE  __defaultException_t;                       \
+        SCAN_EHMARKER();                                                            \
+        PAL_CPP_TRY                                                                 \
+        {                                                                           \
+            SCAN_EHMARKER_TRY();                                                    \
+            CAutoTryCleanup<STATETYPE> __autoCleanupTry(__state);                   \
+            /* prevent annotations from being dropped by optimizations in debug */  \
+            INDEBUG(static bool __alwayszero;)                                      \
+            INDEBUG(VolatileLoad(&__alwayszero);)                                   \
+            {                                                                       \
+                /* Disallow returns to make exception handling work. */             \
+                /* Some work is done after the catch, see EX_ENDTRY. */             \
+                DEBUG_ASSURE_NO_RETURN_BEGIN(EX_TRY)                                \
+
+#define EX_CATCH_IMPL_CPP_ONLY                                                      \
+                DEBUG_ASSURE_NO_RETURN_END(EX_TRY)                                  \
+            }                                                                       \
+            SCAN_EHMARKER_END_TRY();                                                \
+        }                                                                           \
+        PAL_CPP_CATCH_DERIVED (Exception, __pExceptionRaw)                          \
+        {                                                                           \
+            SCAN_EHMARKER_CATCH();                                                  \
+            __state.SetCaughtCxx();                                                 \
+            __state.m_pExceptionPtr = __pExceptionRaw;                              \
+            SCAN_EHMARKER_END_CATCH();                                              \
+            SCAN_IGNORE_THROW_MARKER;                                               \
+            __defaultException_t __defaultException;                                \
+            CHECK::ResetAssert();                                                   \
+            ExceptionHolder __pException(__state.m_pExceptionPtr);                  \
+            /* work around unreachable code warning */                              \
+            if (true) {                                                             \
+                DEBUG_ASSURE_NO_RETURN_BEGIN(EX_CATCH)                              \
+                /* don't embed file names in retail to save space and avoid IP */   \
+                /* a findstr /n will allow you to locate it in a pinch */           \
+                __state.SetupCatch(INDEBUG_COMMA(__FILE__) __LINE__);               \
+
+
+// Here we finally define the EX_CATCH* macros that will be used throughout the system.
+// These can catch C++ and SEH exceptions, or just C++ exceptions.
+// See code:NO_HOST_CPP_EH_ONLY for more details.
+//
+// Note: we make it illegal to use forms that are redundant with the basic EX_CATCH
+// version. I.e., in the C++ & SEH version, EX_CATCH_CPP_AND_SEH is the same as EX_CATCH.
+// Likewise, in the C++ only version, EX_CATCH_CPP_ONLY is redundant with EX_CATCH.
+
+#ifndef NO_HOST_CPP_EH_ONLY
+#define EX_TRY                  EX_TRY_IMPL
+#define EX_CATCH                EX_CATCH_IMPL
+#define EX_CATCH_EX             EX_CATCH_IMPL_EX
+#define EX_CATCH_CPP_ONLY       EX_CATCH_IMPL_CPP_ONLY
+#define EX_CATCH_CPP_AND_SEH    Dont_Use_EX_CATCH_CPP_AND_SEH
+#else
+#define EX_TRY                  EX_TRY_CPP_ONLY
+#define EX_CATCH                EX_CATCH_IMPL_CPP_ONLY
+#define EX_CATCH_CPP_ONLY       Dont_Use_EX_CATCH_CPP_ONLY
+#define EX_CATCH_CPP_AND_SEH    EX_CATCH_IMPL
+
+// Note: at this time we don't have a use case for EX_CATCH_EX, and we do not have
+// the C++-only version of the implementation available. Thus we disallow its use at this time.
+// If a real use case arises then we should go ahead and enable this.
+#define EX_CATCH_EX             Dont_Use_EX_CATCH_EX
+#endif
+
+#define EX_END_CATCH_UNREACHABLE                                                        \
+                DEBUG_ASSURE_NO_RETURN_END(EX_CATCH)                                    \
+            }                                                                           \
+            SCAN_EHMARKER_END_CATCH();                                                  \
+            UNREACHABLE();                                                              \
+        }                                                                               \
+        PAL_CPP_ENDTRY                                                                  \
+    }                                                                                   \
+
+
+// "terminalexceptionpolicy" must be one of "RethrowTerminalExceptions",
+// "RethrowTransientExceptions", or "SwallowAllExceptions"
+
+#define EX_END_CATCH(terminalexceptionpolicy)                                           \
+                terminalexceptionpolicy;                                                \
+                __state.SucceedCatch();                                                 \
+                DEBUG_ASSURE_NO_RETURN_END(EX_CATCH)                                    \
+            }                                                                           \
+            SCAN_EHMARKER_END_CATCH();                                                  \
+        }                                                                               \
+        EX_ENDTRY                                                                       \
+    }                                                                                   \
+
+
+#define EX_END_CATCH_FOR_HOOK                                                           \
+                __state.SucceedCatch();                                                 \
+                DEBUG_ASSURE_NO_RETURN_END(EX_CATCH)                                    \
+                ANNOTATION_HANDLER_END;                                                 \
+            }                                                                           \
+            SCAN_EHMARKER_END_CATCH();                                                  \
+        }                                                                               \
+        EX_ENDTRY
+
+#define EX_ENDTRY                                                                       \
+        PAL_CPP_ENDTRY
+
+#define EX_RETHROW                                                                      \
+        {                                                                               \
+            __pException.SuppressRelease();                                             \
+            PAL_CPP_RETHROW;                                                            \
+        }                                                                               \
+
+ // Define a copy of GET_EXCEPTION() that will not be redefined by clrex.h
+#define GET_EXCEPTION() (__pException == NULL ? &__defaultException : __pException.GetValue())
+#define EXTRACT_EXCEPTION() (__pException.Extract())
+
+
+//==============================================================================
+// High-level macros for common uses of EX_TRY. Try using these rather
+// than the raw EX_TRY constructs.
+//==============================================================================
+
+//===================================================================================
+// Macro for converting exceptions into HR internally. Unlike EX_CATCH_HRESULT,
+// it does not set up IErrorInfo on the current thread.
+//
+// Usage:
+//
+//   HRESULT hr = S_OK;
+//   EX_TRY
+//   <do managed stuff>
+//   EX_CATCH_HRESULT_NO_ERRORINFO(hr);
+//   return hr;
+//
+// Comments:
+//   Since IErrorInfo is not set up, this does not require COM interop to be started.
+//===================================================================================
+
+#define EX_CATCH_HRESULT_NO_ERRORINFO(_hr)                                      \
+    EX_CATCH                                                                    \
+    {                                                                           \
+        (_hr) = GET_EXCEPTION()->GetHR();                                       \
+        _ASSERTE(FAILED(_hr));                                                  \
+    }                                                                           \
+    EX_END_CATCH(SwallowAllExceptions)
+
+
+//===================================================================================
+// Macro for catching managed exception object.
+//
+// Usage:
+//
+//   OBJECTREF pThrowable = NULL;
+//   EX_TRY
+//   <do managed stuff>
+//   EX_CATCH_THROWABLE(&pThrowable);
+//
+//===================================================================================
+
+#define EX_CATCH_THROWABLE(ppThrowable)                                         \
+    EX_CATCH                                                                    \
+    {                                                                           \
+        *ppThrowable = GET_THROWABLE();                                         \
+    }                                                                           \
+    EX_END_CATCH(SwallowAllExceptions)
+
+
+#ifdef FEATURE_COMINTEROP
+
+//===================================================================================
+// Macro for defining external entrypoints such as COM interop boundaries.
+// The boundary will catch all exceptions (including terminals) and convert
+// them into HR/IErrorInfo pairs as appropriate.
+//
+// Usage:
+//
+//   HRESULT hr = S_OK;
+//   EX_TRY
+//   <do managed stuff>
+//   EX_CATCH_HRESULT(hr);
+//   return hr;
+//
+// Comments:
+//   Note that IErrorInfo will automatically be set up on the thread if appropriate.
+//===================================================================================
+
+#define EX_CATCH_HRESULT(_hr)                                                   \
+    EX_CATCH                                                                    \
+    {                                                                           \
+        (_hr) = GET_EXCEPTION()->GetHR();                                       \
+        _ASSERTE(FAILED(_hr));                                                  \
+        IErrorInfo *pErr = GET_EXCEPTION()->GetErrorInfo();                     \
+        if (pErr != NULL)                                                       \
+        {                                                                       \
+            SetErrorInfo(0, pErr);                                              \
+            pErr->Release();                                                    \
+        }                                                                       \
+    }                                                                           \
+    EX_END_CATCH(SwallowAllExceptions)
+
+//===================================================================================
+// Macro to make conditional catching more succinct.
+//
+// Usage:
+//
+//   EX_TRY
+//   ...
+//   EX_CATCH_HRESULT_IF(IsHRESULTForExceptionKind(GET_EXCEPTION()->GetHR(), kFileNotFoundException));
+//===================================================================================
+
+#define EX_CATCH_HRESULT_IF(HR, ...)                                            \
+    EX_CATCH                                                                    \
+    {                                                                           \
+        (HR) = GET_EXCEPTION()->GetHR();                                        \
+                                                                                \
+        /* Rethrow if condition is false. */                                    \
+        if (!(__VA_ARGS__))                                                     \
+            EX_RETHROW;                                                         \
+                                                                                \
+        _ASSERTE(FAILED(HR));                                                   \
+        IErrorInfo *pErr = GET_EXCEPTION()->GetErrorInfo();                     \
+        if (pErr != NULL)                                                       \
+        {                                                                       \
+            SetErrorInfo(0, pErr);                                              \
+            pErr->Release();                                                    \
+        }                                                                       \
+    }                                                                           \
+    EX_END_CATCH(SwallowAllExceptions)
+
+#else // FEATURE_COMINTEROP
+
+#define EX_CATCH_HRESULT(_hr) EX_CATCH_HRESULT_NO_ERRORINFO(_hr)
+
+#endif // FEATURE_COMINTEROP
+
+//===================================================================================
+// Macro for containing normal exceptions but letting terminal exceptions continue to propagate.
+//
+// Usage:
+//
+//  EX_TRY
+//  {
+//      ...your stuff...
+//  }
+//  EX_SWALLOW_NONTERMINAL
+//
+// Remember, terminal exceptions (such as ThreadAbort) will still throw out of this
+// block. So don't use this as a substitute for exception-safe cleanup!
+//===================================================================================
+
+#define EX_SWALLOW_NONTERMINAL                           \
+    EX_CATCH                                             \
+    {                                                    \
+    }                                                    \
+    EX_END_CATCH(RethrowTerminalExceptions)              \
+
+
+//===================================================================================
+// Macro for containing normal exceptions but letting transient exceptions continue to propagate.
+//
+// Usage:
+//
+//  EX_TRY
+//  {
+//      ...your stuff...
+//  }
+//  EX_SWALLOW_NONTRANSIENT
+//
+// Terminal exceptions (such as ThreadAbort and OutOfMemory) will still throw out of this
+// block. So don't use this as a substitute for exception-safe cleanup!
+//===================================================================================
+
+#define EX_SWALLOW_NONTRANSIENT                          \
+    EX_CATCH                                             \
+    {                                                    \
+    }                                                    \
+    EX_END_CATCH(RethrowTransientExceptions)             \
+
+
+//===================================================================================
+// Macro for observing or wrapping exceptions in flight.
+//
+// Usage:
+//
+//   EX_TRY
+//   {
+//      ... your stuff ...
+//   }
+//   EX_HOOK
+//   {
+//      ... your stuff ...
+//   }
+//   EX_END_HOOK
+//   ... control will never get here ...
+//
+//
+// EX_HOOK is like EX_CATCH except that you can't prevent the
+// exception from being rethrown. You can throw a new exception inside the hook
+// (for example, if you want to wrap the exception in flight with your own).
+// But if control reaches the end of the hook, the original exception gets rethrown.
+//
+// Avoid using EX_HOOK for conditional backout if a destructor-based holder
+// will suffice. Because these macros are implemented on top of SEH, using them will
+// prevent the use of holders anywhere else inside the same function. That is, instead
+// of saying this:
+//
+//     EX_TRY          // DON'T DO THIS
+//     {
+//          thing = new Thing();
+//          blah
+//     }
+//     EX_HOOK
+//     {
+//          delete thing; // if it failed, we don't want to keep the Thing.
+//     }
+//     EX_END_HOOK
+//
+// do this:
+//
+//     Holder<Thing> thing = new Thing();   //DO THIS INSTEAD
+//     blah
+//     // If we got here, we succeeded. So tell holder we want to keep the thing.
+//     thing.SuppressRelease();
+//
+//     We won't rethrow the exception if it is a Stack Overflow exception. Instead, we'll throw a new
+//   exception. This will allow the stack to unwind point, and so we won't be jeopardizing a
+//   second stack overflow.
+//===================================================================================
+#define EX_HOOK                                          \
+    EX_CATCH                                             \
+    {                                                    \
+
+#define EX_END_HOOK                                      \
+    }                                                    \
+    ANNOTATION_HANDLER_END;                              \
+    EX_RETHROW;                                          \
+    EX_END_CATCH_FOR_HOOK;                               \
+    }
+
+// ---------------------------------------------------------------------------
+// Inline implementations. Pay no attention to that man behind the curtain.
+// ---------------------------------------------------------------------------
+
+inline Exception::HandlerState::HandlerState()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+
+    m_dwFlags = 0;
+    m_pExceptionPtr = NULL;
+
+#if defined(STACK_GUARDS_DEBUG) && defined(ENABLE_CONTRACTS_IMPL)
+    // If we have a debug state, use its setting for SO tolerance.  The default
+    // is SO-tolerant if we have no debug state.  Can't probe w/o debug state and
+    // can't enter SO-interolant mode w/o probing.
+    GetClrDebugState();
+#endif
+}
+
+inline void Exception::HandlerState::CleanupTry()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+}
+
+inline void Exception::HandlerState::SetupCatch(INDEBUG_COMMA(_In_z_ const char * szFile) int lineNum)
+{
+    WRAPPER_NO_CONTRACT;
+
+    /* don't embed file names in retail to save space and avoid IP */
+    /* a findstr /n will allow you to locate it in a pinch */
+#ifdef _DEBUG
+    STRESS_LOG2(LF_EH, LL_INFO100, "EX_CATCH %s line %d\n", szFile, lineNum);
+#else
+    STRESS_LOG1(LF_EH, LL_INFO100, "EX_CATCH line %d\n", lineNum);
+#endif
+
+    SetCaught();
+}
+
+inline void Exception::HandlerState::SucceedCatch()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+}
+
+inline HRException::HRException()
+  : m_hr(E_UNEXPECTED)
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+}
+
+inline HRException::HRException(HRESULT hr)
+  : m_hr(hr)
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+
+    // Catchers assume only failing hresults
+    _ASSERTE(FAILED(hr));
+}
+
+inline HRMsgException::HRMsgException()
+  : HRException()
+{
+    LIMITED_METHOD_CONTRACT;
+}
+
+inline HRMsgException::HRMsgException(HRESULT hr, SString const &s)
+  : HRException(hr), m_msg(s)
+{
+    WRAPPER_NO_CONTRACT;
+}
+
+inline COMException::COMException()
+  : HRException(),
+  m_pErrorInfo(NULL)
+{
+    WRAPPER_NO_CONTRACT;
+}
+
+inline COMException::COMException(HRESULT hr)
+  : HRException(hr),
+  m_pErrorInfo(NULL)
+{
+    LIMITED_METHOD_CONTRACT;
+}
+
+inline COMException::COMException(HRESULT hr, IErrorInfo *pErrorInfo)
+  : HRException(hr),
+  m_pErrorInfo(pErrorInfo)
+{
+    LIMITED_METHOD_CONTRACT;
+}
+
+inline SEHException::SEHException()
+{
+    LIMITED_METHOD_CONTRACT;
+    memset(&m_exception, 0, sizeof(EXCEPTION_RECORD));
+}
+
+inline SEHException::SEHException(EXCEPTION_RECORD *pointers, T_CONTEXT *pContext)
+{
+    LIMITED_METHOD_CONTRACT;
+    memcpy(&m_exception, pointers, sizeof(EXCEPTION_RECORD));
+}
+
+// The exception throwing helpers are intentionally not inlined
+// Exception throwing is a rare slow codepath that should be optimized for code size
+
+void DECLSPEC_NORETURN ThrowHR(HRESULT hr);
+void DECLSPEC_NORETURN ThrowHR(HRESULT hr, SString const &msg);
+void DECLSPEC_NORETURN ThrowWin32(DWORD err);
+void DECLSPEC_NORETURN ThrowLastError();
+void DECLSPEC_NORETURN ThrowOutOfMemory();
+void DECLSPEC_NORETURN ThrowStackOverflow();
+
+#undef IfFailThrow
+inline HRESULT IfFailThrow(HRESULT hr)
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (FAILED(hr))
+    {
+        ThrowHR(hr);
+    }
+
+    return hr;
+}
+
+inline HRESULT IfFailThrow(HRESULT hr, SString &msg)
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (FAILED(hr))
+    {
+        ThrowHR(hr, msg);
+    }
+
+    return hr;
+}
+
+inline HRESULT IfTransientFailThrow(HRESULT hr)
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (FAILED(hr) && Exception::IsTransient(hr))
+    {
+        ThrowHR(hr);
+    }
+
+    return hr;
+}
+
+// Set if fatal error (like stack overflow or out of memory) occurred in this process.
+GVAL_DECL(HRESULT, g_hrFatalError);
+
+#endif  // _EX_H_
diff --git a/src/inc/fstring.h b/src/inc/fstring.h
new file mode 100644 (file)
index 0000000..1be37e2
--- /dev/null
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// FString.h  (Fast String)
+//
+
+// ---------------------------------------------------------------------------
+
+// ------------------------------------------------------------------------------------------
+// FString is fast string handling namespace
+
+
+// 1) Simple
+// 2) No C++ exception
+// 3) Optimized for speed
+
+
+#ifndef _FSTRING_H_
+#define _FSTRING_H_
+
+namespace FString
+{
+    // Note: All "length" parameters do not count the space for the null terminator.
+    // Caller of Unicode_Utf8 and Utf8_Unicode must pass in a buffer of size at least length + 1.
+
+    // Scan for ASCII only string, calculate result UTF8 string length
+    HRESULT Unicode_Utf8_Length(_In_z_ LPCWSTR pString, _Out_ bool * pAllAscii, _Out_ DWORD * pLength);
+
+    // Convert UNICODE string to UTF8 string. Direct/fast conversion if ASCII
+    HRESULT Unicode_Utf8(_In_z_ LPCWSTR pString, bool allAscii, _Out_writes_bytes_(length) LPSTR pBuffer, DWORD length);
+
+    // Scan for ASCII string, calculate result UNICODE string length
+    HRESULT Utf8_Unicode_Length(_In_z_ LPCSTR pString, _Out_ bool * pAllAscii, _Out_ DWORD * pLength);
+
+    // Convert UTF8 string to UNICODE. Direct/fast conversion if ASCII
+    HRESULT Utf8_Unicode(_In_z_ LPCSTR pString, bool allAscii, _Out_writes_bytes_(length) LPWSTR pBuffer, DWORD length);
+
+    HRESULT ConvertUnicode_Utf8(_In_z_ LPCWSTR pString, _Outptr_result_z_ LPSTR * pBuffer);
+
+    HRESULT ConvertUtf8_Unicode(_In_z_ LPCSTR pString, _Outptr_result_z_ LPWSTR * pBuffer);
+
+}  // namespace FString
+
+#endif  // _FSTRING_H_
diff --git a/src/inc/getproductversionnumber.h b/src/inc/getproductversionnumber.h
new file mode 100644 (file)
index 0000000..068ed78
--- /dev/null
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// GetProductVersionNumber.h
+//
+// Helper function to retrieve the file version number of a file.
+//
+// ======================================================================================
+
+
+
+#ifndef __GetProductVersionNumber_h__
+#define __GetProductVersionNumber_h__
+
+#include "contract.h"
+#include "sstring.h"
+#include "holder.h"
+#include "ex.h"
+
+//---------------------------------------------------------------------------------------
+//
+// Given the full path to an image, return the product version number.
+//
+// Arguments:
+//    szFullPath - full path to the image
+//    pdwVersionMS - out parameter; return the most significant 4 bytes of the version number according to
+//                   the VS_FIXEDFILEINFO convention
+//    pdwVersionLS - out parameter; return the least significant 4 bytes of the version number according to
+//                   the VS_FIXEDFILEINFO convention
+//
+// Notes:
+//    Throws on error
+
+void inline GetProductVersionNumber(SString &szFullPath, DWORD * pdwVersionMS, DWORD * pdwVersionLS)
+{
+    WRAPPER_NO_CONTRACT;
+#ifndef TARGET_UNIX
+
+    DWORD dwDummy = 0;
+    DWORD dwFileInfoSize = 0;
+
+    // Get the size of all of the file version information.
+    dwFileInfoSize = GetFileVersionInfoSize(szFullPath, &dwDummy);
+    if (dwFileInfoSize == 0)
+    {
+        ThrowLastError();
+    }
+
+    // Create the buffer to store the file information.
+    NewHolder<BYTE> pbFileInfo(new BYTE[dwFileInfoSize]);
+
+    // Actually retrieve the file version information.
+    if (!GetFileVersionInfo(szFullPath, NULL, dwFileInfoSize, pbFileInfo))
+    {
+        ThrowLastError();
+    }
+
+    // Now retrieve only the relevant version information, which will be returned in a VS_FIXEDFILEINFO.
+    UINT uVersionInfoSize = 0;
+    VS_FIXEDFILEINFO * pVersionInfo = NULL;
+
+    if (!VerQueryValue(pbFileInfo, W("\\"), reinterpret_cast<LPVOID *>(&pVersionInfo), &uVersionInfoSize))
+    {
+        ThrowLastError();
+    }
+    _ASSERTE(uVersionInfoSize == sizeof(VS_FIXEDFILEINFO));
+
+    *pdwVersionMS = pVersionInfo->dwProductVersionMS;
+    *pdwVersionLS = pVersionInfo->dwProductVersionLS;
+#else
+    *pdwVersionMS = 0;
+    *pdwVersionLS = 0;
+#endif // TARGET_UNIX
+}
+
+#endif // __GetProductVersionNumber_h__
diff --git a/src/inc/holder.h b/src/inc/holder.h
new file mode 100644 (file)
index 0000000..4ec7b10
--- /dev/null
@@ -0,0 +1,1404 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#ifndef __HOLDER_H_
+#define __HOLDER_H_
+
+#include <wincrypt.h>
+#include "cor.h"
+#include "staticcontract.h"
+#include "volatile.h"
+#include "palclr.h"
+
+#ifdef PAL_STDCPP_COMPAT
+#include <utility>
+#include <type_traits>
+#else
+#include "clr_std/utility"
+#include "clr_std/type_traits"
+#endif
+
+#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
+#include <Activation.h>
+#include <Inspectable.h>
+#endif
+
+// Note: you can't use CONTRACT's in this file. You can't use dynamic contracts because the impl of dynamic
+// contracts depends on holders. You can't use static contracts because they include the function name as a string,
+// and the template names in this file are just too long, so you get a compiler error.
+//
+// All the functions in this file are pretty basic, so the lack of CONTRACT's isn't a big loss.
+
+#ifdef _MSC_VER
+// Make sure we can recurse deep enough for FORCEINLINE
+#pragma inline_recursion(on)
+#pragma inline_depth(16)
+#pragma warning(disable:4714)
+#endif  // _MSC_VER
+
+//------------------------------------------------------------------------------------------------
+// Declare but do not define methods that would normally be automatically generated by the
+// compiler. This will produce a link-time error if they are used. This is involved in object
+// initialization and operator eliding; see
+// http://groups.google.com/group/comp.lang.c++/msg/3cd673ab749bed83?dmode=source
+// for the intricate details.
+
+#ifdef __GNUC__
+// GCC checks accessibility of the copy ctor before performing elision optimization, so
+// it must be declared as public. VC does not, so we can declare it private to give an
+// earlier error message.
+#define HIDE_GENERATED_METHODS(_NAME)                                                       \
+    public:                                                                                 \
+        _NAME(_NAME const &);                                                               \
+    private:                                                                                \
+        _NAME & operator=(_NAME const &);
+#else
+#define HIDE_GENERATED_METHODS(_NAME)                                                       \
+    private:                                                                                \
+        _NAME(_NAME const &);                                                               \
+        _NAME & operator=(_NAME const &);
+#endif
+
+#ifdef _DEBUG
+
+//------------------------------------------------------------------------------------------------
+// This is used to make Visual Studio autoexp.dat work sensibly with holders again.
+// The problem is that certain codebases (particulary Fusion) implement key data structures
+// using a class but refer to it using a holder to an interface type. This combination prevents
+// autoexp rules from working as desired.
+//
+// Example: Take this useful autoexp rule for CAssemblyName.
+//
+//   CAssemblyName=<_rProp._rProp[3].asStr>
+//
+// To get the same rule to fire when your assemblyname is wrapped in a ReleaseHolder,
+// add these companion rules.
+//
+//    HolderBase<CAssemblyName *>=<m_value->_rProp._rProp[3].asStr>
+//    HolderBase<IAssemblyName *>=<m_pAutoExpVisibleValue->_asCAssemblyName->_rProp._rProp[3].asStr>
+//
+//------------------------------------------------------------------------------------------------
+struct AutoExpVisibleValue
+{
+  private:
+    union
+    {
+        const void                                          *_pPreventEmptyUnion;
+    };
+};
+#endif //_DEBUG
+
+//-----------------------------------------------------------------------------
+// Holder is the base class of all holder objects.  Any backout object should derive from it.
+// (Eventually some additional bookeeping and exception handling code will be placed in this
+// base class.)
+//
+// There are several ways to use this class:
+//  1. Derive from HolderBase, and instantiate a Holder or Wrapper around your base.  This is necessary
+//      if you need to add more state to your holder.
+//  2. Instantiate the Holder template with your type and functions.
+//  3. Instantiate the Wrapper template with your type and functions.  The Wrapper adds some additional
+//      operator overloads to provide "smart pointer" like behavior
+//  4. Use a prebaked Holder.  This is ALWAYS the preferable strategy.  It is expected that
+//      the general design patter is that Holders will be provided as part of a typical data abstraction.
+//      (See Crst for an example of this.)
+//-----------------------------------------------------------------------------
+
+
+
+//-----------------------------------------------------------------------------
+// HolderBase defines the base holder functionality. You can subtype and plug in
+// a different base if you need to add more members for access during
+// acquire & release
+//-----------------------------------------------------------------------------
+template <typename TYPE>
+class HolderBase
+{
+    friend class ClrDataAccess;
+
+  protected:
+    TYPE    m_value;
+
+    HolderBase(TYPE value)
+      : m_value(value)
+    {
+#ifdef _DEBUG
+        m_pAutoExpVisibleValue = (const AutoExpVisibleValue *)(&m_value);
+#endif //_DEBUG
+    }
+
+    void DoAcquire()
+    {
+        // Insert any global or thread bookeeping here
+    }
+
+    void DoRelease()
+    {
+        // Insert any global or thread bookeeping here
+    }
+
+#ifdef _DEBUG
+ private:
+    // NOT DEAD CODE: This field is not referenced in the source code but it is not a dead field. See comments above "class AutoExpVisibleValue" for why this field exists.
+    // Note: What we really want is for m_value and m_pAutoExpVisibleValue to be members of a union. But the compiler won't let you build that
+    //       since it can't prove that "TYPE" doesn't have a non-trivial constructor.
+    const AutoExpVisibleValue *m_pAutoExpVisibleValue;  // This field is to be referenced from individual autoexp.dat files, NOT from the CLR source code.
+#endif //_DEBUG
+
+};  // class HolderBase<>
+
+#ifndef _PREFAST_ // Work around an ICE error in EspX.dll
+
+template <typename TYPE>
+BOOL CompareDefault(TYPE value, TYPE defaultValue)
+{
+    STATIC_CONTRACT_SUPPORTS_DAC;
+    return value == defaultValue;
+}
+
+#else
+
+template <typename TYPE>
+BOOL CompareDefault(TYPE value, TYPE defaultValue)
+{
+    return FALSE;
+}
+
+#endif
+
+
+template <typename TYPE>
+BOOL NoNull(TYPE value, TYPE defaultValue)
+{
+    return FALSE;
+}
+
+// Used e.g. for retail version of code:SyncAccessHolder
+template <typename TYPE>
+class NoOpBaseHolder
+{
+  public:
+    FORCEINLINE NoOpBaseHolder()
+    {
+    }
+    FORCEINLINE NoOpBaseHolder(TYPE value, BOOL take = TRUE)
+    {
+    }
+    FORCEINLINE ~NoOpBaseHolder()
+    {
+    }
+    FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
+    {
+    }
+    FORCEINLINE void Acquire()
+    {
+    }
+    FORCEINLINE void Release()
+    {
+    }
+    FORCEINLINE void Clear()
+    {
+    }
+    FORCEINLINE void SuppressRelease()
+    {
+    }
+    FORCEINLINE TYPE Extract()
+    {
+    }
+    FORCEINLINE TYPE GetValue()
+    {
+    }
+    FORCEINLINE BOOL IsNull() const
+    {
+        return FALSE;
+    }
+
+  private:
+    NoOpBaseHolder& operator=(NoOpBaseHolder const &);
+    NoOpBaseHolder(NoOpBaseHolder const &);
+};  // NoOpBaseHolder<>
+
+
+template
+    <
+        typename TYPE,
+        typename BASE,
+        UINT_PTR DEFAULTVALUE = 0,
+        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>
+    >
+class BaseHolder : protected BASE
+{
+    friend class ClrDataAccess;
+  protected:
+    BOOL    m_acquired;      // Have we acquired the resource?
+
+    static_assert(!std::is_pointer<TYPE>::value || DEFAULTVALUE == 0 || DEFAULTVALUE == UINT_PTR(-1 /*INVALID_HANDLE_VALUE*/),
+                  "DEFAULTVALUE must be NULL for pointer holders and wrappers.");
+
+  public:
+    FORCEINLINE BaseHolder()
+      : BASE(TYPE(DEFAULTVALUE)),
+        m_acquired(FALSE)
+    {
+    }
+    FORCEINLINE BaseHolder(TYPE value)
+      : BASE(value),
+        m_acquired(FALSE)
+    {
+        if (!IsNull())
+            Acquire();
+    }
+    FORCEINLINE BaseHolder(TYPE value, BOOL takeOwnership)
+      : BASE(value),
+        m_acquired(FALSE)
+    {
+        if (takeOwnership)
+            Acquire();
+    }
+    FORCEINLINE ~BaseHolder()
+    {
+        Release();
+    }
+    // Sets the value to 'value'. Doesn't call Acquire if value is DEFAULTVALUE.
+    FORCEINLINE void Assign(TYPE value)
+    {
+        Assign(value, !IS_NULL(value, TYPE(DEFAULTVALUE)));
+    }
+    // Sets the value to 'value'. Doesn't call Acquire if fTake is FALSE.
+    FORCEINLINE void Assign(TYPE value, BOOL takeOwnership)
+    {
+        Release();
+        this->m_value = value;
+        if (takeOwnership)
+            Acquire();
+    }
+    FORCEINLINE void Acquire()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        _ASSERTE(!m_acquired);
+
+        if (!IsNull())
+        {
+            this->DoAcquire();
+            m_acquired = TRUE;
+        }
+    }
+    FORCEINLINE void Release()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        if (m_acquired)
+        {
+            _ASSERTE(!IsNull());
+            this->DoRelease();
+            m_acquired = FALSE;
+        }
+    }
+
+    FORCEINLINE void Clear()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        Assign(TYPE(DEFAULTVALUE), FALSE);
+    }
+    FORCEINLINE void SuppressRelease()
+    {
+        STATIC_CONTRACT_LEAF;
+        m_acquired = FALSE;
+    }
+    FORCEINLINE TYPE Extract()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        SuppressRelease();
+        return GetValue();
+    }
+    FORCEINLINE TYPE GetValue()
+    {
+        STATIC_CONTRACT_LEAF;
+        return this->m_value;
+    }
+    FORCEINLINE BOOL IsNull() const
+    {
+        STATIC_CONTRACT_WRAPPER;
+        return IS_NULL(this->m_value, TYPE(DEFAULTVALUE));
+    }
+
+    HIDE_GENERATED_METHODS(BaseHolder)
+};  // BaseHolder<>
+
+template <void (*ACQUIRE)(), void (*RELEASEF)()>
+class StateHolder
+{
+  private:
+    BOOL    m_acquired;      // Have we acquired the state?
+
+  public:
+    FORCEINLINE StateHolder(BOOL take = TRUE)
+      : m_acquired(FALSE)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        if (take)
+            Acquire();
+    }
+    FORCEINLINE ~StateHolder()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        Release();
+    }
+    FORCEINLINE void Acquire()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        // Insert any global or thread bookeeping here
+
+        _ASSERTE(!m_acquired);
+
+        ACQUIRE();
+        m_acquired = TRUE;
+    }
+    FORCEINLINE void Release()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        // Insert any global or thread bookeeping here
+
+        if (m_acquired)
+        {
+            RELEASEF();
+            m_acquired = FALSE;
+        }
+    }
+    FORCEINLINE void Clear()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        if (m_acquired)
+        {
+            RELEASEF();
+        }
+
+        m_acquired = FALSE;
+    }
+    FORCEINLINE void SuppressRelease()
+    {
+        STATIC_CONTRACT_LEAF;
+        m_acquired = FALSE;
+    }
+
+    HIDE_GENERATED_METHODS(StateHolder)
+};  // class StateHolder<>
+
+// Holder for the case where the acquire function can fail.
+template <typename VALUE, BOOL (*ACQUIRE)(VALUE value), void (*RELEASEF)(VALUE value)>
+class ConditionalStateHolder
+{
+  private:
+    VALUE   m_value;
+    BOOL    m_acquired;      // Have we acquired the state?
+
+  public:
+    FORCEINLINE ConditionalStateHolder(VALUE value, BOOL take = TRUE)
+      : m_value(value), m_acquired(FALSE)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        if (take)
+            Acquire();
+    }
+    FORCEINLINE ~ConditionalStateHolder()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        Release();
+    }
+    FORCEINLINE BOOL Acquire()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        // Insert any global or thread bookeeping here
+
+        _ASSERTE(!m_acquired);
+
+        m_acquired = ACQUIRE(m_value);
+
+        return m_acquired;
+    }
+    FORCEINLINE void Release()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        // Insert any global or thread bookeeping here
+
+        if (m_acquired)
+        {
+            RELEASEF(m_value);
+            m_acquired = FALSE;
+        }
+    }
+    FORCEINLINE void Clear()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        if (m_acquired)
+        {
+            RELEASEF(m_value);
+        }
+
+        m_acquired = FALSE;
+    }
+    FORCEINLINE void SuppressRelease()
+    {
+        STATIC_CONTRACT_LEAF;
+        m_acquired = FALSE;
+    }
+    FORCEINLINE BOOL Acquired()
+    {
+        STATIC_CONTRACT_LEAF;
+
+        return m_acquired;
+    }
+
+    HIDE_GENERATED_METHODS(ConditionalStateHolder)
+};  // class ConditionalStateHolder<>
+
+
+// Making the copy constructor private produces a warning about "can't generate copy
+// constructor" on all holders (duh, that's the point.)
+#ifdef _MSC_VER
+#pragma warning(disable:4511)
+#endif  // _MSC_VER
+
+//-----------------------------------------------------------------------------
+// BaseWrapper is just Base like a Holder, but it "transparently" proxies the type it contains,
+// using operator overloads.  Use this when you want a holder to expose the functionality of
+// the value it contains.
+//-----------------------------------------------------------------------------
+template <typename TYPE, typename BASE,
+          UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>>
+class BaseWrapper : public BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL>
+{
+    typedef BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL> BaseT;
+
+
+#ifdef __GNUC__
+//#pragma GCC visibility push(hidden)
+#endif // __GNUC__
+    // This temporary object takes care of the case where we are initializing
+    // a holder's contents by passing it as an out parameter.  The object is
+    // guaranteed to live longer than the call it is passed to, hence we should
+    // properly acquire the object on return
+    friend class AddressInitHolder;
+    class AddressInitHolder
+    {
+      protected:
+        BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &m_holder;
+
+      public:
+        FORCEINLINE AddressInitHolder(BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &holder)
+          : m_holder(holder)
+        {
+            //
+            // We must clear the value, to avoid the following scenario:
+            //
+            //      ReleaseHolder<MyType> pMyType;
+            //      hr = MyFunction(&pMyType, ...);
+            //      <do something with pMyType>
+            //      hr = MyFunction(&pMyType, ...); <- calls Release before call and Acquire on return.
+            //
+            // If the second call to MyFunction were to fail and return without updating the
+            // out parameter, then ~AddressInitHolder will all Acquire, which is a no-op on
+            // the underlying pointer but sets m_acquired to TRUE. Thus, when pMyType goes
+            // out of scope, ReleaseHolder will cause a double-release of pMyType.
+            //
+            // By calling Clear, then the call to Acquire in the dtor will not set m_acquired
+            // to true since IsNull(m_holder.m_value) will return true.
+            //
+            m_holder.Clear();
+        }
+        FORCEINLINE ~AddressInitHolder()
+        {
+            m_holder.Acquire();
+        }
+
+        // It's not optimal to have to declare these casting operators.  But if we don't,
+        // people cannot cast the result of &holder to these values.  (The C++ compiler won't
+        // automatically use the TYPE * cast as an intermediate value.)  So we put them here,
+        // rather than forcing callers to double cast in these common cases.
+
+        FORCEINLINE operator IUnknown **()
+        {
+            IUnknown *unknown;
+            // Typesafe check.  This will fail at compile time if
+            // m_holder.m_value can't be converted to an IUnknown *.
+            unknown = static_cast<IUnknown*>(m_holder.m_value);
+            // do the cast with an unsafe cast
+            return (IUnknown **)(&m_holder.m_value);
+        }
+
+#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
+        FORCEINLINE operator IInspectable **()
+        {
+            IInspectable *inspectable;
+            // Typesafe check.  This will fail at compile time if
+            // m_holder.m_value can't be converted to an IInspectable *.
+            inspectable = static_cast<IInspectable *>(m_holder.m_value);
+            return (IInspectable **)(&m_holder.m_value);
+
+        }
+#endif // FEATURE_COMINTEROP
+
+        FORCEINLINE operator void **()
+        {
+            return (void **)(&m_holder.m_value);
+        }
+        FORCEINLINE operator void *()
+        {
+            return (void *)(&m_holder.m_value);
+        }
+    };
+
+    // Separate out method with TYPE * cast operator, since it may clash with IUnknown ** or
+    // void ** cast operator.
+    friend class TypedAddressInitHolder;
+    class TypedAddressInitHolder : public AddressInitHolder
+    {
+      public:
+        FORCEINLINE TypedAddressInitHolder(BaseWrapper & holder)
+          : AddressInitHolder(holder)
+        {
+        }
+
+        FORCEINLINE operator TYPE *()
+        {
+            return static_cast<TYPE *>(&this->m_holder.m_value);
+        }
+    };
+#ifdef __GNUC__
+//#pragma GCC visibility pop
+#endif // __GNUC__
+
+  public:
+    FORCEINLINE BaseWrapper()
+        : BaseT(TYPE(DEFAULTVALUE), FALSE)
+    {
+    }
+    FORCEINLINE BaseWrapper(TYPE value)
+        : BaseT(value)
+    {
+    }
+    FORCEINLINE BaseWrapper(TYPE value, BOOL take)
+        : BaseT(value, take)
+    {
+    }
+    FORCEINLINE BaseWrapper& operator=(TYPE value)
+    {
+        BaseT::Assign(value);
+        return *this;
+    }
+    FORCEINLINE operator TYPE() const
+    {
+        return this->m_value;
+    }
+    FORCEINLINE TypedAddressInitHolder operator&()
+    {
+        return TypedAddressInitHolder(*this);
+    }
+    template <typename T>
+    FORCEINLINE bool operator==(T const & value) const
+    {
+        return !!(this->m_value == TYPE(value));
+    }
+    template <typename T>
+    FORCEINLINE bool operator!=(T const & value) const
+    {
+        return !!(this->m_value != TYPE(value));
+    }
+
+    // This handles the NULL value that is an int and the
+    // compiler doesn't want to convert int to a pointer.
+    FORCEINLINE bool operator==(int value) const
+    {
+        return !!(this->m_value == TYPE((void*)(SIZE_T)value));
+    }
+    FORCEINLINE bool operator!=(int value) const
+    {
+        return !!(this->m_value != TYPE((void*)(SIZE_T)value));
+    }
+
+    FORCEINLINE const TYPE &operator->() const
+    {
+        return this->m_value;
+    }
+    FORCEINLINE int operator!() const
+    {
+        return this->IsNull();
+    }
+
+  private:
+    HIDE_GENERATED_METHODS(BaseWrapper)
+};  // class BaseWrapper<>
+
+//-----------------------------------------------------------------------------
+// Generic templates to use to wrap up acquire/release functionality for Holder
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void DoNothing(TYPE value)
+{
+    // @TODO: Due to prefast template problems, implementations of the DoNothing macro have been changed
+    // Search by prefast, and remove them when prefast is ready
+}
+
+FORCEINLINE void DoNothing()
+{
+}
+
+// Prefast stuff.We should have DoNothing<type*> in the holder declaration, but currently
+// prefast doesnt support, it, so im stuffing all these here so if we need to change the template you can change
+// everything here. When prefast works, remove the following functions
+struct ConnectionCookie;
+FORCEINLINE void ConnectionCookieDoNothing(ConnectionCookie* p)
+{
+}
+
+class ComCallWrapper;
+FORCEINLINE void CCWHolderDoNothing(ComCallWrapper* p)
+{
+}
+
+
+FORCEINLINE void DispParamHolderDoNothing(VARIANT* p)
+{
+}
+
+FORCEINLINE void VariantPtrDoNothing(VARIANT* p)
+{
+}
+
+FORCEINLINE void VariantDoNothing(VARIANT)
+{
+}
+
+FORCEINLINE void ZeroDoNothing(VOID* p)
+{
+}
+
+class CtxEntry;
+FORCEINLINE void CtxEntryDoNothing(CtxEntry* p)
+{
+}
+
+struct RCW;
+FORCEINLINE void NewRCWHolderDoNothing(RCW*)
+{
+}
+
+// Prefast stuff.We should have DoNothing<SafeArray*> in the holder declaration
+FORCEINLINE void SafeArrayDoNothing(SAFEARRAY* p)
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Holder/Wrapper are the simplest way to define holders - they synthesizes a base class out of
+// function pointers
+//-----------------------------------------------------------------------------
+
+template <typename TYPE, void (*ACQUIREF)(TYPE), void (*RELEASEF)(TYPE)>
+class FunctionBase : protected HolderBase<TYPE>
+{
+    friend class ClrDataAccess;
+  protected:
+
+    FORCEINLINE FunctionBase(TYPE value)
+      : HolderBase<TYPE>(value)
+    {
+    }
+
+    FORCEINLINE void DoAcquire()
+    {
+        ACQUIREF(this->m_value);
+    }
+
+    void DoRelease()
+    {
+        RELEASEF(this->m_value);
+    }
+};  // class Function<>
+
+template
+    <
+        typename TYPE,
+        void (*ACQUIREF)(TYPE),
+        void (*RELEASEF)(TYPE),
+        UINT_PTR DEFAULTVALUE = 0,
+        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
+        // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
+        // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
+        // operates on static or global value instead.
+        bool DEFAULT_CTOR_ACQUIRE = true
+    >
+class Holder : public BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF>,
+                                 DEFAULTVALUE, IS_NULL>
+{
+    typedef BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF>,
+                                 DEFAULTVALUE, IS_NULL> BaseT;
+
+  public:
+    FORCEINLINE Holder()
+        : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
+    {
+        STATIC_CONTRACT_WRAPPER;
+    }
+
+    FORCEINLINE Holder(TYPE value)
+        : BaseT(value)
+    {
+        STATIC_CONTRACT_WRAPPER;
+    }
+
+    FORCEINLINE Holder(TYPE value, BOOL takeOwnership)
+        : BaseT(value, takeOwnership)
+    {
+        STATIC_CONTRACT_WRAPPER;
+    }
+
+    FORCEINLINE Holder& operator=(TYPE p)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        BaseT::operator=(p);
+        return *this;
+    }
+
+    HIDE_GENERATED_METHODS(Holder)
+};
+
+//---------------------------------------------------------------------------------------
+//
+template
+    <
+        typename TYPE,
+        void (*ACQUIREF)(TYPE),
+        void (*RELEASEF)(TYPE),
+        UINT_PTR DEFAULTVALUE = 0,
+        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
+        // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
+        // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
+        // operates on static or global value instead.
+        bool DEFAULT_CTOR_ACQUIRE = true
+    >
+class Wrapper : public BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF>,
+                                   DEFAULTVALUE, IS_NULL>
+{
+    typedef BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF>,
+                                   DEFAULTVALUE, IS_NULL> BaseT;
+
+  public:
+    FORCEINLINE Wrapper()
+        : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
+    {
+        STATIC_CONTRACT_WRAPPER;
+    }
+
+    FORCEINLINE Wrapper(TYPE value)
+        : BaseT(value)
+    {
+        STATIC_CONTRACT_WRAPPER;
+    }
+
+    FORCEINLINE Wrapper(TYPE value, BOOL takeOwnership)
+        : BaseT(value, takeOwnership)
+    {
+        STATIC_CONTRACT_WRAPPER;
+    }
+
+    FORCEINLINE Wrapper& operator=(TYPE const & value)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        BaseT::operator=(value);
+        return *this;
+    }
+
+    HIDE_GENERATED_METHODS(Wrapper)
+};  // Wrapper<>
+
+//---------------------------------------------------------------------------------------
+// - Cannot use the standard INDEBUG macro: holder.h is used in places where INDEBUG is defined in the nonstandard way
+#if defined(_DEBUG)
+#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x) x
+#else
+#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x)
+#endif
+
+template <typename _TYPE, void (*_RELEASEF)(_TYPE*)>
+class SpecializedWrapper : public Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL>
+{
+    using BaseT = Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL>;
+public:
+    FORCEINLINE SpecializedWrapper() : BaseT(NULL, FALSE)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)
+    }
+    FORCEINLINE SpecializedWrapper(_TYPE* value) : BaseT(value)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)
+    }
+    FORCEINLINE SpecializedWrapper(_TYPE* value, BOOL takeOwnership) : BaseT(value, takeOwnership)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)
+    }
+    FORCEINLINE ~SpecializedWrapper()
+    {
+    }
+
+    SpecializedWrapper(SpecializedWrapper const &) = delete;
+    SpecializedWrapper & operator=(SpecializedWrapper const &) = delete;
+
+    FORCEINLINE SpecializedWrapper& operator=(_TYPE * value)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        BaseT::operator=(value);
+        return *this;
+    }
+
+    FORCEINLINE SpecializedWrapper(SpecializedWrapper && other)
+    : BaseT(NULL, FALSE)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)
+        *this = std::move(other);
+    }
+
+    FORCEINLINE SpecializedWrapper& operator=(SpecializedWrapper && other)
+    {
+        BaseT::m_value = std::move(other.BaseT::m_value);
+        BaseT::m_acquired = std::move(other.BaseT::m_acquired);
+        other.BaseT::m_value = nullptr;
+        other.BaseT::m_acquired = FALSE;
+        return *this;
+    }
+
+    /* Since operator& is overloaded we need a way to get a type safe this pointer. */
+    FORCEINLINE SpecializedWrapper* GetAddr()
+    {
+        STATIC_CONTRACT_LEAF;
+        return this;
+    }
+    private:
+    /* m_ppValue: Do not use from source code: Only for convenient use from debugger */
+    /*     watch windows - saves five mouseclicks when inspecting holders. */
+    INDEBUG_AND_WINDOWS_FOR_HOLDERS(_TYPE ** m_pvalue;)
+};
+
+//-----------------------------------------------------------------------------
+// NOTE: THIS IS UNSAFE TO USE IN THE VM for interop COM objects!!
+//  WE DO NOT CORRECTLY CHANGE TO PREEMPTIVE MODE BEFORE CALLING RELEASE!!
+//  USE SafeComHolder
+//
+// ReleaseHolder : COM Interface holder for use outside the VM (or on well known instances
+//                  which do not need preemptive Relesae)
+//
+// Usage example:
+//
+//  {
+//      ReleaseHolder<IFoo> foo;
+//      hr = FunctionToGetRefOfFoo(&foo);
+//      // Note ComHolder doesn't call AddRef - it assumes you already have a ref (if non-0).
+//  } // foo->Release() on out of scope (WITHOUT RESPECT FOR GC MODE!!)
+//
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void DoTheRelease(TYPE *value)
+{
+    if (value)
+    {
+        value->Release();
+    }
+}
+
+template<typename _TYPE>
+using DoNothingHolder = SpecializedWrapper<_TYPE, DoNothing<_TYPE*>>;
+
+template<typename _TYPE>
+using ReleaseHolder = SpecializedWrapper<_TYPE, DoTheRelease<_TYPE>>;
+
+template<typename _TYPE>
+using NonVMComHolder = SpecializedWrapper<_TYPE, DoTheRelease<_TYPE>>;
+
+
+//-----------------------------------------------------------------------------
+// StubHolder : holder for stubs
+//
+// Usage example:
+//
+//  {
+//      StubHolder<Stub> foo;
+//      foo = new Stub();
+//      foo->AddRef();
+//      // Note StubHolder doesn't call AddRef for you.
+//  } // foo->DecRef() on out of scope
+//
+//-----------------------------------------------------------------------------
+template<typename _TYPE>
+class ExecutableWriterHolder;
+
+template <typename TYPE>
+FORCEINLINE void StubRelease(TYPE* value)
+{
+    if (value)
+    {
+        ExecutableWriterHolder<TYPE> stubWriterHolder(value, sizeof(TYPE));
+        stubWriterHolder.GetRW()->DecRef();
+    }
+}
+
+template<typename _TYPE>
+using StubHolder = SpecializedWrapper<_TYPE, StubRelease<_TYPE>>;
+
+//-----------------------------------------------------------------------------
+// CoTaskMemHolder : CoTaskMemAlloc allocated memory holder
+//
+//  {
+//      CoTaskMemHolder<Foo> foo = (Foo*) CoTaskMemAlloc(sizeof(Foo));
+//  } // delete foo on out of scope
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void DeleteCoTaskMem(TYPE *value)
+{
+    if (value)
+        CoTaskMemFree(value);
+}
+
+template<typename _TYPE>
+using CoTaskMemHolder = SpecializedWrapper<_TYPE, DeleteCoTaskMem<_TYPE>>;
+
+//-----------------------------------------------------------------------------
+// NewHolder : New'ed memory holder
+//
+//  {
+//      NewHolder<Foo> foo = new Foo ();
+//  } // delete foo on out of scope
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void Delete(TYPE *value)
+{
+    STATIC_CONTRACT_LEAF;
+
+    static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, WCHAR>::value,
+                  "Must use NewArrayHolder (not NewHolder) for strings.");
+    static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, CHAR>::value,
+                  "Must use NewArrayHolder (not NewHolder) for strings.");
+
+    delete value;
+}
+
+template<typename _TYPE>
+using NewHolder = SpecializedWrapper<_TYPE, Delete<_TYPE>>;
+
+ //-----------------------------------------------------------------------------
+// NewExecutableHolder : New'ed memory holder for executable memory.
+//
+//  {
+//      NewExecutableHolder<Foo> foo = (Foo*) new (executable) Byte[num];
+//  } // delete foo on out of scope
+//-----------------------------------------------------------------------------
+// IJW
+template<class T> void DeleteExecutable(T *p);
+
+template<typename _TYPE>
+using NewExecutableHolder = SpecializedWrapper<_TYPE, DeleteExecutable<_TYPE>>;
+
+//-----------------------------------------------------------------------------
+// NewArrayHolder : New []'ed pointer holder
+//  {
+//      NewArrayHolder<Foo> foo = new Foo [30];
+//  } // delete [] foo on out of scope
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void DeleteArray(TYPE *value)
+{
+    STATIC_CONTRACT_WRAPPER;
+    delete [] value;
+    value = NULL;
+}
+
+template<typename _TYPE>
+using NewArrayHolder = SpecializedWrapper<_TYPE, DeleteArray<_TYPE>>;
+typedef NewArrayHolder<CHAR>  AStringHolder;
+typedef NewArrayHolder<WCHAR> WStringHolder;
+
+//-----------------------------------------------------------------------------
+// A special array holder that expects its contents are interface pointers,
+// and will call Release() on them.
+//
+// NOTE: You may ONLY use this if you've determined that it is SAFE to call
+// Release() on the contained interface pointers (e.g., as opposed to SafeRelease)
+//
+template <typename INTERFACE>
+class NewInterfaceArrayHolder : public NewArrayHolder<INTERFACE *>
+{
+public:
+    NewInterfaceArrayHolder() :
+        NewArrayHolder<INTERFACE *>(),
+        m_cElements(0)
+    {
+        STATIC_CONTRACT_WRAPPER;
+    }
+
+    NewInterfaceArrayHolder& operator=(INTERFACE ** value)
+    {
+        STATIC_CONTRACT_WRAPPER;
+        NewArrayHolder<INTERFACE *>::operator=(value);
+        return *this;
+    }
+
+    void SetElementCount(ULONG32 cElements)
+    {
+        STATIC_CONTRACT_LEAF;
+        m_cElements = cElements;
+    }
+
+    ~NewInterfaceArrayHolder()
+    {
+        STATIC_CONTRACT_LEAF;
+        for (ULONG32 i=0; i < m_cElements; i++)
+        {
+            if (this->m_value[i] != NULL)
+                this->m_value[i]->Release();
+        }
+    }
+
+protected:
+    ULONG32 m_cElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// ResetPointerHolder : pointer which needs to be set to NULL
+//  {
+//      ResetPointerHolder<Foo> holder = &pFoo;
+//  } // "*pFoo=NULL" on out of scope
+//-----------------------------------------------------------------------------
+#ifdef __GNUC__
+// With -fvisibility-inlines-hidden, the Invoke methods below
+// get hidden, which causes warnings when visible classes expose them.
+#define VISIBLE __attribute__ ((visibility("default")))
+#else
+#define VISIBLE
+#endif // __GNUC__
+
+namespace detail
+{
+    template <typename T>
+    struct ZeroMem
+    {
+        static VISIBLE void Invoke(T * pVal)
+        {
+            ZeroMemory(pVal, sizeof(T));
+        }
+    };
+
+    template <typename T>
+    struct ZeroMem<T*>
+    {
+        static VISIBLE void Invoke(T ** pVal)
+        {
+            *pVal = NULL;
+        }
+    };
+
+}
+#undef VISIBLE
+
+template<typename _TYPE>
+using ResetPointerHolder = SpecializedWrapper<_TYPE, detail::ZeroMem<_TYPE>::Invoke>;
+template<typename _TYPE>
+using FieldNuller = SpecializedWrapper<_TYPE, detail::ZeroMem<_TYPE>::Invoke>;
+
+//-----------------------------------------------------------------------------
+// Wrap win32 functions using HANDLE
+//-----------------------------------------------------------------------------
+
+FORCEINLINE void VoidCloseHandle(HANDLE h) { if (h != NULL) CloseHandle(h); }
+// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
+FORCEINLINE void VoidCloseFileHandle(HANDLE h) { if (h != ((HANDLE)((LONG_PTR) -1))) CloseHandle(h); }
+FORCEINLINE void VoidFindClose(HANDLE h) { FindClose(h); }
+FORCEINLINE void VoidUnmapViewOfFile(void *ptr) { UnmapViewOfFile(ptr); }
+
+template <typename TYPE>
+FORCEINLINE void TypeUnmapViewOfFile(TYPE *ptr) { UnmapViewOfFile(ptr); }
+
+// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
+//@TODO: Dangerous default value. Some Win32 functions return INVALID_HANDLE_VALUE, some return NULL (such as CreatEvent).
+typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseHandle, (UINT_PTR) -1> HandleHolder;
+typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseFileHandle, (UINT_PTR) -1> FileHandleHolder;
+typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidFindClose, (UINT_PTR) -1> FindHandleHolder;
+
+typedef Wrapper<void *, DoNothing, VoidUnmapViewOfFile> MapViewHolder;
+
+#ifdef WszDeleteFile
+// Deletes a file with the specified path.  Do not use if you care about failures
+// deleting the file, as failures are ignored by VoidDeleteFile.
+FORCEINLINE void VoidDeleteFile(LPCWSTR wszFilePath) { WszDeleteFile(wszFilePath); }
+typedef Wrapper<LPCWSTR, DoNothing<LPCWSTR>, VoidDeleteFile, NULL> DeleteFileHolder;
+#endif // WszDeleteFile
+
+
+//-----------------------------------------------------------------------------
+// Misc holders
+//-----------------------------------------------------------------------------
+
+// A holder for HMODULE.
+FORCEINLINE void HolderFreeLibrary(HMODULE h) { FreeLibrary(h); }
+
+typedef Wrapper<HMODULE, DoNothing<HMODULE>, HolderFreeLibrary, NULL> HModuleHolder;
+
+template <typename T> FORCEINLINE
+void DoLocalFree(T* pMem)
+{
+#ifdef HOST_WINDOWS
+    (LocalFree)((void*)pMem);
+#else
+    (free)((void*)pMem);
+#endif
+}
+
+template<typename _TYPE>
+using LocalAllocHolder = SpecializedWrapper<_TYPE, DoLocalFree<_TYPE>>;
+
+inline void BoolSet( _Out_ bool * val ) { *val = true; }
+inline void BoolUnset( _Out_ bool * val ) { *val = false; }
+
+typedef Wrapper< bool *, BoolSet, BoolUnset > BoolFlagStateHolder;
+
+//
+// We need the following methods to have volatile arguments, so that they can accept
+// raw pointers in addition to the results of the & operator on Volatile<T>.
+//
+
+FORCEINLINE void CounterIncrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedIncrement(p);};
+FORCEINLINE void CounterDecrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedDecrement(p);};
+
+typedef Wrapper<RAW_KEYWORD(volatile) LONG*, CounterIncrease, CounterDecrease, (UINT_PTR)0, CompareDefault<RAW_KEYWORD(volatile) LONG*>> CounterHolder;
+
+
+#ifdef HOST_WINDOWS
+FORCEINLINE void RegKeyRelease(HKEY k) {RegCloseKey(k);};
+typedef Wrapper<HKEY,DoNothing,RegKeyRelease> RegKeyHolder;
+#endif // HOST_WINDOWS
+
+class ErrorModeHolder
+{
+    UINT m_oldMode;
+public:
+    ErrorModeHolder(UINT newMode){m_oldMode=SetErrorMode(newMode);};
+    ~ErrorModeHolder(){SetErrorMode(m_oldMode);};
+    UINT OldMode() {return m_oldMode;};
+};
+
+#ifdef HOST_WINDOWS
+//-----------------------------------------------------------------------------
+// HKEYHolder : HKEY holder, Calls RegCloseKey on scope exit.
+//
+//  {
+//      HKEYHolder hFoo = NULL;
+//      WszRegOpenKeyEx(HKEY_CLASSES_ROOT, L"Interface",0, KEY_READ, hFoo);
+//
+//  } // close key on out of scope via RegCloseKey.
+//-----------------------------------------------------------------------------
+
+class HKEYHolder
+{
+public:
+    HKEYHolder()
+    {
+        STATIC_CONTRACT_LEAF;
+        m_value = 0;
+    }
+
+    ~HKEYHolder()
+    {
+        STATIC_CONTRACT_WRAPPER;
+        if (m_value != NULL)
+            ::RegCloseKey(m_value);
+    }
+
+    FORCEINLINE void operator=(HKEY p)
+    {
+        STATIC_CONTRACT_LEAF;
+        if (p != 0)
+            m_value = p;
+    }
+
+    FORCEINLINE operator HKEY()
+    {
+        STATIC_CONTRACT_LEAF;
+        return m_value;
+    }
+
+    FORCEINLINE operator HKEY*()
+    {
+        STATIC_CONTRACT_LEAF;
+        return &m_value;
+    }
+
+    FORCEINLINE HKEY* operator&()
+    {
+        STATIC_CONTRACT_LEAF;
+        return &m_value;
+    }
+
+private:
+    HKEY m_value;
+};
+#endif // HOST_WINDOWS
+
+//----------------------------------------------------------------------------
+//
+// External data access does not want certain holder implementations
+// to be active as locks should not be taken and so on.  Provide
+// a no-op in that case.
+//
+//----------------------------------------------------------------------------
+
+#ifndef DACCESS_COMPILE
+
+#define DacHolder Holder
+
+#else
+
+template <typename TYPE, void (*ACQUIRE)(TYPE), void (*RELEASEF)(TYPE), UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, BOOL VALIDATE_BACKOUT_STACK = TRUE>
+class DacHolder
+{
+  protected:
+    TYPE    m_value;
+
+  private:
+    BOOL    m_acquired;      // Have we acquired the resource?
+
+  public:
+    FORCEINLINE DacHolder()
+      : m_value(TYPE(DEFAULTVALUE)),
+        m_acquired(FALSE)
+    {
+        STATIC_CONTRACT_SUPPORTS_DAC;
+    }
+
+    // construct a new instance of DacHolder
+    // Arguments:
+    //     input:  value - the resource held
+    //             take  - indicates whether the lock should be taken--the default is true. See Notes:
+    // Note: In DAC builds, the Acquire function does not actually take the lock, instead
+    //       it determines whether the lock is held (by the LS). If it is, the locked data
+    //       is assumed to be inconsistent and the Acquire function will throw.
+    FORCEINLINE DacHolder(TYPE value, BOOL take = TRUE)
+      : m_value(value),
+        m_acquired(FALSE)
+    {
+        STATIC_CONTRACT_SUPPORTS_DAC;
+        if (take)
+            Acquire();
+
+    }
+    FORCEINLINE ~DacHolder()
+    {
+        STATIC_CONTRACT_SUPPORTS_DAC;
+    }
+    // Sets the value to 'value'. Doesn't call Acquire/Release if fTake is FALSE.
+    FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
+    {
+        m_value = value;
+    }
+    FORCEINLINE void Acquire()
+    {
+        STATIC_CONTRACT_SUPPORTS_DAC;
+
+        if (!IsNull())
+        {
+            m_acquired = TRUE;
+            // because ACQUIRE is a template argument, if the line m_acquired = TRUE is placed after the call
+            // where it logically belongs, the compiler flags it as "unreachable code."
+            ACQUIRE(this->m_value);
+        }
+    }
+    FORCEINLINE void Release()
+    {
+        // Insert any global or thread bookeeping here
+
+        if (m_acquired)
+        {
+            m_acquired = FALSE;
+        }
+    }
+    FORCEINLINE void Clear()
+    {
+        m_value = TYPE(DEFAULTVALUE);
+        m_acquired = FALSE;
+    }
+    FORCEINLINE void SuppressRelease()
+    {
+        m_acquired = FALSE;
+    }
+    FORCEINLINE TYPE GetValue()
+    {
+        return m_value;
+    }
+    FORCEINLINE BOOL IsNull() const
+    {
+        return IS_NULL(m_value, TYPE(DEFAULTVALUE));
+    }
+
+  private:
+    FORCEINLINE DacHolder& operator=(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
+    {
+    }
+
+    FORCEINLINE DacHolder(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
+    {
+    }
+};
+
+#endif // #ifndef DACCESS_COMPILE
+
+// Holder-specific clr::SafeAddRef and clr::SafeRelease helper functions.
+namespace clr
+{
+    // Copied from utilcode.h. We can't include the header directly because there
+    // is circular reference.
+    // Forward declare the overload which is used by 'SafeAddRef' below.
+    template <typename ItfT>
+    static inline
+    typename std::enable_if< std::is_pointer<ItfT>::value, ItfT >::type
+    SafeAddRef(ItfT pItf);
+
+    template < typename ItfT > __checkReturn
+    ItfT *
+    SafeAddRef(ReleaseHolder<ItfT> & pItf)
+    {
+        STATIC_CONTRACT_LIMITED_METHOD;
+        //@TODO: Would be good to add runtime validation that the return value is used.
+        return SafeAddRef(pItf.GetValue());
+    }
+
+    namespace detail
+    {
+        template <typename T>
+        char IsHolderHelper(HolderBase<T>*);
+        int  IsHolderHelper(...);
+
+        template <typename T>
+        struct IsHolder : public std::conditional<
+            sizeof(IsHolderHelper(reinterpret_cast<T*>(NULL))) == sizeof(char),
+            std::true_type,
+            std::false_type>::type
+        {};
+    }
+
+    template < typename T >
+    typename std::enable_if<detail::IsHolder<T>::value, ULONG>::type
+    SafeRelease(T& arg)
+    {
+        STATIC_CONTRACT_LIMITED_METHOD;
+        return arg.Release();
+    }
+}
+
+#endif  // __HOLDER_H_
diff --git a/src/inc/iterator.h b/src/inc/iterator.h
new file mode 100644 (file)
index 0000000..b7bb142
--- /dev/null
@@ -0,0 +1,640 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// Iterator.h
+// ---------------------------------------------------------------------------
+
+// ================================================================================
+// Iterator pattern:
+//
+// This pattern is similar to the STL iterator pattern.  It basically consists of
+// wrapping an "iteration variable" in an object, and providing pointer-like operators
+// on the iterator. Example usage:
+//
+// for (Iterator start = foo->Begin(), end = foo->End(); start != end; start++)
+// {
+//      // use foo, start
+// }
+//
+// There are 3 levels of iterator functionality
+//      1. Enumerator (STL forward) - only go forward one at a time
+//          Enumerators have the following operations:
+//              operator * : access current element as ref
+//              operator -> : access current element as ptr
+//              operator++ : go to the next element
+//              operator==, operator!= : compare to another enumerator
+//
+//
+//      2. Scanner (STL bidirectional) - backward or forward one at a time
+//          Scanners have all the functionality of enumerators, plus:
+//              operator-- : go backward one element
+//
+//      3. Indexer (STL random access)  - skip around arbitrarily
+//          Indexers have all the functionality of scanners, plus:
+//              operator[] : access the element at index from iterator as ref
+//              operator+= : advance iterator by index
+//              operator+ : return new iterator at index from iterator
+//              operator-= : rewind iterator by index
+//              operator- : return new iterator at index back from iterator
+//              operator <, operator <=, operator >, operator>= :
+//                  range comparison on two indexers
+//
+// The object being iterated should define the following methods:
+//      Begin()             return an iterator starting at the first element
+//      End()               return an iterator just past the last element
+//
+// Iterator types are normally defined as member types named "Iterator", no matter
+// what their functionality level is.
+// ================================================================================
+
+
+#ifndef ITERATOR_H_
+#define ITERATOR_H_
+
+#include "contract.h"
+
+namespace HIDDEN {
+// These prototypes are not for direct use - they are only here to illustrate the
+// iterator pattern
+
+template <typename CONTAINER, typename ELEMENT>
+class ScannerPrototype
+{
+  public:
+
+    typedef ScannerPrototype<CONTAINER, ELEMENT> Iterator;
+
+    ELEMENT &operator*();
+    ELEMENT *operator->();
+
+    Iterator &operator++();
+    Iterator operator++(int);
+    Iterator &operator--();
+    Iterator operator--(int);
+
+    bool operator==(const Iterator &i);
+    bool operator!=(const Iterator &i);
+};
+
+template <typename CONTAINER, typename ELEMENT>
+class EnumeratorPrototype
+{
+  public:
+
+    typedef EnumeratorPrototype<CONTAINER, ELEMENT> Iterator;
+
+    ELEMENT &operator*();
+    ELEMENT *operator->();
+
+    Iterator &operator++();
+    Iterator operator++(int);
+
+    bool operator==(const Iterator &i);
+    bool operator!=(const Iterator &i);
+};
+
+template <typename CONTAINER, typename ELEMENT>
+class IndexerPrototype
+{
+  public:
+    typedef IndexerPrototype<CONTAINER, ELEMENT> Iterator;
+
+    ELEMENT &operator*();
+    ELEMENT *operator->();
+    ELEMENT &operator[](int index);
+
+    Iterator &operator++();
+    Iterator operator++(int);
+    Iterator &operator--();
+    Iterator operator--(int);
+
+    Iterator &operator+=(SCOUNT_T index);
+    Iterator &operator-=(SCOUNT_T index);
+
+    Iterator operator+(SCOUNT_T index);
+    Iterator operator-(SCOUNT_T index);
+
+    SCOUNT_T operator-(Iterator &i);
+
+    bool operator==(const Iterator &i);
+    bool operator!=(const Iterator &i);
+    bool operator<(const Iterator &i);
+    bool operator<=(const Iterator &i);
+    bool operator>(const Iterator &i);
+    bool operator>=(const Iterator &i);
+};
+
+template <typename ELEMENT>
+class EnumerablePrototype
+{
+    typedef EnumeratorPrototype<EnumerablePrototype, ELEMENT> Iterator;
+
+    Iterator Begin();
+    Iterator End();
+};
+
+template <typename ELEMENT>
+class ScannablePrototype
+{
+    typedef ScannerPrototype<ScannablePrototype, ELEMENT> Iterator;
+
+    Iterator Begin();
+    Iterator End();
+};
+
+template <typename ELEMENT>
+class IndexablePrototype
+{
+    typedef IndexerPrototype<IndexablePrototype, ELEMENT> Iterator;
+
+    Iterator Begin();
+    Iterator End();
+};
+
+};
+
+// --------------------------------------------------------------------------------
+// EnumeratorBase, ScannerBase, and IndexerBase are abstract classes
+// describing basic operations for iterator functionality at the different levels.
+//
+// You
+// 1. Use the classes as a pattern (don't derive from them), and plug in your own
+//      class into the Enumerator/Scanner/Indexer templates below.
+// 2. Subclass the AbstractEnumerator/AbstractScanner/AbstractIndexer classes
+// --------------------------------------------------------------------------------
+
+namespace HIDDEN
+{
+// These prototypes are not for direct use - they are only here to illustrate the
+// pattern of the BASE class for the Iterator templates
+
+template <typename ELEMENT, typename CONTAINER>
+class EnumeratorBasePrototype
+{
+  protected:
+    EnumeratorBasePrototype(CONTAINER *container, BOOL begin);
+    ELEMENT &Get() const;
+    void Next();
+    BOOL Equal(const EnumeratorBasePrototype &i) const;
+    CHECK DoCheck() const;
+};
+
+template <typename ELEMENT, typename CONTAINER>
+class ScannerBasePrototype
+{
+ protected:
+    ScannerBasePrototype(CONTAINER *container, BOOL begin);
+    ELEMENT &Get() const;
+    void Next();
+    void Previous();
+    BOOL Equal(const ScannerBasePrototype &i) const;
+    CHECK DoCheck() const;
+};
+
+template <typename ELEMENT, typename CONTAINER>
+class IndexerBasePrototype
+{
+ protected:
+    IndexerBasePrototype(CONTAINER *container, SCOUNT_T delta);
+    ELEMENT &GetAt(SCOUNT_T delta) const;
+    void Skip(SCOUNT_T delta);
+    SCOUNT_T Subtract(const IndexerBasePrototype &i) const;
+    CHECK DoCheck(SCOUNT_T delta) const;
+};
+
+};
+
+
+template <typename CONTAINER>
+class CheckedIteratorBase
+{
+  protected:
+#if defined(_DEBUG)
+    const CONTAINER *m_container;
+    int m_revision;
+#endif
+
+    CHECK CheckRevision() const
+    {
+        LIMITED_METHOD_CONTRACT;
+        SUPPORTS_DAC;
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__llvm__))
+        __if_exists(CONTAINER::m_revision)
+        {
+            CHECK_MSG(m_revision == m_container->m_revision,
+                      "Use of Iterator after container has been modified");
+        }
+#endif
+        CHECK_OK;
+    }
+
+    CheckedIteratorBase()
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+#if defined(_DEBUG)
+        m_container = NULL;
+#endif
+    }
+
+    CheckedIteratorBase(const CONTAINER *container)
+    {
+        LIMITED_METHOD_CONTRACT;
+#if defined(_DEBUG)
+        m_container = container;
+#if defined(_MSC_VER) || defined(__llvm__)
+        __if_exists(CONTAINER::m_revision)
+        {
+            m_revision = m_container->m_revision;
+        }
+#endif
+#endif
+    }
+
+    void Resync(const CONTAINER *container)
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__llvm__))
+        __if_exists(CONTAINER::m_revision)
+        {
+            m_revision = m_container->m_revision;
+        }
+#endif
+    }
+
+#if defined(_DEBUG)
+    const CONTAINER *GetContainerDebug() const
+    {
+        LIMITED_METHOD_CONTRACT;
+        return m_container;
+    }
+#endif
+
+  public:
+    CHECK Check() const
+    {
+        WRAPPER_NO_CONTRACT;
+        SUPPORTS_DAC;
+        CHECK(CheckRevision());
+        CHECK_OK;
+    }
+
+    CHECK CheckContainer(const CONTAINER *container) const
+    {
+        WRAPPER_NO_CONTRACT;
+#if defined(_DEBUG)
+        CHECK(container == m_container);
+#endif
+        CHECK_OK;
+    }
+
+};
+
+
+// --------------------------------------------------------------------------------
+// Enumerator, Scanner, and Indexer provide a template to produce an iterator
+// on an existing class with a single iteration variable.
+//
+// The template takes 3 type parameters:
+// CONTAINER - type of object being interated on
+// ELEMENT - type of iteration
+// BASE - base type of the iteration.  This type must follow the pattern described
+//      by the above Prototypes
+// --------------------------------------------------------------------------------
+
+template <typename ELEMENT, typename SUBTYPE>
+class Enumerator
+{
+ private:
+    const SUBTYPE *This() const
+    {
+        return (const SUBTYPE *) this;
+    }
+
+    SUBTYPE *This()
+    {
+        return (SUBTYPE *)this;
+    }
+
+  public:
+
+    Enumerator()
+    {
+    }
+
+    CHECK CheckIndex() const
+    {
+#if defined(_DEBUG)
+        CHECK(This()->DoCheck());
+#endif
+        CHECK_OK;
+    }
+
+    ELEMENT &operator*() const
+    {
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(This()->CheckIndex());
+
+        return This()->Get();
+    }
+    ELEMENT *operator->() const
+    {
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(This()->CheckIndex());
+
+        return &(This()->Get());
+    }
+    SUBTYPE &operator++()
+    {
+        PRECONDITION(CheckPointer(This()));
+
+        This()->Next();
+        return *This();
+    }
+    SUBTYPE operator++(int)
+    {
+        PRECONDITION(CheckPointer(This()));
+
+        SUBTYPE i = *This();
+        This()->Next();
+        return i;
+    }
+    bool operator==(const SUBTYPE &i) const
+    {
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+
+        return This()->Equal(i);
+    }
+    bool operator!=(const SUBTYPE &i) const
+    {
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+
+        return !This()->Equal(i);
+    }
+};
+
+template <typename ELEMENT, typename SUBTYPE>
+class Scanner
+{
+ private:
+    const SUBTYPE *This() const
+    {
+        return (const SUBTYPE *)this;
+    }
+
+    SUBTYPE *This()
+    {
+        return (SUBTYPE *)this;
+    }
+
+  public:
+
+    Scanner()
+    {
+    }
+
+    CHECK CheckIndex() const
+    {
+#if defined(_DEBUG)
+        CHECK(This()->DoCheck());
+#endif
+        CHECK_OK;
+    }
+
+    ELEMENT &operator*() const
+    {
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(This()->CheckIndex());
+
+        return This()->Get();
+    }
+    ELEMENT *operator->() const
+    {
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(This()->CheckIndex());
+
+        return &This()->Get();
+    }
+    SUBTYPE &operator++()
+    {
+        PRECONDITION(CheckPointer(This()));
+
+        This()->Next();
+        return *This();
+    }
+    SUBTYPE operator++(int)
+    {
+        PRECONDITION(CheckPointer(This()));
+
+        SUBTYPE i = *This();
+        This()->Next();
+        return i;
+    }
+    SUBTYPE &operator--()
+    {
+        PRECONDITION(CheckPointer(This()));
+
+        This()->Previous();
+        return *This();
+    }
+    SUBTYPE operator--(int)
+    {
+        PRECONDITION(CheckPointer(this));
+
+        SUBTYPE i = *This();
+        This()->Previous();
+        return i;
+    }
+    bool operator==(const SUBTYPE &i) const
+    {
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+
+        return This()->Equal(i);
+    }
+    bool operator!=(const SUBTYPE &i) const
+    {
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+
+        return !This()->Equal(i);
+    }
+};
+
+template <typename ELEMENT, typename SUBTYPE>
+class Indexer
+{
+ private:
+    const SUBTYPE *This() const
+    {
+        return (const SUBTYPE *)this;
+    }
+
+    SUBTYPE *This()
+    {
+        return (SUBTYPE *)this;
+    }
+
+  public:
+
+    Indexer()
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+    }
+
+    CHECK CheckIndex() const
+    {
+#if defined(_DEBUG)
+        CHECK(This()->DoCheck(0));
+#endif
+        CHECK_OK;
+    }
+
+    CHECK CheckIndex(int index) const
+    {
+#if defined(_DEBUG)
+        CHECK(This()->DoCheck(index));
+#endif
+        CHECK_OK;
+    }
+
+    ELEMENT &operator*() const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(This()->CheckIndex(0));
+
+        return *(ELEMENT*)&This()->GetAt(0);
+    }
+    ELEMENT *operator->() const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(This()->CheckIndex(0));
+
+        return &This()->GetAt(0);
+    }
+    ELEMENT &operator[](int index) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(This()->CheckIndex(index));
+        return *(ELEMENT*)&This()->GetAt(index);
+    }
+    SUBTYPE &operator++()
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        This()->Skip(1);
+        return *This();
+    }
+    SUBTYPE operator++(int)
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        SUBTYPE i = *This();
+        This()->Skip(1);
+        return i;
+    }
+    SUBTYPE &operator--()
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        This()->Skip(-1);
+        return *This();
+    }
+    SUBTYPE operator--(int)
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        SUBTYPE i = *This();
+        This()->Skip(-1);
+        return i;
+    }
+    SUBTYPE &operator+=(SCOUNT_T index)
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        This()->Skip(index);
+        return *This();
+    }
+    SUBTYPE operator+(SCOUNT_T index) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        SUBTYPE i = *This();
+        i.Skip(index);
+        return i;
+    }
+    SUBTYPE &operator-=(SCOUNT_T index)
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        This()->Skip(-index);
+        return *This();
+    }
+    SUBTYPE operator-(SCOUNT_T index) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        SUBTYPE i = *This();
+        i.Skip(-index);
+        return i;
+    }
+    SCOUNT_T operator-(const SUBTYPE &i) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+
+        return This()->Subtract(i);
+    }
+    bool operator==(const SUBTYPE &i) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+
+        return This()->Subtract(i) == 0;
+    }
+    bool operator!=(const SUBTYPE &i) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+
+        return This()->Subtract(i) != 0;
+    }
+    bool operator<(const SUBTYPE &i) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+        return This()->Subtract(i) < 0;
+    }
+    bool operator<=(const SUBTYPE &i) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+        return This()->Subtract(i) <= 0;
+    }
+    bool operator>(const SUBTYPE &i) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+        return This()->Subtract(i) > 0;
+    }
+    bool operator>=(const SUBTYPE &i) const
+    {
+        WRAPPER_NO_CONTRACT;
+        PRECONDITION(CheckPointer(This()));
+        PRECONDITION(i.Check());
+        return This()->Subtract(i) >= 0;
+    }
+};
+
+#endif  // ITERATOR_H_
diff --git a/src/inc/mdcommon.h b/src/inc/mdcommon.h
new file mode 100644 (file)
index 0000000..eeeb32f
--- /dev/null
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// MDCommon.h
+//
+// Common header file for both MD and COMPLIB subdirectories
+//
+//*****************************************************************************
+
+#ifndef __MDCommon_h__
+#define __MDCommon_h__
+
+// File types for the database.
+enum FILETYPE
+{
+       FILETYPE_UNKNOWN,                                       // Unknown or undefined type.
+       FILETYPE_CLB,                                           // Native .clb file format.
+       FILETYPE_CLX,                                       // An obsolete file format.
+       FILETYPE_NTPE,                                          // Windows PE executable.
+       FILETYPE_NTOBJ,                                         // .obj file format (with .clb embedded).
+       FILETYPE_TLB                                            // Typelib format.
+};
+
+enum MAPPINGTYPE
+{
+    MTYPE_NOMAPPING,                        // No mapped file
+    MTYPE_FLAT,                             // Mapped as a flat file
+    MTYPE_IMAGE                             // Mapped with the SEC_IMAGE flag
+};
+
+
+#define SCHEMA_STREAM_A             "#Schema"
+#define STRING_POOL_STREAM_A        "#Strings"
+#define BLOB_POOL_STREAM_A          "#Blob"
+#define US_BLOB_POOL_STREAM_A       "#US"
+#define GUID_POOL_STREAM_A          "#GUID"
+#define COMPRESSED_MODEL_STREAM_A   "#~"
+#define ENC_MODEL_STREAM_A          "#-"
+#define MINIMAL_MD_STREAM_A         "#JTD"
+#define HOT_MODEL_STREAM_A          "#!"
+#ifdef FEATURE_METADATA_EMIT_PORTABLE_PDB
+#define PDB_STREAM_A                "#Pdb"
+#endif // FEATURE_METADATA_EMIT_PORTABLE_PDB
+
+#define SCHEMA_STREAM               W("#Schema")
+#define STRING_POOL_STREAM          W("#Strings")
+#define BLOB_POOL_STREAM            W("#Blob")
+#define US_BLOB_POOL_STREAM         W("#US")
+#define GUID_POOL_STREAM            W("#GUID")
+#define COMPRESSED_MODEL_STREAM     W("#~")
+#define ENC_MODEL_STREAM            W("#-")
+#define MINIMAL_MD_STREAM           W("#JTD")
+#define HOT_MODEL_STREAM            W("#!")
+#ifdef FEATURE_METADATA_EMIT_PORTABLE_PDB
+#define PDB_STREAM                  W("#Pdb")
+#endif // FEATURE_METADATA_EMIT_PORTABLE_PDB
+
+#endif // __MDCommon_h__
diff --git a/src/inc/memoryrange.h b/src/inc/memoryrange.h
new file mode 100644 (file)
index 0000000..ae1d440
--- /dev/null
@@ -0,0 +1,97 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// MemoryRange.h
+//
+// defines the code:MemoryRange class.
+//*****************************************************************************
+
+#ifndef _memory_range_h
+#define _memory_range_h
+
+#include "daccess.h"
+
+// MemoryRange is a descriptor of a memory range. This groups (pointer + size).
+//
+// Some key qualities:
+// - simple!
+// - Not mutable
+// - blitabble descriptor which can be useful for out-of-process tools like the debugger.
+// - no ownership semantics.
+// - no manipulation, growing semantics.
+// - no memory marshalling, allocation, copying. etc.
+// - can be efficiently passed / copied / returned by value
+//
+// This class has general value as an abstraction to group pointer and size together. It also has significant
+// value to the debugger. An expected design pattern is that other mutable complex data structures (eg,
+// code:SBuffer, code:CGrowableStream) will provide an accessor to expose their underlying storage as a
+// MemoryRange to debugger. This mirrors the Debugger's code:TargetBuffer data structure, but as a
+// general-purpose VM utility versus a debugger right-side data structure.
+
+//
+class MemoryRange
+{
+public:
+    // Constructor to create a memory range around a (start address, size) pair.
+    MemoryRange() :
+        m_pStartAddress(NULL),
+        m_cbBytes(0)
+    {
+        SUPPORTS_DAC;
+    }
+
+    MemoryRange(PTR_VOID pStartAddress, SIZE_T cbBytes) :
+        m_pStartAddress(pStartAddress),
+        m_cbBytes(cbBytes)
+    {
+        SUPPORTS_DAC;
+    }
+
+    // Note: use compiler-default copy ctor and assignment operator
+
+
+
+    // Check whether a pointer is in the memory range represented by this instance.
+    BOOL IsInRange(PTR_VOID pAddress) const
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+
+        return (dac_cast<TADDR>(pAddress) - dac_cast<TADDR>(m_pStartAddress)) < m_cbBytes;
+    }
+
+    // Check whether a pointer is in the memory range represented by this instance.
+    BOOL IsInRange(TADDR pAddress) const
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+
+        return (pAddress - dac_cast<TADDR>(m_pStartAddress)) < m_cbBytes;
+    }
+
+    // Get the starting address.
+    PTR_VOID StartAddress() const
+    {
+        SUPPORTS_DAC;
+        return m_pStartAddress;
+    }
+
+    // Get the size of the range in bytes
+    SIZE_T Size() const
+    {
+        SUPPORTS_DAC;
+        return m_cbBytes;
+    }
+
+private:
+    // The start of the memory range.
+    PTR_VOID const m_pStartAddress;
+
+    // The size of the memory range in bytes.
+    // This is s SIZE_T so that it can describe any memory range in the process (for example, larger than 4gb on 64-bit machines)
+    const SIZE_T        m_cbBytes;
+
+};
+
+typedef ArrayDPTR(MemoryRange) ARRAY_PTR_MemoryRange;
+
+#endif // _memory_range_h
+
diff --git a/src/inc/metadata.h b/src/inc/metadata.h
new file mode 100644 (file)
index 0000000..cf69f3a
--- /dev/null
@@ -0,0 +1,1531 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//****************************************************************************
+//  File: metadata.h
+//
+
+//
+//  Notes:
+//   Common includes for EE & metadata internal. This file contains
+//   definition of CorMetaDataScope
+//****************************************************************************
+
+#ifndef _METADATA_H_
+#define _METADATA_H_
+
+#include "ex.h"
+
+class CorProfileData;
+class IMetaModelCommon;
+class MDInternalRW;
+class UTSemReadWrite;
+
+inline int IsGlobalMethodParentTk(mdTypeDef td)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (td == mdTypeDefNil || td == mdTokenNil);
+}
+
+typedef enum CorInternalStates
+{
+    tdNoTypes               = 0x00000000,
+    tdAllAssemblies         = 0x00000001,
+    tdAllTypes              = 0xffffffff,
+} CorInternalStates;
+
+//
+// MetaData custom value names.
+//
+enum CorIfaceAttr
+{
+    ifDual        = 0,            // Interface derives from IDispatch.
+    ifVtable      = 1,            // Interface derives from IUnknown.
+    ifDispatch    = 2,            // Interface is a dispinterface.
+    ifInspectable = 3,            // Interface derives from IInspectable.
+    ifLast        = 4,            // The last member of the enum.
+};
+
+inline BOOL IsDispatchBasedItf(CorIfaceAttr ifaceAttr)
+{
+    return (ifaceAttr == ifDual || ifaceAttr == ifDispatch);
+}
+
+enum CorClassIfaceAttr
+{
+    clsIfNone      = 0,                 // No class interface is generated.
+    clsIfAutoDisp  = 1,                 // A dispatch only class interface is generated.
+    clsIfAutoDual  = 2,                 // A dual class interface is generated.
+    clsIfLast      = 3,                 // The last member of the enum.
+};
+
+//
+// The default values for the COM interface and class interface types.
+//
+#define DEFAULT_COM_INTERFACE_TYPE ifDual
+#define DEFAULT_CLASS_INTERFACE_TYPE clsIfAutoDisp
+
+#define HANDLE_UNCOMPRESSED(func) (E_FAIL)
+#define HANDLE_UNCOMPRESSED_BOOL(func) (false)
+
+class TOKENLIST : public CDynArray<mdToken>
+{
+};
+
+
+typedef enum tagEnumType
+{
+    MDSimpleEnum        = 0x0,                  // simple enumerator that doesn't allocate memory
+
+    // You could get this kind of enum if you perform a non-simple query (such as EnumMethodWithName).
+    //
+    MDDynamicArrayEnum = 0x2,                   // dynamic array that holds tokens
+} EnumType;
+
+//*****************************************
+// Enumerator used by MetaDataInternal
+//*****************************************
+struct HENUMInternal
+{
+    DWORD       m_tkKind;                   // kind of tables that the enum is holding the result
+    uint32_t    m_ulCount;                  // count of total entries holding by the enumerator
+
+    EnumType    m_EnumType;
+
+    struct {
+        uint32_t   m_ulStart;
+        uint32_t   m_ulEnd;
+        uint32_t   m_ulCur;
+    } u;
+
+    // m_cursor will go away when we no longer support running EE with uncompressed
+    // format. WHEN WE REMOVE THIS, REMOVE ITS VESTIAGES FROM ZeroEnum as well
+    //
+    union {
+        void*       m_alignpad;                 // The first item is m_cursor[] is a pointer
+        char        m_cursor[32];               // cursor holding query result for read/write mode
+    };
+
+    // TOKENLIST    daTKList;               // dynamic arrays of token list
+    HENUMInternal() : m_EnumType(MDSimpleEnum) { LIMITED_METHOD_DAC_CONTRACT; }
+
+    // in-place initialization
+    static void InitDynamicArrayEnum(
+        HENUMInternal   *pEnum);            // HENUMInternal to be initialized
+
+    static void InitSimpleEnum(
+        DWORD           tkKind,             // kind of token that we are iterating
+        ULONG           ridStart,           // starting rid
+        ULONG           ridEnd,             // end rid
+        HENUMInternal   *pEnum);            // HENUMInternal to be initialized
+
+    // Specialized helper which should be better than always calling memset
+    inline
+    static void ZeroEnum(
+        HENUMInternal   *pEnum)
+    {
+        // we use this to avoid the memset that will happen otherwise.
+        // this should be inlined in its caller. we are seeing a large
+        // number of calls to memset from MDInternalRO::EnumPermissionSetsInit
+        // on x64 which we can eliminate with this code.
+        pEnum->m_tkKind = 0;
+        pEnum->m_ulCount = 0;
+        pEnum->m_EnumType =  MDSimpleEnum;
+        pEnum->u.m_ulStart = 0;
+        pEnum->u.m_ulEnd = 0;
+        pEnum->u.m_ulCur = 0;
+
+        // TODO: remove this when we remove m_cursor from the HENUMInternal structure
+        _ASSERTE(IS_ALIGNED(pEnum->m_cursor, sizeof(DWORD)));
+        _ASSERTE((sizeof(HENUMInternal) - offsetof(HENUMInternal, m_cursor)) == (8 * sizeof(DWORD)));
+
+        DWORD* pBuffer = (DWORD*)pEnum->m_cursor;
+        pBuffer[0] = 0;
+        pBuffer[1] = 0;
+        pBuffer[2] = 0;
+        pBuffer[3] = 0;
+        pBuffer[4] = 0;
+        pBuffer[5] = 0;
+        pBuffer[6] = 0;
+        pBuffer[7] = 0;
+    }
+
+    // This will only clear the content of enum and will not free the memory of enum
+    static void ClearEnum(
+        HENUMInternal   *pmdEnum);
+
+    // create a HENUMInternal. This will allocate the memory
+    __checkReturn
+    static HRESULT CreateSimpleEnum(
+        DWORD           tkKind,             // kind of token that we are iterating
+        ULONG           ridStart,           // starting rid
+        ULONG           ridEnd,             // end rid
+        HENUMInternal   **ppEnum);          // return the created HENUMInternal
+
+    __checkReturn
+    static HRESULT CreateDynamicArrayEnum(
+        DWORD           tkKind,             // kind of token that we are iterating
+        HENUMInternal   **ppEnum);          // return the created HENUMInternal
+
+    // Destory Enum. This will free the memory
+    static void DestroyEnum(
+        HENUMInternal   *pmdEnum);
+
+    static void DestroyEnumIfEmpty(
+        HENUMInternal   **ppEnum);          // reset the enumerator pointer to NULL if empty
+
+    __checkReturn
+    static HRESULT EnumWithCount(
+        HENUMInternal   *pEnum,             // enumerator
+        ULONG           cMax,               // max tokens that caller wants
+        mdToken         rTokens[],          // output buffer to fill the tokens
+        ULONG           *pcTokens);         // number of tokens fill to the buffer upon return
+
+    __checkReturn
+    static HRESULT EnumWithCount(
+        HENUMInternal   *pEnum,             // enumerator
+        ULONG           cMax,               // max tokens that caller wants
+        mdToken         rTokens1[],         // first output buffer to fill the tokens
+        mdToken         rTokens2[],         // second output buffer to fill the tokens
+        ULONG           *pcTokens);         // number of tokens fill to the buffer upon return
+
+    __checkReturn
+    static HRESULT AddElementToEnum(
+        HENUMInternal   *pEnum,             // return the created HENUMInternal
+        mdToken         tk);                // token to fill
+
+    //*****************************************
+    // Get next value contained in the enumerator
+    //*****************************************
+    static bool EnumNext(
+        HENUMInternal   *phEnum,            // [IN] the enumerator to retrieve information
+        mdToken         *ptk);              // [OUT] token to scope the search
+
+    __checkReturn
+    static HRESULT GetCount(
+        HENUMInternal   *phEnum,            // [IN] the enumerator to retrieve information
+        ULONG           *pCount);           // ]OUT] the index of the desired item
+
+    __checkReturn
+    static HRESULT GetElement(
+        HENUMInternal   *phEnum,            // [IN] the enumerator to retrieve information
+        ULONG           ix,                 // ]IN] the index of the desired item
+        mdToken         *ptk);              // [OUT] token to fill
+
+};
+
+
+
+//*****************************************
+// Default Value for field, param or property. Returned by GetDefaultValue
+//*****************************************
+typedef struct _MDDefaultValue
+{
+#if BIGENDIAN
+    _MDDefaultValue(void)
+    {
+        m_bType = ELEMENT_TYPE_END;
+    }
+    ~_MDDefaultValue(void)
+    {
+        if (m_bType == ELEMENT_TYPE_STRING)
+        {
+            delete[] m_wzValue;
+        }
+    }
+#endif
+
+    // type of default value
+    BYTE            m_bType;                // CorElementType for the default value
+
+    // the default value
+    union
+    {
+        BOOL        m_bValue;               // ELEMENT_TYPE_BOOLEAN
+        CHAR        m_cValue;               // ELEMENT_TYPE_I1
+        BYTE        m_byteValue;            // ELEMENT_TYPE_UI1
+        SHORT       m_sValue;               // ELEMENT_TYPE_I2
+        USHORT      m_usValue;              // ELEMENT_TYPE_UI2
+        LONG        m_lValue;               // ELEMENT_TYPE_I4
+        ULONG       m_ulValue;              // ELEMENT_TYPE_UI4
+        LONGLONG    m_llValue;              // ELEMENT_TYPE_I8
+        ULONGLONG   m_ullValue;             // ELEMENT_TYPE_UI8
+        FLOAT       m_fltValue;             // ELEMENT_TYPE_R4
+        DOUBLE      m_dblValue;             // ELEMENT_TYPE_R8
+        LPCWSTR     m_wzValue;              // ELEMENT_TYPE_STRING
+        IUnknown    *m_unkValue;            // ELEMENT_TYPE_CLASS
+    };
+    ULONG   m_cbSize;   // default value size (for blob)
+
+} MDDefaultValue;
+
+
+
+//*****************************************
+// structure use to in GetAllEventAssociates and GetAllPropertyAssociates
+//*****************************************
+typedef struct
+{
+    mdMethodDef m_memberdef;
+    DWORD       m_dwSemantics;
+} ASSOCIATE_RECORD;
+
+
+//
+// structure use to retrieve class layout informaiton
+//
+typedef struct
+{
+    RID         m_ridFieldCur;          // indexing to the field table
+    RID         m_ridFieldEnd;          // end index to field table
+} MD_CLASS_LAYOUT;
+
+
+// Structure for describing the Assembly MetaData.
+typedef struct
+{
+    USHORT      usMajorVersion;         // Major Version.
+    USHORT      usMinorVersion;         // Minor Version.
+    USHORT      usBuildNumber;          // Build Number.
+    USHORT      usRevisionNumber;       // Revision Number.
+    LPCSTR      szLocale;               // Locale.
+} AssemblyMetaDataInternal;
+
+
+
+// Callback definition for comparing signatures.
+// (*PSIGCOMPARE) (BYTE ScopeSignature[], DWORD ScopeSignatureLength,
+//                 BYTE ExternalSignature[], DWORD ExternalSignatureLength,
+//                 void* SignatureData);
+typedef BOOL (*PSIGCOMPARE)(PCCOR_SIGNATURE, DWORD, PCCOR_SIGNATURE, DWORD, void*);
+
+
+// {1B119F60-C507-4024-BB39-F8223FB3E1FD}
+EXTERN_GUID(IID_IMDInternalImport, 0x1b119f60, 0xc507, 0x4024, 0xbb, 0x39, 0xf8, 0x22, 0x3f, 0xb3, 0xe1, 0xfd);
+
+#undef  INTERFACE
+#define INTERFACE IMDInternalImport
+DECLARE_INTERFACE_(IMDInternalImport, IUnknown)
+{
+    //*****************************************************************************
+    // return the count of entries of a given kind in a scope
+    // For example, pass in mdtMethodDef will tell you how many MethodDef
+    // contained in a scope
+    //*****************************************************************************
+    STDMETHOD_(ULONG, GetCountWithTokenKind)(// return hresult
+        DWORD       tkKind) PURE;           // [IN] pass in the kind of token.
+
+    //*****************************************************************************
+    // enumerator for typedef
+    //*****************************************************************************
+    __checkReturn
+    STDMETHOD(EnumTypeDefInit)(             // return hresult
+        HENUMInternal *phEnum) PURE;        // [OUT] buffer to fill for enumerator data
+
+    //*****************************************************************************
+    // enumerator for MethodImpl
+    //*****************************************************************************
+    __checkReturn
+    STDMETHOD(EnumMethodImplInit)(          // return hresult
+        mdTypeDef       td,                 // [IN] TypeDef over which to scope the enumeration.
+        HENUMInternal   *phEnumBody,        // [OUT] buffer to fill for enumerator data for MethodBody tokens.
+        HENUMInternal   *phEnumDecl) PURE;  // [OUT] buffer to fill for enumerator data for MethodDecl tokens.
+
+    ULONG EnumMethodImplGetCount(
+        HENUMInternal   *phEnumBody,        // [IN] MethodBody enumerator.
+        HENUMInternal   *phEnumDecl)        // [IN] MethodDecl enumerator.
+    {
+        return phEnumBody->m_ulCount;
+    }
+
+    STDMETHOD_(void, EnumMethodImplReset)(
+        HENUMInternal   *phEnumBody,        // [IN] MethodBody enumerator.
+        HENUMInternal   *phEnumDecl) PURE;  // [IN] MethodDecl enumerator.
+
+    __checkReturn
+    STDMETHOD(EnumMethodImplNext)(          // return hresult (S_OK = TRUE, S_FALSE = FALSE or error code)
+        HENUMInternal   *phEnumBody,        // [IN] input enum for MethodBody
+        HENUMInternal   *phEnumDecl,        // [IN] input enum for MethodDecl
+        mdToken         *ptkBody,           // [OUT] return token for MethodBody
+        mdToken         *ptkDecl) PURE;     // [OUT] return token for MethodDecl
+
+    STDMETHOD_(void, EnumMethodImplClose)(
+        HENUMInternal   *phEnumBody,        // [IN] MethodBody enumerator.
+        HENUMInternal   *phEnumDecl) PURE;  // [IN] MethodDecl enumerator.
+
+    //*****************************************
+    // Enumerator helpers for memberdef, memberref, interfaceimp,
+    // event, property, exception, param
+    //*****************************************
+
+    __checkReturn
+    STDMETHOD(EnumGlobalFunctionsInit)(     // return hresult
+        HENUMInternal   *phEnum) PURE;      // [OUT] buffer to fill for enumerator data
+
+    __checkReturn
+    STDMETHOD(EnumGlobalFieldsInit)(        // return hresult
+        HENUMInternal   *phEnum) PURE;      // [OUT] buffer to fill for enumerator data
+
+    __checkReturn
+    STDMETHOD(EnumInit)(                    // return S_FALSE if record not found
+        DWORD       tkKind,                 // [IN] which table to work on
+        mdToken     tkParent,               // [IN] token to scope the search
+        HENUMInternal *phEnum) PURE;        // [OUT] the enumerator to fill
+
+    __checkReturn
+    STDMETHOD(EnumAllInit)(                 // return S_FALSE if record not found
+        DWORD       tkKind,                 // [IN] which table to work on
+        HENUMInternal *phEnum) PURE;        // [OUT] the enumerator to fill
+
+    bool EnumNext(
+        HENUMInternal *phEnum,              // [IN] the enumerator to retrieve information
+        mdToken     *ptk)                   // [OUT] token to scope the search
+    {
+        _ASSERTE(phEnum && ptk);
+        if (phEnum->u.m_ulCur >= phEnum->u.m_ulEnd)
+            return false;
+
+        if ( phEnum->m_EnumType == MDSimpleEnum )
+        {
+            *ptk = phEnum->u.m_ulCur | phEnum->m_tkKind;
+            phEnum->u.m_ulCur++;
+        }
+        else
+        {
+            TOKENLIST       *pdalist = (TOKENLIST *)&(phEnum->m_cursor);
+
+            _ASSERTE( phEnum->m_EnumType == MDDynamicArrayEnum );
+            *ptk = *( pdalist->Get(phEnum->u.m_ulCur++) );
+        }
+        return true;
+    }
+
+    ULONG EnumGetCount(
+        HENUMInternal *phEnum)        // [IN] the enumerator to retrieve information
+    {
+        _ASSERTE(phEnum);
+        return phEnum->m_ulCount;
+    }
+
+    void EnumReset(
+        HENUMInternal *phEnum)        // [IN] the enumerator to be reset
+    {
+        _ASSERTE(phEnum);
+        _ASSERTE( phEnum->m_EnumType == MDSimpleEnum || phEnum->m_EnumType == MDDynamicArrayEnum);
+
+        phEnum->u.m_ulCur = phEnum->u.m_ulStart;
+    } // MDInternalRW::EnumReset
+
+    void EnumClose(
+        HENUMInternal *phEnum)        // [IN] the enumerator to be closed
+    {
+        _ASSERTE( phEnum->m_EnumType == MDSimpleEnum ||
+            phEnum->m_EnumType == MDDynamicArrayEnum);
+        if (phEnum->m_EnumType == MDDynamicArrayEnum)
+            HENUMInternal::ClearEnum(phEnum);
+    }
+
+    //*****************************************
+    // Enumerator helpers for CustomAttribute
+    //*****************************************
+    __checkReturn
+    STDMETHOD(EnumCustomAttributeByNameInit)(// return S_FALSE if record not found
+        mdToken     tkParent,               // [IN] token to scope the search
+        LPCSTR      szName,                 // [IN] CustomAttribute's name to scope the search
+        HENUMInternal *phEnum) PURE;        // [OUT] the enumerator to fill
+
+    //*****************************************
+    // Nagivator helper to navigate back to the parent token given a token.
+    // For example, given a memberdef token, it will return the containing typedef.
+    //
+    // the mapping is as following:
+    //  ---given child type---------parent type
+    //  mdMethodDef                 mdTypeDef
+    //  mdFieldDef                  mdTypeDef
+    //  mdInterfaceImpl             mdTypeDef
+    //  mdParam                     mdMethodDef
+    //  mdProperty                  mdTypeDef
+    //  mdEvent                     mdTypeDef
+    //
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetParentToken)(
+        mdToken     tkChild,                // [IN] given child token
+        mdToken     *ptkParent) PURE;       // [OUT] returning parent
+
+    //*****************************************
+    // Custom value helpers
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetCustomAttributeProps)(     // S_OK or error.
+        mdCustomAttribute at,               // [IN] The attribute.
+        mdToken     *ptkType) PURE;         // [OUT] Put attribute type here.
+
+    __checkReturn
+    STDMETHOD(GetCustomAttributeAsBlob)(
+        mdCustomAttribute cv,               // [IN] given custom value token
+        void const  **ppBlob,               // [OUT] return the pointer to internal blob
+        ULONG       *pcbSize) PURE;         // [OUT] return the size of the blob
+
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD (GetScopeProps)(
+        LPCSTR      *pszName,               // [OUT] scope name
+        GUID        *pmvid) PURE;           // [OUT] version id
+
+    // finding a particular method
+    __checkReturn
+    STDMETHOD(FindMethodDef)(
+        mdTypeDef   classdef,               // [IN] given typedef
+        LPCSTR      szName,                 // [IN] member name
+        PCCOR_SIGNATURE pvSigBlob,          // [IN] point to a blob value of CLR signature
+        ULONG       cbSigBlob,              // [IN] count of bytes in the signature blob
+        mdMethodDef *pmd) PURE;             // [OUT] matching memberdef
+
+    // return a iSeq's param given a MethodDef
+    __checkReturn
+    STDMETHOD(FindParamOfMethod)(           // S_OK or error.
+        mdMethodDef md,                     // [IN] The owning method of the param.
+        ULONG       iSeq,                   // [IN] The sequence # of the param.
+        mdParamDef  *pparamdef) PURE;       // [OUT] Put ParamDef token here.
+
+    //*****************************************
+    //
+    // GetName* functions
+    //
+    //*****************************************
+
+    // return the name and namespace of typedef
+    __checkReturn
+    STDMETHOD(GetNameOfTypeDef)(
+        mdTypeDef   classdef,               // given classdef
+        LPCSTR      *pszname,               // return class name(unqualified)
+        LPCSTR      *psznamespace) PURE;    // return the name space name
+
+    __checkReturn
+    STDMETHOD(GetIsDualOfTypeDef)(
+        mdTypeDef   classdef,               // [IN] given classdef.
+        ULONG       *pDual) PURE;           // [OUT] return dual flag here.
+
+    __checkReturn
+    STDMETHOD(GetIfaceTypeOfTypeDef)(
+        mdTypeDef   classdef,               // [IN] given classdef.
+        ULONG       *pIface) PURE;          // [OUT] 0=dual, 1=vtable, 2=dispinterface
+
+    // get the name of either methoddef
+    __checkReturn
+    STDMETHOD(GetNameOfMethodDef)(  // return the name of the memberdef in UTF8
+        mdMethodDef md,             // given memberdef
+        LPCSTR     *pszName) PURE;
+
+    __checkReturn
+    STDMETHOD(GetNameAndSigOfMethodDef)(
+        mdMethodDef      methoddef,         // [IN] given memberdef
+        PCCOR_SIGNATURE *ppvSigBlob,        // [OUT] point to a blob value of CLR signature
+        ULONG           *pcbSigBlob,        // [OUT] count of bytes in the signature blob
+        LPCSTR          *pszName) PURE;
+
+    // return the name of a FieldDef
+    __checkReturn
+    STDMETHOD(GetNameOfFieldDef)(
+        mdFieldDef fd,              // given memberdef
+        LPCSTR    *pszName) PURE;
+
+    // return the name of typeref
+    __checkReturn
+    STDMETHOD(GetNameOfTypeRef)(
+        mdTypeRef   classref,               // [IN] given typeref
+        LPCSTR      *psznamespace,          // [OUT] return typeref name
+        LPCSTR      *pszname) PURE;         // [OUT] return typeref namespace
+
+    // return the resolutionscope of typeref
+    __checkReturn
+    STDMETHOD(GetResolutionScopeOfTypeRef)(
+        mdTypeRef classref,                     // given classref
+        mdToken  *ptkResolutionScope) PURE;
+
+    // Find the type token given the name.
+    __checkReturn
+    STDMETHOD(FindTypeRefByName)(
+        LPCSTR      szNamespace,            // [IN] Namespace for the TypeRef.
+        LPCSTR      szName,                 // [IN] Name of the TypeRef.
+        mdToken     tkResolutionScope,      // [IN] Resolution Scope fo the TypeRef.
+        mdTypeRef   *ptk) PURE;             // [OUT] TypeRef token returned.
+
+    // return the TypeDef properties
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetTypeDefProps)(
+        mdTypeDef   classdef,               // given classdef
+        DWORD       *pdwAttr,               // return flags on class, tdPublic, tdAbstract
+        mdToken     *ptkExtends) PURE;      // [OUT] Put base class TypeDef/TypeRef here
+
+    // return the item's guid
+    __checkReturn
+    STDMETHOD(GetItemGuid)(
+        mdToken     tkObj,                  // [IN] given item.
+        CLSID       *pGuid) PURE;           // [out[ put guid here.
+
+    // Get enclosing class of the NestedClass.
+    __checkReturn
+    STDMETHOD(GetNestedClassProps)(         // S_OK or error
+        mdTypeDef   tkNestedClass,          // [IN] NestedClass token.
+        mdTypeDef   *ptkEnclosingClass) PURE; // [OUT] EnclosingClass token.
+
+    // Get count of Nested classes given the enclosing class.
+    __checkReturn
+    STDMETHOD(GetCountNestedClasses)(   // return count of Nested classes.
+        mdTypeDef   tkEnclosingClass,   // Enclosing class.
+        ULONG      *pcNestedClassesCount) PURE;
+
+    // Return array of Nested classes given the enclosing class.
+    __checkReturn
+    STDMETHOD(GetNestedClasses)(        // Return actual count.
+        mdTypeDef   tkEnclosingClass,       // [IN] Enclosing class.
+        mdTypeDef   *rNestedClasses,        // [OUT] Array of nested class tokens.
+        ULONG       ulNestedClasses,        // [IN] Size of array.
+        ULONG      *pcNestedClasses) PURE;
+
+    // return the ModuleRef properties
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetModuleRefProps)(
+        mdModuleRef mur,                    // [IN] moduleref token
+        LPCSTR      *pszName) PURE;         // [OUT] buffer to fill with the moduleref name
+
+    //*****************************************
+    //
+    // GetSig* functions
+    //
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetSigOfMethodDef)(
+        mdMethodDef       tkMethodDef,  // [IN] given MethodDef
+        ULONG *           pcbSigBlob,   // [OUT] count of bytes in the signature blob
+        PCCOR_SIGNATURE * ppSig) PURE;
+
+    __checkReturn
+    STDMETHOD(GetSigOfFieldDef)(
+        mdFieldDef        tkFieldDef,   // [IN] given FieldDef
+        ULONG *           pcbSigBlob,   // [OUT] count of bytes in the signature blob
+        PCCOR_SIGNATURE * ppSig) PURE;
+
+    __checkReturn
+    STDMETHOD(GetSigFromToken)(
+        mdToken           tk, // FieldDef, MethodDef, Signature or TypeSpec token
+        ULONG *           pcbSig,
+        PCCOR_SIGNATURE * ppSig) PURE;
+
+
+
+    //*****************************************
+    // get method property
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetMethodDefProps)(
+        mdMethodDef md,                 // The method for which to get props.
+        DWORD      *pdwFlags) PURE;
+
+    //*****************************************
+    // return method implementation informaiton, like RVA and implflags
+    //*****************************************
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetMethodImplProps)(
+        mdToken     tk,                     // [IN] MethodDef
+        ULONG       *pulCodeRVA,            // [OUT] CodeRVA
+        DWORD       *pdwImplFlags) PURE;    // [OUT] Impl. Flags
+
+    //*****************************************
+    // return method implementation informaiton, like RVA and implflags
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetFieldRVA)(
+        mdFieldDef  fd,                     // [IN] fielddef
+        ULONG       *pulCodeRVA) PURE;      // [OUT] CodeRVA
+
+    //*****************************************
+    // get field property
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetFieldDefProps)(
+        mdFieldDef fd,              // [IN] given fielddef
+        DWORD     *pdwFlags) PURE;  // [OUT] return fdPublic, fdPrive, etc flags
+
+    //*****************************************************************************
+    // return default value of a token(could be paramdef, fielddef, or property
+    //*****************************************************************************
+    __checkReturn
+    STDMETHOD(GetDefaultValue)(
+        mdToken     tk,                     // [IN] given FieldDef, ParamDef, or Property
+        MDDefaultValue *pDefaultValue) PURE;// [OUT] default value to fill
+
+
+    //*****************************************
+    // get dispid of a MethodDef or a FieldDef
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetDispIdOfMemberDef)(        // return hresult
+        mdToken     tk,                     // [IN] given methoddef or fielddef
+        ULONG       *pDispid) PURE;         // [OUT] Put the dispid here.
+
+    //*****************************************
+    // return TypeRef/TypeDef given an InterfaceImpl token
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetTypeOfInterfaceImpl)(  // return the TypeRef/typedef token for the interfaceimpl
+        mdInterfaceImpl iiImpl,         // given a interfaceimpl
+        mdToken        *ptkType) PURE;
+
+    //*****************************************
+    // look up function for TypeDef
+    //*****************************************
+    __checkReturn
+    STDMETHOD(FindTypeDef)(
+        LPCSTR      szNamespace,            // [IN] Namespace for the TypeDef.
+        LPCSTR      szName,                 // [IN] Name of the TypeDef.
+        mdToken     tkEnclosingClass,       // [IN] TypeRef/TypeDef Token for the enclosing class.
+        mdTypeDef   *ptypedef) PURE;        // [IN] return typedef
+
+    //*****************************************
+    // return name and sig of a memberref
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetNameAndSigOfMemberRef)(    // return name here
+        mdMemberRef      memberref,         // given memberref
+        PCCOR_SIGNATURE *ppvSigBlob,        // [OUT] point to a blob value of CLR signature
+        ULONG           *pcbSigBlob,        // [OUT] count of bytes in the signature blob
+        LPCSTR          *pszName) PURE;
+
+    //*****************************************************************************
+    // Given memberref, return the parent. It can be TypeRef, ModuleRef, MethodDef
+    //*****************************************************************************
+    __checkReturn
+    STDMETHOD(GetParentOfMemberRef)(
+        mdMemberRef memberref,          // given memberref
+        mdToken    *ptkParent) PURE;    // return the parent token
+
+    __checkReturn
+    STDMETHOD(GetParamDefProps)(
+        mdParamDef paramdef,            // given a paramdef
+        USHORT    *pusSequence,         // [OUT] slot number for this parameter
+        DWORD     *pdwAttr,             // [OUT] flags
+        LPCSTR    *pszName) PURE;       // [OUT] return the name of the parameter
+
+    __checkReturn
+    STDMETHOD(GetPropertyInfoForMethodDef)( // Result.
+        mdMethodDef md,                     // [IN] memberdef
+        mdProperty  *ppd,                   // [OUT] put property token here
+        LPCSTR      *pName,                 // [OUT] put pointer to name here
+        ULONG       *pSemantic) PURE;       // [OUT] put semantic here
+
+    //*****************************************
+    // class layout/sequence information
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetClassPackSize)(            // return error if class doesn't have packsize
+        mdTypeDef   td,                     // [IN] give typedef
+        ULONG       *pdwPackSize) PURE;     // [OUT] 1, 2, 4, 8, or 16
+
+    __checkReturn
+    STDMETHOD(GetClassTotalSize)(           // return error if class doesn't have total size info
+        mdTypeDef   td,                     // [IN] give typedef
+        ULONG       *pdwClassSize) PURE;    // [OUT] return the total size of the class
+
+    __checkReturn
+    STDMETHOD(GetClassLayoutInit)(
+        mdTypeDef   td,                     // [IN] give typedef
+        MD_CLASS_LAYOUT *pLayout) PURE;     // [OUT] set up the status of query here
+
+    __checkReturn
+    STDMETHOD(GetClassLayoutNext)(
+        MD_CLASS_LAYOUT *pLayout,           // [IN|OUT] set up the status of query here
+        mdFieldDef  *pfd,                   // [OUT] return the fielddef
+        ULONG       *pulOffset) PURE;       // [OUT] return the offset/ulSequence associate with it
+
+    //*****************************************
+    // marshal information of a field
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetFieldMarshal)(             // return error if no native type associate with the token
+        mdFieldDef  fd,                     // [IN] given fielddef
+        PCCOR_SIGNATURE *pSigNativeType,    // [OUT] the native type signature
+        ULONG       *pcbNativeType) PURE;   // [OUT] the count of bytes of *ppvNativeType
+
+
+    //*****************************************
+    // property APIs
+    //*****************************************
+    // find a property by name
+    __checkReturn
+    STDMETHOD(FindProperty)(
+        mdTypeDef   td,                     // [IN] given a typdef
+        LPCSTR      szPropName,             // [IN] property name
+        mdProperty  *pProp) PURE;           // [OUT] return property token
+
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetPropertyProps)(
+        mdProperty  prop,                   // [IN] property token
+        LPCSTR      *szProperty,            // [OUT] property name
+        DWORD       *pdwPropFlags,          // [OUT] property flags.
+        PCCOR_SIGNATURE *ppvSig,            // [OUT] property type. pointing to meta data internal blob
+        ULONG       *pcbSig) PURE;          // [OUT] count of bytes in *ppvSig
+
+    //**********************************
+    // Event APIs
+    //**********************************
+    __checkReturn
+    STDMETHOD(FindEvent)(
+        mdTypeDef   td,                     // [IN] given a typdef
+        LPCSTR      szEventName,            // [IN] event name
+        mdEvent     *pEvent) PURE;          // [OUT] return event token
+
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetEventProps)(
+        mdEvent     ev,                     // [IN] event token
+        LPCSTR      *pszEvent,              // [OUT] Event name
+        DWORD       *pdwEventFlags,         // [OUT] Event flags.
+        mdToken     *ptkEventType) PURE;    // [OUT] EventType class
+
+
+    //**********************************
+    // find a particular associate of a property or an event
+    //**********************************
+    __checkReturn
+    STDMETHOD(FindAssociate)(
+        mdToken     evprop,                 // [IN] given a property or event token
+        DWORD       associate,              // [IN] given a associate semantics(setter, getter, testdefault, reset, AddOn, RemoveOn, Fire)
+        mdMethodDef *pmd) PURE;             // [OUT] return method def token
+
+    // Note, void function in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(EnumAssociateInit)(
+        mdToken     evprop,                 // [IN] given a property or an event token
+        HENUMInternal *phEnum) PURE;        // [OUT] cursor to hold the query result
+
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetAllAssociates)(
+        HENUMInternal *phEnum,              // [IN] query result form GetPropertyAssociateCounts
+        ASSOCIATE_RECORD *pAssociateRec,    // [OUT] struct to fill for output
+        ULONG       cAssociateRec) PURE;    // [IN] size of the buffer
+
+
+    //**********************************
+    // Get info about a PermissionSet.
+    //**********************************
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetPermissionSetProps)(
+        mdPermission pm,                    // [IN] the permission token.
+        DWORD       *pdwAction,             // [OUT] CorDeclSecurity.
+        void const  **ppvPermission,        // [OUT] permission blob.
+        ULONG       *pcbPermission) PURE;   // [OUT] count of bytes of pvPermission.
+
+    //****************************************
+    // Get the String given the String token.
+    // Returns a pointer to the string, or NULL in case of error.
+    //****************************************
+    __checkReturn
+    STDMETHOD(GetUserString)(
+        mdString stk,                   // [IN] the string token.
+        ULONG   *pchString,             // [OUT] count of characters in the string.
+        BOOL    *pbIs80Plus,            // [OUT] specifies where there are extended characters >= 0x80.
+        LPCWSTR *pwszUserString) PURE;
+
+    //*****************************************************************************
+    // p-invoke APIs.
+    //*****************************************************************************
+    __checkReturn
+    STDMETHOD(GetPinvokeMap)(
+        mdToken     tk,                     // [IN] FieldDef, MethodDef.
+        DWORD       *pdwMappingFlags,       // [OUT] Flags used for mapping.
+        LPCSTR      *pszImportName,         // [OUT] Import name.
+        mdModuleRef *pmrImportDLL) PURE;    // [OUT] ModuleRef token for the target DLL.
+
+    //*****************************************************************************
+    // helpers to convert a text signature to a com format
+    //*****************************************************************************
+    __checkReturn
+    STDMETHOD(ConvertTextSigToComSig)(      // Return hresult.
+        BOOL        fCreateTrIfNotFound,    // [IN] create typeref if not found
+        LPCSTR      pSignature,             // [IN] class file format signature
+        CQuickBytes *pqbNewSig,             // [OUT] place holder for CLR signature
+        ULONG       *pcbCount) PURE;        // [OUT] the result size of signature
+
+    //*****************************************************************************
+    // Assembly MetaData APIs.
+    //*****************************************************************************
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetAssemblyProps)(
+        mdAssembly  mda,                    // [IN] The Assembly for which to get the properties.
+        const void  **ppbPublicKey,         // [OUT] Pointer to the public key.
+        ULONG       *pcbPublicKey,          // [OUT] Count of bytes in the public key.
+        ULONG       *pulHashAlgId,          // [OUT] Hash Algorithm.
+        LPCSTR      *pszName,               // [OUT] Buffer to fill with name.
+        AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData.
+        DWORD       *pdwAssemblyFlags) PURE;// [OUT] Flags.
+
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetAssemblyRefProps)(
+        mdAssemblyRef mdar,                 // [IN] The AssemblyRef for which to get the properties.
+        const void  **ppbPublicKeyOrToken,  // [OUT] Pointer to the public key or token.
+        ULONG       *pcbPublicKeyOrToken,   // [OUT] Count of bytes in the public key or token.
+        LPCSTR      *pszName,               // [OUT] Buffer to fill with name.
+        AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData.
+        const void  **ppbHashValue,         // [OUT] Hash blob.
+        ULONG       *pcbHashValue,          // [OUT] Count of bytes in the hash blob.
+        DWORD       *pdwAssemblyRefFlags) PURE; // [OUT] Flags.
+
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetFileProps)(
+        mdFile      mdf,                    // [IN] The File for which to get the properties.
+        LPCSTR      *pszName,               // [OUT] Buffer to fill with name.
+        const void  **ppbHashValue,         // [OUT] Pointer to the Hash Value Blob.
+        ULONG       *pcbHashValue,          // [OUT] Count of bytes in the Hash Value Blob.
+        DWORD       *pdwFileFlags) PURE;    // [OUT] Flags.
+
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetExportedTypeProps)(
+        mdExportedType   mdct,              // [IN] The ExportedType for which to get the properties.
+        LPCSTR      *pszNamespace,          // [OUT] Namespace.
+        LPCSTR      *pszName,               // [OUT] Name.
+        mdToken     *ptkImplementation,     // [OUT] mdFile or mdAssemblyRef that provides the ExportedType.
+        mdTypeDef   *ptkTypeDef,            // [OUT] TypeDef token within the file.
+        DWORD       *pdwExportedTypeFlags) PURE; // [OUT] Flags.
+
+    // returned void in v1.0/v1.1
+    __checkReturn
+    STDMETHOD(GetManifestResourceProps)(
+        mdManifestResource  mdmr,           // [IN] The ManifestResource for which to get the properties.
+        LPCSTR      *pszName,               // [OUT] Buffer to fill with name.
+        mdToken     *ptkImplementation,     // [OUT] mdFile or mdAssemblyRef that provides the ExportedType.
+        DWORD       *pdwOffset,             // [OUT] Offset to the beginning of the resource within the file.
+        DWORD       *pdwResourceFlags) PURE;// [OUT] Flags.
+
+    __checkReturn
+    STDMETHOD(FindExportedTypeByName)(      // S_OK or error
+        LPCSTR      szNamespace,            // [IN] Namespace of the ExportedType.
+        LPCSTR      szName,                 // [IN] Name of the ExportedType.
+        mdExportedType   tkEnclosingType,   // [IN] ExportedType for the enclosing class.
+        mdExportedType   *pmct) PURE;       // [OUT] Put ExportedType token here.
+
+    __checkReturn
+    STDMETHOD(FindManifestResourceByName)(  // S_OK or error
+        LPCSTR      szName,                 // [IN] Name of the ManifestResource.
+        mdManifestResource *pmmr) PURE;     // [OUT] Put ManifestResource token here.
+
+    __checkReturn
+    STDMETHOD(GetAssemblyFromScope)(        // S_OK or error
+        mdAssembly  *ptkAssembly) PURE;     // [OUT] Put token here.
+
+    __checkReturn
+    STDMETHOD(GetCustomAttributeByName)(    // S_OK or error
+        mdToken     tkObj,                  // [IN] Object with Custom Attribute.
+        LPCUTF8     szName,                 // [IN] Name of desired Custom Attribute.
+        const void  **ppData,               // [OUT] Put pointer to data here.
+        ULONG       *pcbData) PURE;         // [OUT] Put size of data here.
+
+    // Note: The return type of this method was void in v1
+    __checkReturn
+    STDMETHOD(GetTypeSpecFromToken)(      // S_OK or error.
+        mdTypeSpec typespec,                // [IN] Signature token.
+        PCCOR_SIGNATURE *ppvSig,            // [OUT] return pointer to token.
+        ULONG       *pcbSig) PURE;               // [OUT] return size of signature.
+
+    __checkReturn
+    STDMETHOD(SetUserContextData)(          // S_OK or E_NOTIMPL
+        IUnknown    *pIUnk) PURE;           // The user context.
+
+    __checkReturn
+    STDMETHOD_(BOOL, IsValidToken)(         // True or False.
+        mdToken     tk) PURE;               // [IN] Given token.
+
+    __checkReturn
+    STDMETHOD(TranslateSigWithScope)(
+        IMDInternalImport *pAssemImport,    // [IN] import assembly scope.
+        const void  *pbHashValue,           // [IN] hash value for the import assembly.
+        ULONG       cbHashValue,            // [IN] count of bytes in the hash value.
+        PCCOR_SIGNATURE pbSigBlob,          // [IN] signature in the importing scope
+        ULONG       cbSigBlob,              // [IN] count of bytes of signature
+        IMetaDataAssemblyEmit *pAssemEmit,  // [IN] assembly emit scope.
+        IMetaDataEmit *emit,                // [IN] emit interface
+        CQuickBytes *pqkSigEmit,            // [OUT] buffer to hold translated signature
+        ULONG       *pcbSig) PURE;          // [OUT] count of bytes in the translated signature
+
+    STDMETHOD_(IMetaModelCommon*, GetMetaModelCommon)(  // Return MetaModelCommon interface.
+        ) PURE;
+
+    STDMETHOD_(IUnknown *, GetCachedPublicInterface)(BOOL fWithLock) PURE;   // return the cached public interface
+    __checkReturn
+    STDMETHOD(SetCachedPublicInterface)(IUnknown *pUnk) PURE;  // no return value
+    STDMETHOD_(UTSemReadWrite*, GetReaderWriterLock)() PURE;   // return the reader writer lock
+    __checkReturn
+    STDMETHOD(SetReaderWriterLock)(UTSemReadWrite * pSem) PURE;
+
+    STDMETHOD_(mdModule, GetModuleFromScope)() PURE;             // [OUT] Put mdModule token here.
+
+
+    //-----------------------------------------------------------------
+    // Additional custom methods
+
+    // finding a particular method
+    __checkReturn
+    STDMETHOD(FindMethodDefUsingCompare)(
+        mdTypeDef   classdef,               // [IN] given typedef
+        LPCSTR      szName,                 // [IN] member name
+        PCCOR_SIGNATURE pvSigBlob,          // [IN] point to a blob value of CLR signature
+        ULONG       cbSigBlob,              // [IN] count of bytes in the signature blob
+        PSIGCOMPARE pSignatureCompare,      // [IN] Routine to compare signatures
+        void*       pSignatureArgs,         // [IN] Additional info to supply the compare function
+        mdMethodDef *pmd) PURE;             // [OUT] matching memberdef
+
+    // Additional v2 methods.
+
+    //*****************************************
+    // return a field offset for a given field
+    //*****************************************
+    __checkReturn
+    STDMETHOD(GetFieldOffset)(
+        mdFieldDef  fd,                     // [IN] fielddef
+        ULONG       *pulOffset) PURE;       // [OUT] FieldOffset
+
+    __checkReturn
+    STDMETHOD(GetMethodSpecProps)(
+        mdMethodSpec ms,                    // [IN] The method instantiation
+        mdToken *tkParent,                  // [OUT] MethodDef or MemberRef
+        PCCOR_SIGNATURE *ppvSigBlob,        // [OUT] point to the blob value of meta data
+        ULONG       *pcbSigBlob) PURE;      // [OUT] actual size of signature blob
+
+    __checkReturn
+    STDMETHOD(GetTableInfoWithIndex)(
+        ULONG      index,                   // [IN] pass in the table index
+        void       **pTable,                // [OUT] pointer to table at index
+        void       **pTableSize) PURE;      // [OUT] size of table at index
+
+    __checkReturn
+    STDMETHOD(ApplyEditAndContinue)(
+        void        *pDeltaMD,              // [IN] the delta metadata
+        ULONG       cbDeltaMD,              // [IN] length of pData
+        IMDInternalImport **ppv) PURE;      // [OUT] the resulting metadata interface
+
+    //**********************************
+    // Generics APIs
+    //**********************************
+    __checkReturn
+    STDMETHOD(GetGenericParamProps)(        // S_OK or error.
+        mdGenericParam rd,                  // [IN] The type parameter
+        ULONG* pulSequence,                 // [OUT] Parameter sequence number
+        DWORD* pdwAttr,                     // [OUT] Type parameter flags (for future use)
+        mdToken *ptOwner,                   // [OUT] The owner (TypeDef or MethodDef)
+        DWORD *reserved,                    // [OUT] The kind (TypeDef/Ref/Spec, for future use)
+        LPCSTR *szName) PURE;               // [OUT] The name
+
+    __checkReturn
+    STDMETHOD(GetGenericParamConstraintProps)(      // S_OK or error.
+        mdGenericParamConstraint rd,            // [IN] The constraint token
+        mdGenericParam *ptGenericParam,         // [OUT] GenericParam that is constrained
+        mdToken      *ptkConstraintType) PURE;  // [OUT] TypeDef/Ref/Spec constraint
+
+    //*****************************************************************************
+    // This function gets the "built for" version of a metadata scope.
+    //  NOTE: if the scope has never been saved, it will not have a built-for
+    //  version, and an empty string will be returned.
+    //*****************************************************************************
+    __checkReturn
+    STDMETHOD(GetVersionString)(    // S_OK or error.
+        LPCSTR      *pVer) PURE;       // [OUT] Put version string here.
+
+
+    __checkReturn
+    STDMETHOD(GetTypeDefRefTokenInTypeSpec)(// return S_FALSE if enclosing type does not have a token
+        mdTypeSpec  tkTypeSpec,               // [IN] TypeSpec token to look at
+        mdToken    *tkEnclosedToken) PURE;    // [OUT] The enclosed type token
+
+#define MD_STREAM_VER_1X    0x10000
+#define MD_STREAM_VER_2_B1  0x10001
+#define MD_STREAM_VER_2     0x20000
+    STDMETHOD_(DWORD, GetMetadataStreamVersion)() PURE;  //returns DWORD with major version of
+                                // MD stream in senior word and minor version--in junior word
+
+    __checkReturn
+    STDMETHOD(GetNameOfCustomAttribute)(// S_OK or error
+        mdCustomAttribute mdAttribute,      // [IN] The Custom Attribute
+        LPCUTF8          *pszNamespace,     // [OUT] Namespace of Custom Attribute.
+        LPCUTF8          *pszName) PURE;    // [OUT] Name of Custom Attribute.
+
+    STDMETHOD(SetOptimizeAccessForSpeed)(// S_OK or error
+        BOOL    fOptSpeed) PURE;
+
+    STDMETHOD(SetVerifiedByTrustedSource)(// S_OK or error
+        BOOL    fVerified) PURE;
+
+    STDMETHOD(GetRvaOffsetData)(
+        DWORD   *pFirstMethodRvaOffset,     // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table.
+        DWORD   *pMethodDefRecordSize,      // [OUT] Size of each record in MethodDef table.
+        DWORD   *pMethodDefCount,           // [OUT] Number of records in MethodDef table.
+        DWORD   *pFirstFieldRvaOffset,      // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table.
+        DWORD   *pFieldRvaRecordSize,       // [OUT] Size of each record in FieldRVA table.
+        DWORD   *pFieldRvaCount             // [OUT] Number of records in FieldRVA table.
+        ) PURE;
+
+    //----------------------------------------------------------------------------------------
+    // !!! READ THIS !!!
+    //
+    // New methods have to be added at the end. The order and signatures of the existing methods
+    // have to be preserved. We need to maintain a backward compatibility for this interface to
+    // allow ildasm to work on SingleCLR.
+    //
+    //----------------------------------------------------------------------------------------
+
+};  // IMDInternalImport
+
+
+// {E03D7730-D7E3-11d2-8C0D-00C04FF7431A}
+EXTERN_GUID(IID_IMDInternalImportENC, 0xe03d7730, 0xd7e3, 0x11d2, 0x8c, 0xd, 0x0, 0xc0, 0x4f, 0xf7, 0x43, 0x1a);
+
+#undef  INTERFACE
+#define INTERFACE IMDInternalImportENC
+DECLARE_INTERFACE_(IMDInternalImportENC, IMDInternalImport)
+{
+private:
+    using IMDInternalImport::ApplyEditAndContinue;
+public:
+    // ENC only methods here.
+    STDMETHOD(ApplyEditAndContinue)(        // S_OK or error.
+        MDInternalRW *pDelta) PURE;         // Interface to MD with the ENC delta.
+
+    STDMETHOD(EnumDeltaTokensInit)(         // return hresult
+        HENUMInternal *phEnum) PURE;        // [OUT] buffer to fill for enumerator data
+
+}; // IMDInternalImportENC
+
+// {F102C526-38CB-49ed-9B5F-498816AE36E0}
+EXTERN_GUID(IID_IMDInternalEmit, 0xf102c526, 0x38cb, 0x49ed, 0x9b, 0x5f, 0x49, 0x88, 0x16, 0xae, 0x36, 0xe0);
+
+#undef  INTERFACE
+#define INTERFACE IMDInternalEmit
+DECLARE_INTERFACE_(IMDInternalEmit, IUnknown)
+{
+    STDMETHOD(ChangeMvid)(                  // S_OK or error.
+        REFGUID newMvid) PURE;              // GUID to use as the MVID
+
+    STDMETHOD(SetMDUpdateMode)(
+        ULONG updateMode, ULONG *pPreviousUpdateMode) PURE;
+
+}; // IMDInternalEmit
+
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+
+struct IMDCustomDataSource;
+class CMiniMdSchema;
+struct CMiniTableDef;
+namespace MetaData
+{
+    class DataBlob;
+}
+
+// {CC0C8F7A-A00B-493D-80B6-CE0C92491670}
+EXTERN_GUID(IID_IMDCustomDataSource, 0xcc0c8f7a, 0xa00b, 0x493d, 0x80, 0xb6, 0xce, 0xc, 0x92, 0x49, 0x16, 0x70);
+
+#undef  INTERFACE
+#define INTERFACE IMDCustomDataSource
+DECLARE_INTERFACE_(IMDCustomDataSource, IUnknown)
+{
+    STDMETHOD(GetSchema)(CMiniMdSchema* pSchema) PURE;
+    STDMETHOD(GetTableDef)(ULONG32 tableIndex, CMiniTableDef* pTableDef) PURE;
+    STDMETHOD(GetBlobHeap)(MetaData::DataBlob* pBlobHeapData) PURE;
+    STDMETHOD(GetGuidHeap)(MetaData::DataBlob* pGuidHeapData) PURE;
+    STDMETHOD(GetStringHeap)(MetaData::DataBlob* pStringHeapData) PURE;
+    STDMETHOD(GetUserStringHeap)(MetaData::DataBlob* pUserStringHeapData) PURE;
+    STDMETHOD(GetTableRecords)(ULONG32 tableIndex, MetaData::DataBlob* pTableRecordData) PURE;
+    STDMETHOD(GetTableSortable)(ULONG32 tableIndex, BOOL* pSortable) PURE;
+    STDMETHOD(GetStorageSignature)(MetaData::DataBlob* pStorageSignature) PURE;
+
+}; // IMDCustomDataSource
+
+// {503F79FB-7AAE-4364-BDA6-8E235D173AEC}
+EXTERN_GUID(IID_IMetaDataDispenserCustom,
+    0x503f79fb, 0x7aae, 0x4364, 0xbd, 0xa6, 0x8e, 0x23, 0x5d, 0x17, 0x3a, 0xec);
+
+#undef  INTERFACE
+#define INTERFACE IMetaDataDispenserCustom
+DECLARE_INTERFACE_(IMetaDataDispenserCustom, IUnknown)
+{
+    STDMETHOD(OpenScopeOnCustomDataSource)(    // Return code.
+        IMDCustomDataSource  *pCustomSource,  // [in] The scope to open.
+        DWORD                dwOpenFlags,    // [in] Open mode flags.
+        REFIID               riid,           // [in] The interface desired.
+        IUnknown             **ppIUnk) PURE; // [out] Return interface on success.
+
+}; // IMetaDataDispenserCustom
+
+#endif // FEATURE_METADATA_CUSTOM_DATA_SOURCE
+
+#ifdef FEATURE_METADATA_DEBUGGEE_DATA_SOURCE
+struct ICorDebugDataTarget;
+HRESULT CreateRemoteMDInternalRWSource(TADDR mdInternalRWRemoteAddress, ICorDebugDataTarget* pDataTarget, DWORD defines, DWORD dataStructureVersion, IMDCustomDataSource** ppDataSource);
+#endif
+
+enum MetaDataReorderingOptions {
+    NoReordering=0x0,
+    ReArrangeStringPool=0x1
+};
+
+#ifdef __HOLDER_H_
+
+void DECLSPEC_NORETURN ThrowHR(HRESULT hr);
+
+// This wrapper class ensures that the HENUMInternal is EnumClose'd no matter how the scope is exited.
+class HENUMTypeDefInternalHolder
+{
+public:
+    FORCEINLINE HENUMTypeDefInternalHolder(IMDInternalImport *pInternalImport)
+    {
+        WRAPPER_NO_CONTRACT;
+
+        m_pInternalImport = pInternalImport;
+        m_fAcquired       = FALSE;
+    }
+
+    FORCEINLINE VOID EnumTypeDefInit()
+    {
+        CONTRACTL {
+            THROWS;
+        } CONTRACTL_END;
+
+        _ASSERTE(!m_fAcquired);
+        HRESULT hr = m_pInternalImport->EnumTypeDefInit(&m_hEnum);
+        if (FAILED(hr))
+        {
+            ThrowHR(hr);
+        }
+        m_fAcquired = TRUE;
+
+    }
+
+    FORCEINLINE HRESULT EnumTypeDefInitNoThrow()
+    {
+        WRAPPER_NO_CONTRACT;
+
+        _ASSERTE(!m_fAcquired);
+        HRESULT hr = m_pInternalImport->EnumTypeDefInit(&m_hEnum);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+        m_fAcquired = TRUE;
+
+        return hr;
+    }
+
+    FORCEINLINE ~HENUMTypeDefInternalHolder()
+    {
+        WRAPPER_NO_CONTRACT;
+
+        if (m_fAcquired)
+        {
+            m_pInternalImport->EnumClose(&m_hEnum);
+        }
+    }
+
+    FORCEINLINE HENUMInternal* operator& ()
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        _ASSERTE(m_fAcquired);
+        return &m_hEnum;
+    }
+
+private:
+    FORCEINLINE HENUMTypeDefInternalHolder(const HENUMTypeDefInternalHolder &)
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        _ASSERTE(!"Don't try to assign this class.");
+    }
+
+private:
+    IMDInternalImport *m_pInternalImport;
+    HENUMInternal      m_hEnum;
+    BOOL               m_fAcquired;
+};
+
+
+// This wrapper class ensures that the HENUMInternal is EnumClose'd no matter how the scope is exited.
+class HENUMInternalHolder
+{
+public:
+    FORCEINLINE HENUMInternalHolder(IMDInternalImport *pInternalImport)
+    {
+        WRAPPER_NO_CONTRACT;
+
+        m_pInternalImport = pInternalImport;
+        m_fAcquired       = FALSE;
+    }
+
+    FORCEINLINE VOID EnumGlobalFunctionsInit()
+    {
+        CONTRACTL {
+            THROWS;
+        } CONTRACTL_END;
+
+        _ASSERTE(!m_fAcquired);
+        HRESULT hr = m_pInternalImport->EnumGlobalFunctionsInit(&m_hEnum);
+        if (FAILED(hr))
+        {
+            ThrowHR(hr);
+        }
+        m_fAcquired = TRUE;
+
+    }
+
+
+    FORCEINLINE VOID EnumGlobalFieldsInit()
+    {
+        CONTRACTL {
+            THROWS;
+        } CONTRACTL_END;
+
+        _ASSERTE(!m_fAcquired);
+        HRESULT hr = m_pInternalImport->EnumGlobalFieldsInit(&m_hEnum);
+        if (FAILED(hr))
+        {
+            ThrowHR(hr);
+        }
+        m_fAcquired = TRUE;
+
+    }
+
+    FORCEINLINE VOID EnumTypeDefInit()
+    {
+        CONTRACTL {
+            THROWS;
+        } CONTRACTL_END;
+
+        _ASSERTE(!m_fAcquired);
+        HRESULT hr = m_pInternalImport->EnumTypeDefInit(&m_hEnum);
+        if (FAILED(hr))
+        {
+            ThrowHR(hr);
+        }
+        m_fAcquired = TRUE;
+    }
+
+    FORCEINLINE VOID EnumAssociateInit(mdToken tkParent)        // [IN] token to scope the search
+    {
+        CONTRACTL {
+            THROWS;
+        } CONTRACTL_END;
+
+        _ASSERTE(!m_fAcquired);
+        IfFailThrow(m_pInternalImport->EnumAssociateInit(tkParent, &m_hEnum));
+        m_fAcquired = TRUE;
+    }
+
+    FORCEINLINE VOID EnumInit(DWORD       tkKind,                 // [IN] which table to work on
+                              mdToken     tkParent                // [IN] token to scope the search
+                             )
+    {
+        CONTRACTL {
+            THROWS;
+        } CONTRACTL_END;
+
+        HRESULT hr = EnumInitNoThrow(tkKind, tkParent);
+        if (FAILED(hr))
+        {
+            ThrowHR(hr);
+        }
+    }
+
+    __checkReturn
+    FORCEINLINE HRESULT EnumInitNoThrow(DWORD       tkKind,       // [IN] which table to work on
+                                        mdToken     tkParent      // [IN] token to scope the search
+                                       )
+    {
+        CONTRACTL {
+            NOTHROW;
+        } CONTRACTL_END;
+
+        _ASSERTE(!m_fAcquired);
+        HRESULT hr = m_pInternalImport->EnumInit(tkKind, tkParent, &m_hEnum);
+        if (SUCCEEDED(hr))
+        {
+            m_fAcquired = TRUE;
+        }
+        return hr;
+    }
+
+    FORCEINLINE VOID EnumAllInit(DWORD       tkKind                 // [IN] which table to work on
+                             )
+    {
+        CONTRACTL {
+            THROWS;
+        } CONTRACTL_END;
+
+        _ASSERTE(!m_fAcquired);
+        HRESULT hr = m_pInternalImport->EnumAllInit(tkKind, &m_hEnum);
+        if (FAILED(hr))
+        {
+            ThrowHR(hr);
+        }
+        m_fAcquired = TRUE;
+
+    }
+
+    FORCEINLINE ULONG EnumGetCount()
+    {
+        CONTRACTL {
+            NOTHROW;
+            GC_NOTRIGGER;
+            CONSISTENCY_CHECK(m_fAcquired);
+        } CONTRACTL_END;
+
+        return m_pInternalImport->EnumGetCount(&m_hEnum);
+    }
+
+    FORCEINLINE bool EnumNext(mdToken * pTok)
+    {
+        CONTRACTL {
+            NOTHROW;
+            GC_NOTRIGGER;
+            CONSISTENCY_CHECK(m_fAcquired);
+        } CONTRACTL_END;
+
+        return m_pInternalImport->EnumNext(&m_hEnum, pTok);
+    }
+
+    FORCEINLINE void EnumReset()
+    {
+        CONTRACTL {
+            NOTHROW;
+            GC_NOTRIGGER;
+            CONSISTENCY_CHECK(m_fAcquired);
+        } CONTRACTL_END;
+
+        return m_pInternalImport->EnumReset(&m_hEnum);
+    }
+
+    FORCEINLINE ~HENUMInternalHolder()
+    {
+        WRAPPER_NO_CONTRACT;
+
+        if (m_fAcquired)
+        {
+            // Ignore the error
+            (void)m_pInternalImport->EnumClose(&m_hEnum);
+        }
+    }
+
+    FORCEINLINE HENUMInternal* operator& ()
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        _ASSERTE(m_fAcquired);
+        return &m_hEnum;
+    }
+
+private:
+    FORCEINLINE HENUMInternalHolder(const HENUMInternalHolder &)
+    {
+        WRAPPER_NO_CONTRACT;
+
+        _ASSERTE(!"Don't try to assign this class.");
+    }
+
+
+protected:
+    IMDInternalImport *m_pInternalImport;
+    HENUMInternal      m_hEnum;
+    BOOL               m_fAcquired;
+};
+
+class HENUMInternalMethodImplHolder : protected HENUMInternalHolder
+{
+    public:
+        FORCEINLINE HENUMInternalMethodImplHolder(IMDInternalImport *pInternalImport)
+            : HENUMInternalHolder(pInternalImport)
+        {
+            WRAPPER_NO_CONTRACT;
+        }
+
+        FORCEINLINE ~HENUMInternalMethodImplHolder()
+        {
+            WRAPPER_NO_CONTRACT;
+
+            if (m_fAcquired)
+            {
+                // Ignore the error
+                (void)m_pInternalImport->EnumClose(&m_hEnum2);
+            }
+        }
+
+        FORCEINLINE void EnumMethodImplInit(mdToken     tkParent                   // [IN] token to scope the search
+                                 )
+        {
+            CONTRACTL {
+                THROWS;
+            } CONTRACTL_END;
+
+            HRESULT hr = EnumMethodImplInitNoThrow(tkParent);
+            if (FAILED(hr))
+            {
+                ThrowHR(hr);
+            }
+        }
+
+        __checkReturn
+        FORCEINLINE HRESULT EnumMethodImplInitNoThrow(mdToken     tkParent         // [IN] token to scope the search
+                                 )
+        {
+            CONTRACTL {
+                NOTHROW;
+            } CONTRACTL_END;
+
+            _ASSERTE(!m_fAcquired);
+            HRESULT hr = m_pInternalImport->EnumMethodImplInit(tkParent, &m_hEnum, &m_hEnum2);
+            if (SUCCEEDED(hr))
+            {
+                m_fAcquired = TRUE;
+            }
+            return hr;
+        }
+
+        __checkReturn
+        FORCEINLINE HRESULT EnumMethodImplNext(
+            mdToken *ptkImpl,
+            mdToken *ptkDecl)
+        {
+            CONTRACTL {
+                NOTHROW;
+                GC_NOTRIGGER;
+                CONSISTENCY_CHECK(m_fAcquired);
+            } CONTRACTL_END;
+
+            return m_pInternalImport->EnumMethodImplNext(&m_hEnum, &m_hEnum2, ptkImpl, ptkDecl);
+        }
+
+        FORCEINLINE ULONG EnumMethodImplGetCount()
+        {
+            CONTRACTL {
+                NOTHROW;
+                GC_NOTRIGGER;
+                CONSISTENCY_CHECK(m_fAcquired);
+            } CONTRACTL_END;
+
+            return m_pInternalImport->EnumMethodImplGetCount(&m_hEnum, &m_hEnum2);
+        }
+
+    protected:
+        HENUMInternal      m_hEnum2;
+};
+
+#endif //__HOLDER_H_
+
+#endif // _METADATA_H_
diff --git a/src/inc/nibblemapmacros.h b/src/inc/nibblemapmacros.h
new file mode 100644 (file)
index 0000000..9554b5d
--- /dev/null
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef NIBBLEMAPMACROS_H_
+#define NIBBLEMAPMACROS_H_
+
+///////////////////////////////////////////////////////////////////////
+////   some mmgr stuff for JIT, especially for jit code blocks
+///////////////////////////////////////////////////////////////////////
+//
+// In order to quickly find the start of a jit code block
+// we keep track of all those positions via a map.
+// Each entry in this map represents 32 byte (a bucket) of the code heap.
+// We make the assumption that no two code-blocks can start in
+// the same 32byte bucket;
+// Additionally we assume that every code header is DWORD aligned.
+// Because we cannot guarantee that jitblocks always start at
+// multiples of 32 bytes we cannot use a simple bitmap; instead we
+// use a nibble (4 bit) per bucket and encode the offset of the header
+// inside the bucket (in DWORDS). In order to make initialization
+// easier we add one to the real offset, a nibble-value of zero
+// means that there is no header start in the resp. bucket.
+// In order to speed up "backwards scanning" we start numbering
+// nibbles inside a DWORD from the highest bits (28..31). Because
+// of that we can scan backwards inside the DWORD with right shifts.
+
+#if defined(HOST_64BIT)
+// TODO: bump up the windows CODE_ALIGN to 16 and iron out any nibble map bugs that exist.
+// TODO: there is something wrong with USE_INDIRECT_CODEHEADER with CODE_ALIGN=16
+# define CODE_ALIGN             4
+# define LOG2_CODE_ALIGN        2
+#else
+# define CODE_ALIGN             sizeof(DWORD)                                // 4 byte boundry
+# define LOG2_CODE_ALIGN        2
+#endif
+#define NIBBLE_MASK             0xf
+#define NIBBLE_SIZE             4                                            // 4 bits
+#define LOG2_NIBBLE_SIZE        2
+#define NIBBLES_PER_DWORD       ((8*sizeof(DWORD)) >> LOG2_NIBBLE_SIZE)      // 8 (4-bit) nibbles per dword
+#define NIBBLES_PER_DWORD_MASK  (NIBBLES_PER_DWORD - 1)                      // 7
+#define LOG2_NIBBLES_PER_DWORD  3
+#define BYTES_PER_BUCKET        (NIBBLES_PER_DWORD * CODE_ALIGN)             // 32 bytes per bucket
+#define LOG2_BYTES_PER_BUCKET   (LOG2_CODE_ALIGN + LOG2_NIBBLES_PER_DWORD)   //  5 bits per bucket
+#define MASK_BYTES_PER_BUCKET   (BYTES_PER_BUCKET - 1)                       // 31
+#define HIGHEST_NIBBLE_BIT      (32 - NIBBLE_SIZE)                           // 28 (i.e 32 - 4)
+#define HIGHEST_NIBBLE_MASK     (NIBBLE_MASK << HIGHEST_NIBBLE_BIT)          // 0xf0000000
+
+#define ADDR2POS(x)                      ((x) >> LOG2_BYTES_PER_BUCKET)
+#define ADDR2OFFS(x)            (DWORD)  ((((x) & MASK_BYTES_PER_BUCKET) >> LOG2_CODE_ALIGN) + 1)
+#define POSOFF2ADDR(pos, of)    (size_t) (((pos) << LOG2_BYTES_PER_BUCKET) + (((of) - 1) << LOG2_CODE_ALIGN))
+#define HEAP2MAPSIZE(x)                  (((x) / (BYTES_PER_BUCKET * NIBBLES_PER_DWORD)) * CODE_ALIGN)
+#define POS2SHIFTCOUNT(x)       (DWORD)  (HIGHEST_NIBBLE_BIT - (((x) & NIBBLES_PER_DWORD_MASK) << LOG2_NIBBLE_SIZE))
+#define POS2MASK(x)             (DWORD) ~(HIGHEST_NIBBLE_MASK >> (((x) & NIBBLES_PER_DWORD_MASK) << LOG2_NIBBLE_SIZE))
+
+#endif  // NIBBLEMAPMACROS_H_
diff --git a/src/inc/nsutilpriv.h b/src/inc/nsutilpriv.h
new file mode 100644 (file)
index 0000000..5ea9d0e
--- /dev/null
@@ -0,0 +1,265 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// NSUtilPriv.h
+//
+// Helpers for converting namespace separators.
+//
+//*****************************************************************************
+
+#ifndef __NSUTILPRIV_H__
+#define __NSUTILPRIV_H__
+
+template <class T> class CQuickArray;
+class SString;
+
+struct ns
+{
+
+//*****************************************************************************
+// Determine how many chars large a fully qualified name would be given the
+// two parts of the name.  The return value includes room for every character
+// in both names, as well as room for the separator and a final terminator.
+//*****************************************************************************
+static
+int GetFullLength(                      // Number of chars in full name.
+    const WCHAR *szNameSpace,           // Namspace for value.
+    const WCHAR *szName);               // Name of value.
+
+static
+int GetFullLength(                      // Number of chars in full name.
+    LPCUTF8     szNameSpace,            // Namspace for value.
+    LPCUTF8     szName);                // Name of value.
+
+//*****************************************************************************
+// Scan the given string to see if the name contains any invalid characters
+// that are not allowed.
+//*****************************************************************************
+static
+int IsValidName(                        // true if valid, false invalid.
+    const WCHAR *szName);               // Name to parse.
+
+static
+int IsValidName(                        // true if valid, false invalid.
+    LPCUTF8     szName);                // Name to parse.
+
+
+//*****************************************************************************
+// Scan the string from the rear looking for the first valid separator.  If
+// found, return a pointer to it.  Else return null.  This code is smart enough
+// to skip over special sequences, such as:
+//      a.b..ctor
+//         ^
+//         |
+// The ".ctor" is considered one token.
+//*****************************************************************************
+static
+WCHAR *FindSep(                         // Pointer to separator or null.
+    const WCHAR *szPath);               // The path to look in.
+
+static
+LPUTF8 FindSep(                         // Pointer to separator or null.
+    LPCUTF8     szPath);                // The path to look in.
+
+
+//*****************************************************************************
+// Take a path and find the last separator (nsFindSep), and then replace the
+// separator with a '\0' and return a pointer to the name.  So for example:
+//      a.b.c
+// becomes two strings "a.b" and "c" and the return value points to "c".
+//*****************************************************************************
+static
+WCHAR *SplitInline(                     // Pointer to name portion.
+    __inout __inout_z WCHAR       *szPath);               // The path to split.
+
+static
+LPUTF8       SplitInline(               // Pointer to name portion.
+    __inout __inout_z LPUTF8      szPath);                // The path to split.
+
+static
+void SplitInline(
+    __inout __inout_z LPWSTR     szPath,                  // Path to split.
+    LPCWSTR      &szNameSpace,          // Return pointer to namespace.
+    LPCWSTR     &szName);               // Return pointer to name.
+
+static
+void SplitInline(
+    __inout __inout_z LPUTF8       szPath,                // Path to split.
+    LPCUTF8      &szNameSpace,          // Return pointer to namespace.
+    LPCUTF8      &szName);              // Return pointer to name.
+
+
+//*****************************************************************************
+// Split the last parsable element from the end of the string as the name,
+// the first part as the namespace.
+//*****************************************************************************
+static
+int SplitPath(                          // true ok, false trunction.
+    const WCHAR *szPath,                // Path to split.
+    _Out_writes_opt_ (cchNameSpace) WCHAR *szNameSpace,           // Output for namespace value.
+    int         cchNameSpace,           // Max chars for output.
+    _Out_writes_opt_ (cchName) WCHAR       *szName,                // Output for name.
+    int         cchName);               // Max chars for output.
+
+static
+int SplitPath(                          // true ok, false trunction.
+    LPCUTF8     szPath,                 // Path to split.
+    _Out_writes_opt_ (cchNameSpace) LPUTF8 szNameSpace,            // Output for namespace value.
+    int         cchNameSpace,           // Max chars for output.
+    _Out_writes_opt_ (cchName) LPUTF8      szName,                 // Output for name.
+    int         cchName);               // Max chars for output.
+
+
+//*****************************************************************************
+// Take two values and put them together in a fully qualified path using the
+// correct separator.
+//*****************************************************************************
+static
+int MakePath(                           // true ok, false truncation.
+    _Out_writes_(cchChars) WCHAR       *szOut,                 // output path for name.
+    int         cchChars,               // max chars for output path.
+    const WCHAR *szNameSpace,           // Namespace.
+    const WCHAR *szName);               // Name.
+
+static
+int MakePath(                           // true ok, false truncation.
+    _Out_writes_(cchChars) LPUTF8      szOut,                  // output path for name.
+    int         cchChars,               // max chars for output path.
+    LPCUTF8     szNameSpace,            // Namespace.
+    LPCUTF8     szName);                // Name.
+
+static
+int MakePath(                           // true ok, false truncation.
+    _Out_writes_(cchChars) WCHAR       *szOut,                 // output path for name.
+    int         cchChars,               // max chars for output path.
+    LPCUTF8     szNameSpace,            // Namespace.
+    LPCUTF8     szName);                // Name.
+
+static
+int MakePath(                           // true ok, false out of memory
+    CQuickBytes &qb,                    // Where to put results.
+    LPCUTF8     szNameSpace,            // Namespace for name.
+    LPCUTF8     szName);                // Final part of name.
+
+static
+int MakePath(                           // true ok, false out of memory
+    CQuickArray<WCHAR> &qa,             // Where to put results.
+    LPCUTF8     szNameSpace,            // Namespace for name.
+    LPCUTF8     szName);                // Final part of name.
+
+static
+int MakePath(                           // true ok, false out of memory
+    CQuickBytes &qb,                    // Where to put results.
+    const WCHAR *szNameSpace,           // Namespace for name.
+    const WCHAR *szName);               // Final part of name.
+
+static
+void MakePath(                          // throws on out of memory
+    SString       &ssBuf,               // Where to put results.
+    const SString &ssNameSpace,         // Namespace for name.
+    const SString &ssName);             // Final part of name.
+
+//*****************************************************************************
+// Concatinate type names to assembly names
+//*****************************************************************************
+static
+bool MakeAssemblyQualifiedName(                                  // true if ok, false if out of memory
+                               CQuickBytes &qb,                  // location to put result
+                               const WCHAR *szTypeName,          // Type name
+                               const WCHAR *szAssemblyName);     // Assembly Name
+
+static
+bool MakeAssemblyQualifiedName(                                        // true ok, false truncation
+                               _Out_writes_ (dwBuffer) WCHAR* pBuffer, // Buffer to receive the results
+                               int    dwBuffer,                        // Number of characters total in buffer
+                               const WCHAR *szTypeName,                // Namespace for name.
+                               int   dwTypeName,                       // Number of characters (not including null)
+                               const WCHAR *szAssemblyName,            // Final part of name.
+                               int   dwAssemblyName);                  // Number of characters (not including null)
+
+static
+int MakeNestedTypeName(                 // true ok, false out of memory
+    CQuickBytes &qb,                    // Where to put results.
+    LPCUTF8     szEnclosingName,        // Full name for enclosing type
+    LPCUTF8     szNestedName);          // Full name for nested type
+
+static
+int MakeNestedTypeName(                 // true ok, false truncation.
+    _Out_writes_ (cchChars) LPUTF8      szOut,                  // output path for name.
+    int         cchChars,               // max chars for output path.
+    LPCUTF8     szEnclosingName,        // Full name for enclosing type
+    LPCUTF8     szNestedName);          // Full name for nested type
+
+static
+void MakeNestedTypeName(                // throws on out of memory
+    SString        &ssBuf,              // output path for name.
+    const SString  &ssEnclosingName,    // Full name for enclosing type
+    const SString  &ssNestedName);      // Full name for nested type
+}; // struct ns
+
+#ifndef NAMESPACE_SEPARATOR_CHAR
+#define NAMESPACE_SEPARATOR_CHAR '.'
+#define NAMESPACE_SEPARATOR_WCHAR W('.')
+#define NAMESPACE_SEPARATOR_STR "."
+#define NAMESPACE_SEPARATOR_WSTR W(".")
+#define NAMESPACE_SEPARATOR_LEN 1
+#define ASSEMBLY_SEPARATOR_CHAR ','
+#define ASSEMBLY_SEPARATOR_WCHAR W(',')
+#define ASSEMBLY_SEPARATOR_STR ", "
+#define ASSEMBLY_SEPARATOR_WSTR W(", ")
+#define ASSEMBLY_SEPARATOR_LEN 2
+#define BACKSLASH_CHAR '\\'
+#define BACKSLASH_WCHAR W('\\')
+#define NESTED_SEPARATOR_CHAR '+'
+#define NESTED_SEPARATOR_WCHAR W('+')
+#define NESTED_SEPARATOR_STR "+"
+#define NESTED_SEPARATOR_WSTR W("+")
+#endif
+
+#define EMPTY_STR ""
+#define EMPTY_WSTR W("")
+
+#define MAKE_FULL_PATH_ON_STACK_UTF8(toptr, pnamespace, pname) \
+{ \
+    int __i##toptr = ns::GetFullLength(pnamespace, pname); \
+    toptr = (char *) alloca(__i##toptr); \
+    ns::MakePath(toptr, __i##toptr, pnamespace, pname); \
+}
+
+#define MAKE_FULL_PATH_ON_STACK_UNICODE(toptr, pnamespace, pname) \
+{ \
+    int __i##toptr = ns::GetFullLength(pnamespace, pname); \
+    toptr = (WCHAR *) alloca(__i##toptr * sizeof(WCHAR)); \
+    ns::MakePath(toptr, __i##toptr, pnamespace, pname); \
+}
+
+#define MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszNameSpace, pszName) MAKE_FULL_PATH_ON_STACK_UTF8(pszFullyQualifiedName, pszNameSpace, pszName)
+
+#define MAKE_FULLY_QUALIFIED_MEMBER_NAME(ptr, pszNameSpace, pszClassName, pszMemberName, pszSig) \
+{ \
+    int __i##ptr = ns::GetFullLength(pszNameSpace, pszClassName); \
+    __i##ptr += (pszMemberName ? (int) strlen(pszMemberName) : 0); \
+    __i##ptr += (NAMESPACE_SEPARATOR_LEN * 2); \
+    __i##ptr += (pszSig ? (int) strlen(pszSig) : 0); \
+    ptr = (LPUTF8) alloca(__i##ptr); \
+    ns::MakePath(ptr, __i##ptr, pszNameSpace, pszClassName); \
+    if (pszMemberName) { \
+        strcat_s(ptr, __i##ptr, NAMESPACE_SEPARATOR_STR); \
+        strcat_s(ptr, __i##ptr, pszMemberName); \
+    } \
+    if (pszSig) { \
+        if (! pszMemberName) \
+            strcat_s(ptr, __i##ptr, NAMESPACE_SEPARATOR_STR); \
+        strcat_s(ptr, __i##ptr, pszSig); \
+    } \
+}
+
+#ifdef _PREFAST_
+// need to eliminate the expansion of MAKE_FULLY_QUALIFIED_MEMBER_NAME in prefast
+// builds to prevent it complaining about the potential for NULLs to strlen and strcat
+#undef MAKE_FULLY_QUALIFIED_MEMBER_NAME
+// need to set ptr=NULL so we don't get a build error because ptr isn't inited in a couple cases
+#define MAKE_FULLY_QUALIFIED_MEMBER_NAME(ptr, pszNameSpace, pszClassName, pszMemberName, pszSig) ptr=NULL;
+#endif
+
+#endif
diff --git a/src/inc/ostype.h b/src/inc/ostype.h
new file mode 100644 (file)
index 0000000..ddb0ec5
--- /dev/null
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#include "staticcontract.h"
+
+#ifndef WRAPPER_NO_CONTRACT
+#define WRAPPER_NO_CONTRACT             ANNOTATION_WRAPPER
+#endif
+
+#ifndef LIMITED_METHOD_CONTRACT
+#define LIMITED_METHOD_CONTRACT                ANNOTATION_FN_LEAF
+#endif
+
+//*****************************************************************************
+// Enum to track which version of the OS we are running
+// Note that NT5 (Win2k) is the minimum supported platform. Any code using
+// utilcode (which includes the CLR's execution engine) will fail to start
+// on a pre-Win2k platform. This is enforced by InitRunningOnVersionStatus.
+//
+// Note: The value is used for data mining from links clicked by user in shim dialog - see code:FWLinkTemplateFromTextID
+//   Please do not modify existing values, adding new ones is fine.
+//*****************************************************************************
+typedef enum {
+    RUNNING_ON_STATUS_UNINITED = 0,
+    RUNNING_ON_WIN7            = 1,
+    RUNNING_ON_WIN8            = 2
+} RunningOnStatusEnum;
+
+extern RunningOnStatusEnum gRunningOnStatus;
+
+void InitRunningOnVersionStatus();
+
+#if defined(FEATURE_COMINTEROP) && !defined(FEATURE_CORESYSTEM)
+typedef enum
+{
+    WINRT_STATUS_UNINITED = 0,
+    WINRT_STATUS_UNSUPPORTED,
+    WINRT_STATUS_SUPPORTED
+}
+WinRTStatusEnum;
+
+extern WinRTStatusEnum      gWinRTStatus;
+
+void InitWinRTStatus();
+#endif // FEATURE_COMINTEROP && !FEATURE_CORESYSTEM
+
+//*****************************************************************************
+// Returns true if you are running on Windows 8 or newer.
+//*****************************************************************************
+inline BOOL RunningOnWin8()
+{
+    WRAPPER_NO_CONTRACT;
+#if (!defined(HOST_X86) && !defined(HOST_AMD64))
+    return TRUE;
+#else
+    if (gRunningOnStatus == RUNNING_ON_STATUS_UNINITED)
+    {
+        InitRunningOnVersionStatus();
+    }
+
+    return (gRunningOnStatus >= RUNNING_ON_WIN8) ? TRUE : FALSE;
+#endif
+}
+
+#ifdef FEATURE_COMINTEROP
+
+#ifdef FEATURE_CORESYSTEM
+
+inline BOOL WinRTSupported()
+{
+    return RunningOnWin8();
+}
+#else
+inline BOOL WinRTSupported()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+
+
+    if (gWinRTStatus == WINRT_STATUS_UNINITED)
+    {
+        InitWinRTStatus();
+    }
+
+    return gWinRTStatus == WINRT_STATUS_SUPPORTED;
+}
+#endif // FEATURE_CORESYSTEM
+
+#endif // FEATURE_COMINTEROP
+
+#ifdef HOST_64BIT
+inline BOOL RunningInWow64()
+{
+    return FALSE;
+}
+#else
+BOOL RunningInWow64();
+#endif
diff --git a/src/inc/pedecoder.h b/src/inc/pedecoder.h
new file mode 100644 (file)
index 0000000..bb4ea86
--- /dev/null
@@ -0,0 +1,429 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// --------------------------------------------------------------------------------
+// PEDecoder.h
+//
+
+// --------------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------------
+// PEDecoder - Utility class for reading and verifying PE files.
+//
+// Note that the Check step is optional if you are willing to trust the
+// integrity of the image.
+// (Or at any rate can be factored into an initial verification step.)
+//
+// Functions which access the memory of the PE file take a "flat" flag - this
+// indicates whether the PE images data has been loaded flat the way it resides in the file,
+// or if the sections have been mapped into memory at the proper base addresses.
+//
+// Finally, some functions take an optional "size" argument, which can be used for
+// range verification.  This is an optional parameter, but if you omit it be sure
+// you verify the size in some other way.
+// --------------------------------------------------------------------------------
+
+
+#ifndef PEDECODER_H_
+#define PEDECODER_H_
+
+// --------------------------------------------------------------------------------
+// Required headers
+// --------------------------------------------------------------------------------
+
+#include "windows.h"
+#include "clrtypes.h"
+#include "check.h"
+#include "contract.h"
+#include "cor.h"
+#include "corhdr.h"
+
+#include "readytorun.h"
+typedef DPTR(struct READYTORUN_CORE_HEADER) PTR_READYTORUN_CORE_HEADER;
+typedef DPTR(struct READYTORUN_HEADER) PTR_READYTORUN_HEADER;
+typedef DPTR(struct READYTORUN_SECTION) PTR_READYTORUN_SECTION;
+
+typedef DPTR(IMAGE_COR20_HEADER)    PTR_IMAGE_COR20_HEADER;
+
+// --------------------------------------------------------------------------------
+// Forward declared types
+// --------------------------------------------------------------------------------
+
+class Module;
+
+// --------------------------------------------------------------------------------
+// RVA definition
+// --------------------------------------------------------------------------------
+
+// Needs to be DWORD to avoid conflict with <imagehlp.h>
+typedef DWORD RVA;
+
+#ifdef _MSC_VER
+// Wrapper to suppress ambigous overload problems with MSVC.
+inline CHECK CheckOverflow(RVA value1, COUNT_T value2)
+{
+    WRAPPER_NO_CONTRACT;
+    CHECK(CheckOverflow((UINT32) value1, (UINT32) value2));
+    CHECK_OK;
+}
+#endif  // _MSC_VER
+
+// --------------------------------------------------------------------------------
+// IMAGE_FILE_MACHINE_NATIVE
+// --------------------------------------------------------------------------------
+
+#if defined(TARGET_X86)
+#define IMAGE_FILE_MACHINE_NATIVE   IMAGE_FILE_MACHINE_I386
+#elif defined(TARGET_AMD64)
+#define IMAGE_FILE_MACHINE_NATIVE   IMAGE_FILE_MACHINE_AMD64
+#elif defined(TARGET_ARM)
+#define IMAGE_FILE_MACHINE_NATIVE   IMAGE_FILE_MACHINE_ARMNT
+#elif defined(TARGET_ARM64)
+#define IMAGE_FILE_MACHINE_NATIVE   IMAGE_FILE_MACHINE_ARM64
+#elif defined(TARGET_S390X)
+#define IMAGE_FILE_MACHINE_NATIVE   IMAGE_FILE_MACHINE_UNKNOWN
+#else
+#error "port me"
+#endif
+
+// Machine code for native images
+#if defined(__APPLE__)
+#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x4644
+#elif defined(__FreeBSD__)
+#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0xADC4
+#elif defined(__linux__)
+#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x7B79
+#elif defined(__NetBSD__)
+#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x1993
+#elif defined(__sun)
+#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x1992
+#else
+#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0
+#endif
+
+#define IMAGE_FILE_MACHINE_NATIVE_NI (IMAGE_FILE_MACHINE_NATIVE ^ IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE)
+
+// --------------------------------------------------------------------------------
+// Types
+// --------------------------------------------------------------------------------
+
+typedef DPTR(class PEDecoder) PTR_PEDecoder;
+
+typedef bool (*PEDecoder_ResourceTypesCallbackFunction)(LPCWSTR lpType, void* context);
+typedef bool (*PEDecoder_ResourceNamesCallbackFunction)(LPCWSTR lpName, LPCWSTR lpType, void* context);
+typedef bool (*PEDecoder_ResourceCallbackFunction)(LPCWSTR lpName, LPCWSTR lpType, DWORD langid, BYTE* data, COUNT_T cbData, void* context);
+
+class PEDecoder
+{
+  public:
+
+    // ------------------------------------------------------------
+    // Public API
+    // ------------------------------------------------------------
+
+    // Access functions are divided into 3 categories:
+    //  Has - check if the element is present
+    //  Check - Do consistency checks on the element (requires Has).
+    //          This step is optional if you are willing to trust the integrity of the
+    //          image. (It is asserted in a checked build.)
+    //  Get - Access the element (requires Has and Check)
+
+    PEDecoder();
+    PEDecoder(void *flatBase, COUNT_T size);              // flatBase is the raw disk layout data (using MapViewOfFile)
+    PEDecoder(PTR_VOID mappedBase, bool relocated = FALSE);  // mappedBase is the mapped/expanded file (using LoadLibrary)
+
+    void Init(void *flatBase, COUNT_T size);
+    HRESULT Init(void *mappedBase, bool relocated = FALSE);
+    void   Reset();  //make sure you don't have a thread race
+
+    PTR_VOID GetBase() const;            // Currently loaded base, as opposed to GetPreferredBase()
+    BOOL IsMapped() const;
+    BOOL IsRelocated() const;
+    BOOL IsFlat() const;
+    BOOL HasContents() const;
+    COUNT_T GetSize() const;          // size of file on disk, as opposed to GetVirtualSize()
+
+    // High level image checks:
+
+    CHECK CheckFormat() const;        // Check whatever is present
+    CHECK CheckNTFormat() const;      // Check a PE file image
+    CHECK CheckCORFormat() const;     // Check a COR image (IL or native)
+    CHECK CheckILFormat() const;      // Check a managed image
+    CHECK CheckILOnlyFormat() const;  // Check an IL only image
+
+    // NT header access
+
+    BOOL HasNTHeaders() const;
+    CHECK CheckNTHeaders() const;
+
+    IMAGE_NT_HEADERS32 *GetNTHeaders32() const;
+    IMAGE_NT_HEADERS64 *GetNTHeaders64() const;
+    BOOL Has32BitNTHeaders() const;
+
+    const void *GetHeaders(COUNT_T *pSize = NULL) const;
+
+    BOOL IsDll() const;
+    BOOL HasBaseRelocations() const;
+    const void *GetPreferredBase() const; // OptionalHeaders.ImageBase
+    COUNT_T GetVirtualSize() const; // OptionalHeaders.SizeOfImage - size of mapped/expanded image in memory
+    WORD GetSubsystem() const;
+    WORD GetDllCharacteristics() const;
+    DWORD GetTimeDateStamp() const;
+    DWORD GetCheckSum() const;
+    WORD GetMachine() const;
+    WORD GetCharacteristics() const;
+    DWORD GetFileAlignment() const;
+    DWORD GetSectionAlignment() const;
+    SIZE_T GetSizeOfStackReserve() const;
+    SIZE_T GetSizeOfStackCommit() const;
+    SIZE_T GetSizeOfHeapReserve() const;
+    SIZE_T GetSizeOfHeapCommit() const;
+    UINT32 GetLoaderFlags() const;
+    UINT32 GetWin32VersionValue() const;
+    COUNT_T GetNumberOfRvaAndSizes() const;
+    COUNT_T GetNumberOfSections() const;
+    PTR_IMAGE_SECTION_HEADER FindFirstSection() const;
+    IMAGE_SECTION_HEADER *FindSection(LPCSTR sectionName) const;
+
+    DWORD GetImageIdentity() const;
+
+    BOOL HasWriteableSections() const;
+
+    // Directory entry access
+
+    BOOL HasDirectoryEntry(int entry) const;
+    CHECK CheckDirectoryEntry(int entry, int forbiddenFlags = 0, IsNullOK ok = NULL_NOT_OK) const;
+    IMAGE_DATA_DIRECTORY *GetDirectoryEntry(int entry) const;
+    TADDR GetDirectoryEntryData(int entry, COUNT_T *pSize = NULL) const;
+
+    // IMAGE_DATA_DIRECTORY access
+
+    CHECK CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags = 0, IsNullOK ok = NULL_NOT_OK) const;
+    TADDR GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir) const;
+    TADDR GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir, COUNT_T *pSize) const;
+
+    // Basic RVA access
+
+    CHECK CheckRva(RVA rva, IsNullOK ok = NULL_NOT_OK) const;
+    CHECK CheckRva(RVA rva, COUNT_T size, int forbiddenFlags=0, IsNullOK ok = NULL_NOT_OK) const;
+    TADDR GetRvaData(RVA rva, IsNullOK ok = NULL_NOT_OK) const;
+    // Called with ok=NULL_OK only for mapped fields (RVA statics)
+
+    CHECK CheckData(const void *data, IsNullOK ok = NULL_NOT_OK) const;
+    CHECK CheckData(const void *data, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const;
+    RVA GetDataRva(const TADDR data) const;
+    BOOL PointerInPE(PTR_CVOID data) const;
+
+    // Flat mapping utilities - using PointerToRawData instead of (Relative)VirtualAddress
+    CHECK CheckOffset(COUNT_T fileOffset, IsNullOK ok = NULL_NOT_OK) const;
+    CHECK CheckOffset(COUNT_T fileOffset, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const;
+    TADDR GetOffsetData(COUNT_T fileOffset, IsNullOK ok = NULL_NOT_OK) const;
+    // Called with ok=NULL_OK only for mapped fields (RVA statics)
+
+    // Mapping between RVA and file offsets
+    COUNT_T RvaToOffset(RVA rva) const;
+    RVA OffsetToRva(COUNT_T fileOffset) const;
+
+    // Base intra-image pointer access
+    // (These are for pointers retrieved out of the PE image)
+
+    CHECK CheckInternalAddress(SIZE_T address, IsNullOK ok = NULL_NOT_OK) const;
+    CHECK CheckInternalAddress(SIZE_T address, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const;
+    TADDR GetInternalAddressData(SIZE_T address) const;
+
+    // CLR loader IL Image verification - these checks apply to IL_ONLY images.
+
+    BOOL IsILOnly() const;
+    CHECK CheckILOnly() const;
+
+    // Strong name & hashing support
+
+    BOOL HasStrongNameSignature() const;
+    CHECK CheckStrongNameSignature() const;
+    PTR_CVOID GetStrongNameSignature(COUNT_T *pSize = NULL) const;
+
+    // CorHeader flag support
+
+    // IsStrongNameSigned indicates whether the signature has been filled in.
+    // (otherwise if it has a signature it is delay signed.)
+    BOOL IsStrongNameSigned() const;    // TRUE if the COMIMAGE_FLAGS_STRONGNAMESIGNED flag is set
+
+    // TLS
+
+    BOOL HasTls() const;
+    CHECK CheckTls() const;
+    PTR_VOID GetTlsRange(COUNT_T *pSize = NULL) const;
+    UINT32 GetTlsIndex() const;
+
+    // Win32 resources
+    void *GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSize = NULL) const;
+    bool EnumerateWin32ResourceTypes(PEDecoder_ResourceTypesCallbackFunction callback, void* context) const;
+    bool EnumerateWin32ResourceNames(LPCWSTR lpType, PEDecoder_ResourceNamesCallbackFunction callback, void* context) const;
+    bool EnumerateWin32Resources(LPCWSTR lpName, LPCWSTR lpType, PEDecoder_ResourceCallbackFunction callback, void* context) const;
+  public:
+
+    // COR header fields
+
+    BOOL HasCorHeader() const;
+    CHECK CheckCorHeader() const;
+    IMAGE_COR20_HEADER *GetCorHeader() const;
+
+    PTR_CVOID GetMetadata(COUNT_T *pSize = NULL) const;
+
+    const void *GetResources(COUNT_T *pSize = NULL) const;
+    CHECK CheckResource(COUNT_T offset) const;
+    const void *GetResource(COUNT_T offset, COUNT_T *pSize = NULL) const;
+
+    BOOL HasManagedEntryPoint() const;
+    ULONG GetEntryPointToken() const;
+    IMAGE_COR_VTABLEFIXUP *GetVTableFixups(COUNT_T *pCount = NULL) const;
+
+    BOOL IsNativeMachineFormat() const;
+    BOOL IsI386() const;
+
+    void GetPEKindAndMachine(DWORD * pdwPEKind, DWORD *pdwMachine);  // Returns CorPEKind flags
+    BOOL IsPlatformNeutral(); // Returns TRUE for IL-only platform neutral images
+
+    //
+    // Verifies that the IL is within the bounds of the image.
+    //
+    CHECK CheckILMethod(RVA rva);
+
+    //
+    // Compute size of IL blob. Assumes that the IL is within the bounds of the image - make sure
+    // to call CheckILMethod before calling this method.
+    //
+    static SIZE_T ComputeILMethodSize(TADDR pIL);
+
+    // Debug directory access, returns NULL if no such entry
+    PTR_IMAGE_DEBUG_DIRECTORY GetDebugDirectoryEntry(UINT index) const;
+
+    PTR_CVOID GetNativeManifestMetadata(COUNT_T* pSize = NULL) const;
+
+    BOOL IsComponentAssembly() const;
+    BOOL HasReadyToRunHeader() const;
+    READYTORUN_HEADER *GetReadyToRunHeader() const;
+
+    void  GetEXEStackSizes(SIZE_T *PE_SizeOfStackReserve, SIZE_T *PE_SizeOfStackCommit) const;
+
+    // Native DLLMain Entrypoint
+    BOOL HasNativeEntryPoint() const;
+    void *GetNativeEntryPoint() const;
+
+    // Look up a named symbol in the export directory
+    PTR_VOID GetExport(LPCSTR exportName) const;
+
+#ifdef DACCESS_COMPILE
+    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis);
+#endif
+
+  protected:
+
+    // ------------------------------------------------------------
+    // Protected API for subclass use
+    // ------------------------------------------------------------
+
+    // Checking utilites
+    static CHECK CheckBounds(RVA rangeBase, COUNT_T rangeSize, RVA rva);
+    static CHECK CheckBounds(RVA rangeBase, COUNT_T rangeSize, RVA rva, COUNT_T size);
+
+    static CHECK CheckBounds(const void *rangeBase, COUNT_T rangeSize, const void *pointer);
+    static CHECK CheckBounds(PTR_CVOID rangeBase, COUNT_T rangeSize, PTR_CVOID pointer, COUNT_T size);
+
+  protected:
+
+    // Flat mapping utilities - using PointerToRawData instead of (Relative)VirtualAddress
+    IMAGE_SECTION_HEADER *RvaToSection(RVA rva) const;
+    IMAGE_SECTION_HEADER *OffsetToSection(COUNT_T fileOffset) const;
+
+    void SetRelocated();
+    IMAGE_NT_HEADERS* FindNTHeaders() const;
+
+  private:
+
+    // ------------------------------------------------------------
+    // Internal functions
+    // ------------------------------------------------------------
+
+    enum METADATA_SECTION_TYPE
+    {
+        METADATA_SECTION_FULL,
+    };
+
+    IMAGE_DATA_DIRECTORY *GetMetaDataHelper(METADATA_SECTION_TYPE type) const;
+
+    static PTR_IMAGE_SECTION_HEADER FindFirstSection(IMAGE_NT_HEADERS * pNTHeaders);
+
+    IMAGE_COR20_HEADER *FindCorHeader() const;
+    READYTORUN_HEADER *FindReadyToRunHeader() const;
+
+    // Flat mapping utilities
+    RVA InternalAddressToRva(SIZE_T address) const;
+
+    // NT header subchecks
+    CHECK CheckSection(COUNT_T previousAddressEnd, COUNT_T addressStart, COUNT_T addressSize,
+                       COUNT_T previousOffsetEnd, COUNT_T offsetStart, COUNT_T offsetSize) const;
+
+    // Pure managed subchecks
+    CHECK CheckILOnlyImportDlls() const;
+    CHECK CheckILOnlyImportByNameTable(RVA rva) const;
+    CHECK CheckILOnlyBaseRelocations() const;
+    CHECK CheckILOnlyEntryPoint() const;
+
+    // ------------------------------------------------------------
+    // Instance members
+    // ------------------------------------------------------------
+
+    enum
+    {
+        FLAG_MAPPED             = 0x01, // the file is mapped/hydrated (vs. the raw disk layout)
+        FLAG_CONTENTS           = 0x02, // the file has contents
+        FLAG_RELOCATED          = 0x04, // relocs have been applied
+        FLAG_NT_CHECKED         = 0x10,
+        FLAG_COR_CHECKED        = 0x20,
+        FLAG_IL_ONLY_CHECKED    = 0x40,
+        FLAG_NATIVE_CHECKED     = 0x80,
+
+        FLAG_HAS_NO_READYTORUN_HEADER = 0x100,
+    };
+
+    TADDR               m_base;
+    COUNT_T             m_size;     // size of file on disk, as opposed to OptionalHeaders.SizeOfImage
+    ULONG               m_flags;
+
+    PTR_IMAGE_NT_HEADERS   m_pNTHeaders;
+    PTR_IMAGE_COR20_HEADER m_pCorHeader;
+    PTR_READYTORUN_HEADER  m_pReadyToRunHeader;
+};
+
+//
+//  MethodSectionIterator class is used to iterate hot (or) cold method section in an ngen image.
+//  It can also iterate nibble maps generated by the JIT in a regular HeapList.
+//
+class MethodSectionIterator
+{
+  private:
+    PTR_DWORD m_codeTableStart;
+    PTR_DWORD m_codeTable;
+    PTR_DWORD m_codeTableEnd;
+
+    BYTE *m_code;
+
+    DWORD m_dword;
+    DWORD m_index;
+
+    BYTE *m_current;
+
+  public:
+
+    //If code is a target pointer, then GetMethodCode and FindMethodCode return
+    //target pointers.  codeTable may be a pointer of either type, since it is
+    //converted internally into a host pointer.
+    MethodSectionIterator(const void *code, SIZE_T codeSize,
+                          const void *codeTable, SIZE_T codeTableSize);
+    BOOL Next();
+    BYTE *GetMethodCode() { return m_current; } // Get the start of method code of the current method in the iterator
+};
+
+#include "pedecoder.inl"
+
+#endif  // PEDECODER_H_
diff --git a/src/inc/pedecoder.inl b/src/inc/pedecoder.inl
new file mode 100644 (file)
index 0000000..4433924
--- /dev/null
@@ -0,0 +1,1234 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// --------------------------------------------------------------------------------
+// PEDecoder.inl
+//
+
+// --------------------------------------------------------------------------------
+
+#ifndef _PEDECODER_INL_
+#define _PEDECODER_INL_
+
+#include "pedecoder.h"
+#include "ex.h"
+
+#ifndef DACCESS_COMPILE
+
+inline PEDecoder::PEDecoder()
+  : m_base(0),
+    m_size(0),
+    m_flags(0),
+    m_pNTHeaders(nullptr),
+    m_pCorHeader(nullptr),
+    m_pReadyToRunHeader(nullptr)
+{
+    CONTRACTL
+    {
+        CONSTRUCTOR_CHECK;
+        NOTHROW;
+        CANNOT_TAKE_LOCK;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+}
+#else
+inline PEDecoder::PEDecoder()
+{
+    LIMITED_METHOD_CONTRACT;
+}
+#endif // #ifndef DACCESS_COMPILE
+
+inline PTR_VOID PEDecoder::GetBase() const
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+
+    return PTR_VOID(m_base);
+}
+
+inline BOOL PEDecoder::IsMapped() const
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+
+    return (m_flags & FLAG_MAPPED) != 0;
+}
+
+inline BOOL PEDecoder::IsRelocated() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (m_flags & FLAG_RELOCATED) != 0;
+}
+
+inline void PEDecoder::SetRelocated()
+{
+    m_flags |= FLAG_RELOCATED;
+}
+
+inline BOOL PEDecoder::IsFlat() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return HasContents() && !IsMapped();
+}
+
+inline BOOL PEDecoder::HasContents() const
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+
+    return (m_flags & FLAG_CONTENTS) != 0;
+}
+
+inline COUNT_T PEDecoder::GetSize() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return m_size;
+}
+
+inline PEDecoder::PEDecoder(PTR_VOID mappedBase, bool fixedUp /*= FALSE*/)
+  : m_base(dac_cast<TADDR>(mappedBase)),
+    m_size(0),
+    m_flags(FLAG_MAPPED | FLAG_CONTENTS | FLAG_NT_CHECKED | (fixedUp ? FLAG_RELOCATED : 0)),
+    m_pNTHeaders(nullptr),
+    m_pCorHeader(nullptr),
+    m_pReadyToRunHeader(nullptr)
+{
+    CONTRACTL
+    {
+        CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(mappedBase));
+        PRECONDITION(PEDecoder(mappedBase,fixedUp).CheckNTHeaders());
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    // Temporarily set the size to 2 pages, so we can get the headers.
+    m_size = GetOsPageSize()*2;
+
+    m_pNTHeaders = PTR_IMAGE_NT_HEADERS(FindNTHeaders());
+    if (!m_pNTHeaders)
+        ThrowHR(COR_E_BADIMAGEFORMAT);
+
+    m_size = VAL32(m_pNTHeaders->OptionalHeader.SizeOfImage);
+}
+
+#ifndef DACCESS_COMPILE
+
+//REM
+//what's the right way to do this?
+//we want to use some against TADDR, but also want to do
+//some against what's just in the current process.
+//m_base is a TADDR in DAC all the time, though.
+//Have to implement separate fn to do the lookup??
+inline PEDecoder::PEDecoder(void *flatBase, COUNT_T size)
+  : m_base((TADDR)flatBase),
+    m_size(size),
+    m_flags(FLAG_CONTENTS),
+    m_pNTHeaders(NULL),
+    m_pCorHeader(NULL),
+    m_pReadyToRunHeader(NULL)
+{
+    CONTRACTL
+    {
+        CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(flatBase));
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+    }
+    CONTRACTL_END;
+}
+
+inline void PEDecoder::Init(void *flatBase, COUNT_T size)
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION((size == 0) || CheckPointer(flatBase));
+        PRECONDITION(!HasContents());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    m_base = (TADDR)flatBase;
+    m_size = size;
+    m_flags = FLAG_CONTENTS;
+}
+
+
+
+inline HRESULT PEDecoder::Init(void *mappedBase, bool fixedUp /*= FALSE*/)
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(mappedBase));
+        PRECONDITION(!HasContents());
+    }
+    CONTRACTL_END;
+
+    m_base = (TADDR)mappedBase;
+    m_flags = FLAG_MAPPED | FLAG_CONTENTS;
+    if (fixedUp)
+        m_flags |= FLAG_RELOCATED;
+
+    // Temporarily set the size to 2 pages, so we can get the headers.
+    m_size = GetOsPageSize()*2;
+
+    m_pNTHeaders = FindNTHeaders();
+    if (!m_pNTHeaders)
+        return COR_E_BADIMAGEFORMAT;
+
+    m_size = VAL32(m_pNTHeaders->OptionalHeader.SizeOfImage);
+    return S_OK;
+}
+
+inline void PEDecoder::Reset()
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+    m_base=NULL;
+    m_flags=NULL;
+    m_size=NULL;
+    m_pNTHeaders=NULL;
+    m_pCorHeader=NULL;
+    m_pReadyToRunHeader=NULL;
+}
+#endif // #ifndef DACCESS_COMPILE
+
+
+inline IMAGE_NT_HEADERS32 *PEDecoder::GetNTHeaders32() const
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+    return dac_cast<PTR_IMAGE_NT_HEADERS32>(FindNTHeaders());
+}
+
+inline IMAGE_NT_HEADERS64 *PEDecoder::GetNTHeaders64() const
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+    return dac_cast<PTR_IMAGE_NT_HEADERS64>(FindNTHeaders());
+}
+
+inline BOOL PEDecoder::Has32BitNTHeaders() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(HasNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    return (FindNTHeaders()->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC));
+}
+
+inline const void *PEDecoder::GetHeaders(COUNT_T *pSize) const
+{
+    CONTRACT(const void *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+    }
+    CONTRACT_END;
+
+    //even though some data in OptionalHeader is different for 32 and 64, this field is the same
+    if (pSize != NULL)
+        *pSize = VAL32(FindNTHeaders()->OptionalHeader.SizeOfHeaders);
+
+    RETURN (const void *) m_base;
+}
+
+inline BOOL PEDecoder::IsDll() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    return ((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_DLL)) != 0);
+}
+
+inline BOOL PEDecoder::HasBaseRelocations() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    return ((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) == 0);
+}
+
+inline const void *PEDecoder::GetPreferredBase() const
+{
+    CONTRACT(const void *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+    }
+    CONTRACT_END;
+
+    if (Has32BitNTHeaders())
+        RETURN (const void *) (SIZE_T) VAL32(GetNTHeaders32()->OptionalHeader.ImageBase);
+    else
+        RETURN (const void *) (SIZE_T) VAL64(GetNTHeaders64()->OptionalHeader.ImageBase);
+}
+
+inline COUNT_T PEDecoder::GetVirtualSize() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    //even though some data in OptionalHeader is different for 32 and 64,  this field is the same
+    return VAL32(FindNTHeaders()->OptionalHeader.SizeOfImage);
+}
+
+inline WORD PEDecoder::GetSubsystem() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    //even though some data in OptionalHeader is different for 32 and 64,  this field is the same
+    return VAL16(FindNTHeaders()->OptionalHeader.Subsystem);
+}
+
+inline WORD PEDecoder::GetDllCharacteristics() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    //even though some data in OptionalHeader is different for 32 and 64,  this field is the same
+    return VAL16(FindNTHeaders()->OptionalHeader.DllCharacteristics);
+}
+
+inline DWORD PEDecoder::GetTimeDateStamp() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    return VAL32(FindNTHeaders()->FileHeader.TimeDateStamp);
+}
+
+inline DWORD PEDecoder::GetCheckSum() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    //even though some data in OptionalHeader is different for 32 and 64,  this field is the same
+    return VAL32(FindNTHeaders()->OptionalHeader.CheckSum);
+}
+
+inline DWORD PEDecoder::GetFileAlignment() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    //even though some data in OptionalHeader is different for 32 and 64,  this field is the same
+    return VAL32(FindNTHeaders()->OptionalHeader.FileAlignment);
+}
+
+inline DWORD PEDecoder::GetSectionAlignment() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    //even though some data in OptionalHeader is different for 32 and 64,  this field is the same
+    return VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment);
+}
+
+inline WORD PEDecoder::GetMachine() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    return VAL16(FindNTHeaders()->FileHeader.Machine);
+}
+
+inline WORD PEDecoder::GetCharacteristics() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    return VAL16(FindNTHeaders()->FileHeader.Characteristics);
+}
+
+inline SIZE_T PEDecoder::GetSizeOfStackReserve() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    if (Has32BitNTHeaders())
+        return (SIZE_T) VAL32(GetNTHeaders32()->OptionalHeader.SizeOfStackReserve);
+    else
+        return (SIZE_T) VAL64(GetNTHeaders64()->OptionalHeader.SizeOfStackReserve);
+}
+
+
+inline SIZE_T PEDecoder::GetSizeOfStackCommit() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    if (Has32BitNTHeaders())
+        return (SIZE_T) VAL32(GetNTHeaders32()->OptionalHeader.SizeOfStackCommit);
+    else
+        return (SIZE_T) VAL64(GetNTHeaders64()->OptionalHeader.SizeOfStackCommit);
+}
+
+
+inline SIZE_T PEDecoder::GetSizeOfHeapReserve() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    if (Has32BitNTHeaders())
+        return (SIZE_T) VAL32(GetNTHeaders32()->OptionalHeader.SizeOfHeapReserve);
+    else
+        return (SIZE_T) VAL64(GetNTHeaders64()->OptionalHeader.SizeOfHeapReserve);
+}
+
+
+inline SIZE_T PEDecoder::GetSizeOfHeapCommit() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    if (Has32BitNTHeaders())
+        return (SIZE_T) VAL32(GetNTHeaders32()->OptionalHeader.SizeOfHeapCommit);
+    else
+        return (SIZE_T) VAL64(GetNTHeaders64()->OptionalHeader.SizeOfHeapCommit);
+}
+
+inline UINT32 PEDecoder::GetLoaderFlags() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    if (Has32BitNTHeaders())
+        return VAL32(GetNTHeaders32()->OptionalHeader.LoaderFlags);
+    else
+        return VAL32(GetNTHeaders64()->OptionalHeader.LoaderFlags);
+}
+
+inline UINT32 PEDecoder::GetWin32VersionValue() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    if (Has32BitNTHeaders())
+        return VAL32(GetNTHeaders32()->OptionalHeader.Win32VersionValue);
+    else
+        return VAL32(GetNTHeaders64()->OptionalHeader.Win32VersionValue);
+}
+
+inline COUNT_T PEDecoder::GetNumberOfRvaAndSizes() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    if (Has32BitNTHeaders())
+        return VAL32(GetNTHeaders32()->OptionalHeader.NumberOfRvaAndSizes);
+    else
+        return VAL32(GetNTHeaders64()->OptionalHeader.NumberOfRvaAndSizes);
+}
+
+inline BOOL PEDecoder::HasDirectoryEntry(int entry) const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    if (Has32BitNTHeaders())
+        return (GetNTHeaders32()->OptionalHeader.DataDirectory[entry].VirtualAddress != 0);
+    else
+        return (GetNTHeaders64()->OptionalHeader.DataDirectory[entry].VirtualAddress != 0);
+}
+
+inline IMAGE_DATA_DIRECTORY *PEDecoder::GetDirectoryEntry(int entry) const
+{
+    CONTRACT(IMAGE_DATA_DIRECTORY *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    if (Has32BitNTHeaders())
+        RETURN dac_cast<PTR_IMAGE_DATA_DIRECTORY>(
+            dac_cast<TADDR>(GetNTHeaders32()) +
+            offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory) +
+            entry * sizeof(IMAGE_DATA_DIRECTORY));
+    else
+        RETURN dac_cast<PTR_IMAGE_DATA_DIRECTORY>(
+            dac_cast<TADDR>(GetNTHeaders64()) +
+            offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory) +
+            entry * sizeof(IMAGE_DATA_DIRECTORY));
+}
+
+inline TADDR PEDecoder::GetDirectoryEntryData(int entry, COUNT_T *pSize) const
+{
+    CONTRACT(TADDR)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckDirectoryEntry(entry, 0, NULL_OK));
+        PRECONDITION(CheckPointer(pSize, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer((void *)RETVAL, NULL_OK));
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(entry);
+
+    if (pSize != NULL)
+        *pSize = VAL32(pDir->Size);
+
+    RETURN GetDirectoryData(pDir);
+}
+
+inline TADDR PEDecoder::GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir) const
+{
+    CONTRACT(TADDR)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckDirectory(pDir, 0, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+        POSTCONDITION(CheckPointer((void *)RETVAL, NULL_OK));
+        CANNOT_TAKE_LOCK;
+    }
+    CONTRACT_END;
+
+    RETURN GetRvaData(VAL32(pDir->VirtualAddress));
+}
+
+inline TADDR PEDecoder::GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir, COUNT_T *pSize) const
+{
+    CONTRACT(TADDR)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckDirectory(pDir, 0, NULL_OK));
+        PRECONDITION(CheckPointer(pSize));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+        POSTCONDITION(CheckPointer((void *)RETVAL, NULL_OK));
+        CANNOT_TAKE_LOCK;
+    }
+    CONTRACT_END;
+
+    *pSize = VAL32(pDir->Size);
+
+    RETURN GetRvaData(VAL32(pDir->VirtualAddress));
+}
+
+inline TADDR PEDecoder::GetInternalAddressData(SIZE_T address) const
+{
+    CONTRACT(TADDR)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckInternalAddress(address, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer((void *)RETVAL));
+    }
+    CONTRACT_END;
+
+    RETURN GetRvaData(InternalAddressToRva(address));
+}
+
+inline BOOL PEDecoder::HasCorHeader() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        SUPPORTS_DAC;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    return HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER);
+}
+
+inline BOOL PEDecoder::IsILOnly() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(HasCorHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    // Pretend that ready-to-run images are IL-only
+    return((GetCorHeader()->Flags & VAL32(COMIMAGE_FLAGS_ILONLY)) != 0) || HasReadyToRunHeader();
+}
+
+inline COUNT_T PEDecoder::RvaToOffset(RVA rva) const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckRva(rva,NULL_OK));
+        NOTHROW;
+        CANNOT_TAKE_LOCK;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+    if(rva > 0)
+    {
+        IMAGE_SECTION_HEADER *section = RvaToSection(rva);
+        if (section == NULL)
+            return rva;
+
+        return rva - VAL32(section->VirtualAddress) + VAL32(section->PointerToRawData);
+    }
+    else return 0;
+}
+
+inline RVA PEDecoder::OffsetToRva(COUNT_T fileOffset) const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckOffset(fileOffset,NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+    if(fileOffset > 0)
+    {
+        IMAGE_SECTION_HEADER *section = OffsetToSection(fileOffset);
+        PREFIX_ASSUME (section!=NULL); //TODO: actually it is possible that it si null we need to rethink how we handle this cases and do better there
+
+        return fileOffset - VAL32(section->PointerToRawData) + VAL32(section->VirtualAddress);
+    }
+    else return 0;
+}
+
+
+inline BOOL PEDecoder::IsStrongNameSigned() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(HasCorHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    return ((GetCorHeader()->Flags & VAL32(COMIMAGE_FLAGS_STRONGNAMESIGNED)) != 0);
+}
+
+
+inline BOOL PEDecoder::HasStrongNameSignature() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(HasCorHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    return (GetCorHeader()->StrongNameSignature.VirtualAddress != 0);
+}
+
+inline CHECK PEDecoder::CheckStrongNameSignature() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(HasCorHeader());
+        PRECONDITION(HasStrongNameSignature());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    return CheckDirectory(&GetCorHeader()->StrongNameSignature, IMAGE_SCN_MEM_WRITE, NULL_OK);
+}
+
+inline PTR_CVOID PEDecoder::GetStrongNameSignature(COUNT_T *pSize) const
+{
+    CONTRACT(PTR_CVOID)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(HasCorHeader());
+        PRECONDITION(HasStrongNameSignature());
+        PRECONDITION(CheckStrongNameSignature());
+        PRECONDITION(CheckPointer(pSize, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+    }
+    CONTRACT_END;
+
+    IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->StrongNameSignature;
+
+    if (pSize != NULL)
+        *pSize = VAL32(pDir->Size);
+
+    RETURN dac_cast<PTR_CVOID>(GetDirectoryData(pDir));
+}
+
+inline BOOL PEDecoder::HasTls() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    return HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_TLS);
+}
+
+inline CHECK PEDecoder::CheckTls() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_TLS, 0, NULL_OK));
+
+    IMAGE_TLS_DIRECTORY *pTlsHeader = (IMAGE_TLS_DIRECTORY *) GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_TLS);
+
+    CHECK(CheckUnderflow(VALPTR(pTlsHeader->EndAddressOfRawData), VALPTR(pTlsHeader->StartAddressOfRawData)));
+    CHECK(VALPTR(pTlsHeader->EndAddressOfRawData) - VALPTR(pTlsHeader->StartAddressOfRawData) <= COUNT_T_MAX);
+
+    CHECK(CheckInternalAddress(VALPTR(pTlsHeader->StartAddressOfRawData),
+        (COUNT_T) (VALPTR(pTlsHeader->EndAddressOfRawData) - VALPTR(pTlsHeader->StartAddressOfRawData))));
+
+    CHECK_OK;
+}
+
+inline PTR_VOID PEDecoder::GetTlsRange(COUNT_T * pSize) const
+{
+    CONTRACT(void *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(HasTls());
+        PRECONDITION(CheckTls());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+    }
+    CONTRACT_END;
+
+    IMAGE_TLS_DIRECTORY *pTlsHeader =
+        PTR_IMAGE_TLS_DIRECTORY(GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_TLS));
+
+    if (pSize != 0)
+        *pSize = (COUNT_T) (VALPTR(pTlsHeader->EndAddressOfRawData) - VALPTR(pTlsHeader->StartAddressOfRawData));
+    PREFIX_ASSUME (pTlsHeader!=NULL);
+    RETURN PTR_VOID(GetInternalAddressData(pTlsHeader->StartAddressOfRawData));
+}
+
+inline UINT32 PEDecoder::GetTlsIndex() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(HasTls());
+        PRECONDITION(CheckTls());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    IMAGE_TLS_DIRECTORY *pTlsHeader = (IMAGE_TLS_DIRECTORY *) GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_TLS);
+
+    return (UINT32)*PTR_UINT32(GetInternalAddressData((SIZE_T)VALPTR(pTlsHeader->AddressOfIndex)));
+}
+
+inline IMAGE_COR20_HEADER *PEDecoder::GetCorHeader() const
+{
+    CONTRACT(IMAGE_COR20_HEADER *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(HasCorHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    if (m_pCorHeader == NULL)
+        const_cast<PEDecoder *>(this)->m_pCorHeader =
+            dac_cast<PTR_IMAGE_COR20_HEADER>(FindCorHeader());
+
+    RETURN m_pCorHeader;
+}
+
+inline BOOL PEDecoder::IsNativeMachineFormat() const
+{
+    if (!HasContents() || !HasNTHeaders() )
+        return FALSE;
+    _ASSERTE(m_pNTHeaders);
+    WORD expectedFormat = HasCorHeader() && HasReadyToRunHeader() ?
+        IMAGE_FILE_MACHINE_NATIVE_NI :
+        IMAGE_FILE_MACHINE_NATIVE;
+    //do not call GetNTHeaders as we do not want to bother with PE32->PE32+ conversion
+    return m_pNTHeaders->FileHeader.Machine==expectedFormat;
+}
+
+inline BOOL PEDecoder::IsI386() const
+{
+    if (!HasContents() || !HasNTHeaders() )
+        return FALSE;
+    _ASSERTE(m_pNTHeaders);
+    //do not call GetNTHeaders as we do not want to bother with PE32->PE32+ conversion
+    return m_pNTHeaders->FileHeader.Machine==IMAGE_FILE_MACHINE_I386;
+}
+
+// static
+inline PTR_IMAGE_SECTION_HEADER PEDecoder::FindFirstSection(IMAGE_NT_HEADERS * pNTHeaders)
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+
+    return dac_cast<PTR_IMAGE_SECTION_HEADER>(
+        dac_cast<TADDR>(pNTHeaders) +
+        FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
+        VAL16(pNTHeaders->FileHeader.SizeOfOptionalHeader));
+}
+
+inline COUNT_T PEDecoder::GetNumberOfSections() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    return VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
+}
+
+
+inline DWORD PEDecoder::GetImageIdentity() const
+{
+    WRAPPER_NO_CONTRACT;
+    return GetTimeDateStamp() ^ GetCheckSum() ^ DWORD( GetVirtualSize() );
+}
+
+
+inline PTR_IMAGE_SECTION_HEADER PEDecoder::FindFirstSection() const
+{
+    CONTRACT(IMAGE_SECTION_HEADER *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    RETURN FindFirstSection(FindNTHeaders());
+}
+
+inline IMAGE_NT_HEADERS *PEDecoder::FindNTHeaders() const
+{
+    CONTRACT(IMAGE_NT_HEADERS *)
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    RETURN PTR_IMAGE_NT_HEADERS(m_base + VAL32(PTR_IMAGE_DOS_HEADER(m_base)->e_lfanew));
+}
+
+inline IMAGE_COR20_HEADER *PEDecoder::FindCorHeader() const
+{
+    CONTRACT(IMAGE_COR20_HEADER *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(HasCorHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    const IMAGE_COR20_HEADER * pCor=PTR_IMAGE_COR20_HEADER(GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_COMHEADER));
+    RETURN ((IMAGE_COR20_HEADER*)pCor);
+}
+
+inline CHECK PEDecoder::CheckBounds(RVA rangeBase, COUNT_T rangeSize, RVA rva)
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+    CHECK(CheckOverflow(rangeBase, rangeSize));
+    CHECK(rva >= rangeBase);
+    CHECK(rva <= rangeBase + rangeSize);
+    CHECK_OK;
+}
+
+inline CHECK PEDecoder::CheckBounds(RVA rangeBase, COUNT_T rangeSize, RVA rva, COUNT_T size)
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+    CHECK(CheckOverflow(rangeBase, rangeSize));
+    CHECK(CheckOverflow(rva, size));
+    CHECK(rva >= rangeBase);
+    CHECK(rva + size <= rangeBase + rangeSize);
+    CHECK_OK;
+}
+
+inline CHECK PEDecoder::CheckBounds(const void *rangeBase, COUNT_T rangeSize, const void *pointer)
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+    CHECK(CheckOverflow(dac_cast<PTR_CVOID>(rangeBase), rangeSize));
+    CHECK(dac_cast<TADDR>(pointer) >= dac_cast<TADDR>(rangeBase));
+    CHECK(dac_cast<TADDR>(pointer) <= dac_cast<TADDR>(rangeBase) + rangeSize);
+    CHECK_OK;
+}
+
+inline CHECK PEDecoder::CheckBounds(PTR_CVOID rangeBase, COUNT_T rangeSize, PTR_CVOID pointer, COUNT_T size)
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+    CHECK(CheckOverflow(rangeBase, rangeSize));
+    CHECK(CheckOverflow(pointer, size));
+    CHECK(dac_cast<TADDR>(pointer) >= dac_cast<TADDR>(rangeBase));
+    CHECK(dac_cast<TADDR>(pointer) + size <= dac_cast<TADDR>(rangeBase) + rangeSize);
+    CHECK_OK;
+}
+
+inline void PEDecoder::GetPEKindAndMachine(DWORD * pdwPEKind, DWORD *pdwMachine)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    DWORD dwKind=0,dwMachine=0;
+    if(HasContents() && HasNTHeaders())
+    {
+        dwMachine = GetMachine();
+
+        BOOL fIsPE32Plus = !Has32BitNTHeaders();
+
+        if (fIsPE32Plus)
+            dwKind |= (DWORD)pe32Plus;
+
+        if (HasCorHeader())
+        {
+            IMAGE_COR20_HEADER * pCorHdr = GetCorHeader();
+            if(pCorHdr != NULL)
+            {
+                DWORD dwCorFlags = pCorHdr->Flags;
+
+                if (dwCorFlags & VAL32(COMIMAGE_FLAGS_ILONLY))
+                {
+                    dwKind |= (DWORD)peILonly;
+#ifdef HOST_64BIT
+                    // compensate for shim promotion of PE32/ILONLY headers to PE32+ on WIN64
+                    if (fIsPE32Plus && (GetMachine() == IMAGE_FILE_MACHINE_I386))
+                        dwKind &= ~((DWORD)pe32Plus);
+#endif
+                }
+
+                if (COR_IS_32BIT_REQUIRED(dwCorFlags))
+                    dwKind |= (DWORD)pe32BitRequired;
+                else if (COR_IS_32BIT_PREFERRED(dwCorFlags))
+                    dwKind |= (DWORD)pe32BitPreferred;
+
+                // compensate for MC++ peculiarity
+                if(dwKind == 0)
+                    dwKind = (DWORD)pe32BitRequired;
+            }
+            else
+            {
+                dwKind |= (DWORD)pe32Unmanaged;
+            }
+
+            if (HasReadyToRunHeader())
+            {
+                if (dwMachine == IMAGE_FILE_MACHINE_NATIVE_NI)
+                {
+                    // Supply the original machine type to the assembly binder
+                    dwMachine = IMAGE_FILE_MACHINE_NATIVE;
+                }
+
+                if ((GetReadyToRunHeader()->CoreHeader.Flags & READYTORUN_FLAG_PLATFORM_NEUTRAL_SOURCE) != 0)
+                {
+                    // Supply the original PEKind/Machine to the assembly binder to make the full assembly name look like the original
+                    dwKind = peILonly;
+                    dwMachine = IMAGE_FILE_MACHINE_I386;
+                }
+            }
+        }
+        else
+        {
+            dwKind |= (DWORD)pe32Unmanaged;
+        }
+    }
+
+    *pdwPEKind = dwKind;
+    *pdwMachine = dwMachine;
+}
+
+inline BOOL PEDecoder::IsPlatformNeutral()
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    DWORD dwKind, dwMachine;
+    GetPEKindAndMachine(&dwKind, &dwMachine);
+    return ((dwKind & (peILonly | pe32Plus | pe32BitRequired)) == peILonly) && (dwMachine == IMAGE_FILE_MACHINE_I386);
+}
+
+inline BOOL PEDecoder::IsComponentAssembly() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    return HasReadyToRunHeader() && (m_pReadyToRunHeader->CoreHeader.Flags & READYTORUN_FLAG_COMPONENT) != 0;
+}
+
+inline BOOL PEDecoder::HasReadyToRunHeader() const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    if (m_flags & FLAG_HAS_NO_READYTORUN_HEADER)
+        return FALSE;
+
+    if (m_pReadyToRunHeader != NULL)
+        return TRUE;
+
+    return FindReadyToRunHeader() != NULL;
+}
+
+inline READYTORUN_HEADER * PEDecoder::GetReadyToRunHeader() const
+{
+    CONTRACT(READYTORUN_HEADER *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(HasCorHeader());
+        PRECONDITION(HasReadyToRunHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL));
+        SUPPORTS_DAC;
+        CANNOT_TAKE_LOCK;
+    }
+    CONTRACT_END;
+
+    if (m_pReadyToRunHeader != NULL)
+        RETURN m_pReadyToRunHeader;
+
+    RETURN FindReadyToRunHeader();
+}
+
+#endif // _PEDECODER_INL_
diff --git a/src/inc/readytorun.h b/src/inc/readytorun.h
new file mode 100644 (file)
index 0000000..25bd45d
--- /dev/null
@@ -0,0 +1,429 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+// readytorun.h
+//
+
+//
+// Contains definitions for the Ready to Run file format
+//
+
+#ifndef __READYTORUN_H__
+#define __READYTORUN_H__
+
+#define READYTORUN_SIGNATURE 0x00525452 // 'RTR'
+
+// Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
+#define READYTORUN_MAJOR_VERSION 0x0006
+#define READYTORUN_MINOR_VERSION 0x0000
+
+#define MINIMUM_READYTORUN_MAJOR_VERSION 0x006
+
+// R2R Version 2.1 adds the InliningInfo section
+// R2R Version 2.2 adds the ProfileDataInfo section
+// R2R Version 3.0 changes calling conventions to correctly handle explicit structures to spec.
+//     R2R 3.0 is not backward compatible with 2.x.
+// R2R Version 6.0 changes managed layout for sequential types with any unmanaged non-blittable fields.
+//     R2R 6.0 is not backward compatible with 5.x or earlier.
+
+struct READYTORUN_CORE_HEADER
+{
+    DWORD                   Flags;          // READYTORUN_FLAG_XXX
+
+    DWORD                   NumberOfSections;
+
+    // Array of sections follows. The array entries are sorted by Type
+    // READYTORUN_SECTION   Sections[];
+};
+
+struct READYTORUN_HEADER
+{
+    DWORD                   Signature;      // READYTORUN_SIGNATURE
+    USHORT                  MajorVersion;   // READYTORUN_VERSION_XXX
+    USHORT                  MinorVersion;
+
+    READYTORUN_CORE_HEADER  CoreHeader;
+};
+
+struct READYTORUN_COMPONENT_ASSEMBLIES_ENTRY
+{
+    IMAGE_DATA_DIRECTORY CorHeader;
+    IMAGE_DATA_DIRECTORY ReadyToRunCoreHeader;
+};
+
+enum ReadyToRunFlag
+{
+    READYTORUN_FLAG_PLATFORM_NEUTRAL_SOURCE     = 0x00000001,   // Set if the original IL assembly was platform-neutral
+    READYTORUN_FLAG_SKIP_TYPE_VALIDATION        = 0x00000002,   // Set of methods with native code was determined using profile data
+    READYTORUN_FLAG_PARTIAL                     = 0x00000004,
+    READYTORUN_FLAG_NONSHARED_PINVOKE_STUBS     = 0x00000008,   // PInvoke stubs compiled into image are non-shareable (no secret parameter)
+    READYTORUN_FLAG_EMBEDDED_MSIL               = 0x00000010,   // MSIL is embedded in the composite R2R executable
+    READYTORUN_FLAG_COMPONENT                   = 0x00000020,   // This is the header describing a component assembly of composite R2R
+};
+
+enum class ReadyToRunSectionType : uint32_t
+{
+    CompilerIdentifier          = 100,
+    ImportSections              = 101,
+    RuntimeFunctions            = 102,
+    MethodDefEntryPoints        = 103,
+    ExceptionInfo               = 104,
+    DebugInfo                   = 105,
+    DelayLoadMethodCallThunks   = 106,
+    // 107 used by an older format of AvailableTypes
+    AvailableTypes              = 108,
+    InstanceMethodEntryPoints   = 109,
+    InliningInfo                = 110, // Added in V2.1, deprecated in 4.1
+    ProfileDataInfo             = 111, // Added in V2.2
+    ManifestMetadata            = 112, // Added in V2.3
+    AttributePresence           = 113, // Added in V3.1
+    InliningInfo2               = 114, // Added in V4.1
+    ComponentAssemblies         = 115, // Added in V4.1
+    OwnerCompositeExecutable    = 116, // Added in V4.1
+    PgoInstrumentationData      = 117, // Added in V5.2
+    ManifestAssemblyMvids       = 118, // Added in V5.3
+
+    // If you add a new section consider whether it is a breaking or non-breaking change.
+    // Usually it is non-breaking, but if it is preferable to have older runtimes fail
+    // to load the image vs. ignoring the new section it could be marked breaking.
+    // Increment the READYTORUN_MINOR_VERSION (non-breaking) or READYTORUN_MAJOR_VERSION
+    // (breaking) as appropriate.
+};
+
+struct READYTORUN_SECTION
+{
+    ReadyToRunSectionType   Type;           // READYTORUN_SECTION_XXX
+    IMAGE_DATA_DIRECTORY    Section;
+};
+
+//
+// READYTORUN_IMPORT_SECTION describes image range with references to code or runtime data structures
+//
+// There is number of different types of these ranges: eagerly initialized at image load vs. lazily initialized at method entry
+// vs. lazily initialized on first use; handles vs. code pointers, etc.
+//
+struct READYTORUN_IMPORT_SECTION
+{
+    IMAGE_DATA_DIRECTORY    Section;            // Section containing values to be fixed up
+    USHORT                  Flags;              // One or more of ReadyToRunImportSectionFlags
+    BYTE                    Type;               // One of ReadyToRunImportSectionType
+    BYTE                    EntrySize;
+    DWORD                   Signatures;         // RVA of optional signature descriptors
+    DWORD                   AuxiliaryData;      // RVA of optional auxiliary data (typically GC info)
+};
+
+enum ReadyToRunImportSectionType
+{
+    READYTORUN_IMPORT_SECTION_TYPE_UNKNOWN   = 0,
+};
+
+enum ReadyToRunImportSectionFlags
+{
+    READYTORUN_IMPORT_SECTION_FLAGS_EAGER    = 0x0001,
+};
+
+//
+// Constants for method and field encoding
+//
+
+enum ReadyToRunMethodSigFlags
+{
+    READYTORUN_METHOD_SIG_UnboxingStub          = 0x01,
+    READYTORUN_METHOD_SIG_InstantiatingStub     = 0x02,
+    READYTORUN_METHOD_SIG_MethodInstantiation   = 0x04,
+    READYTORUN_METHOD_SIG_SlotInsteadOfToken    = 0x08,
+    READYTORUN_METHOD_SIG_MemberRefToken        = 0x10,
+    READYTORUN_METHOD_SIG_Constrained           = 0x20,
+    READYTORUN_METHOD_SIG_OwnerType             = 0x40,
+    READYTORUN_METHOD_SIG_UpdateContext         = 0x80,
+};
+
+enum ReadyToRunFieldSigFlags
+{
+    READYTORUN_FIELD_SIG_IndexInsteadOfToken    = 0x08,
+    READYTORUN_FIELD_SIG_MemberRefToken         = 0x10,
+    READYTORUN_FIELD_SIG_OwnerType              = 0x40,
+};
+
+enum ReadyToRunTypeLayoutFlags
+{
+    READYTORUN_LAYOUT_HFA                       = 0x01,
+    READYTORUN_LAYOUT_Alignment                 = 0x02,
+    READYTORUN_LAYOUT_Alignment_Native          = 0x04,
+    READYTORUN_LAYOUT_GCLayout                  = 0x08,
+    READYTORUN_LAYOUT_GCLayout_Empty            = 0x10,
+};
+
+enum ReadyToRunVirtualFunctionOverrideFlags
+{
+    READYTORUN_VIRTUAL_OVERRIDE_None = 0x00,
+    READYTORUN_VIRTUAL_OVERRIDE_VirtualFunctionOverriden = 0x01,
+};
+
+//
+// Constants for fixup signature encoding
+//
+
+enum ReadyToRunFixupKind
+{
+    READYTORUN_FIXUP_ThisObjDictionaryLookup    = 0x07,
+    READYTORUN_FIXUP_TypeDictionaryLookup       = 0x08,
+    READYTORUN_FIXUP_MethodDictionaryLookup     = 0x09,
+
+    READYTORUN_FIXUP_TypeHandle                 = 0x10,
+    READYTORUN_FIXUP_MethodHandle               = 0x11,
+    READYTORUN_FIXUP_FieldHandle                = 0x12,
+
+    READYTORUN_FIXUP_MethodEntry                = 0x13, /* For calling a method entry point */
+    READYTORUN_FIXUP_MethodEntry_DefToken       = 0x14, /* Smaller version of MethodEntry - method is def token */
+    READYTORUN_FIXUP_MethodEntry_RefToken       = 0x15, /* Smaller version of MethodEntry - method is ref token */
+
+    READYTORUN_FIXUP_VirtualEntry               = 0x16, /* For invoking a virtual method */
+    READYTORUN_FIXUP_VirtualEntry_DefToken      = 0x17, /* Smaller version of VirtualEntry - method is def token */
+    READYTORUN_FIXUP_VirtualEntry_RefToken      = 0x18, /* Smaller version of VirtualEntry - method is ref token */
+    READYTORUN_FIXUP_VirtualEntry_Slot          = 0x19, /* Smaller version of VirtualEntry - type & slot */
+
+    READYTORUN_FIXUP_Helper                     = 0x1A, /* Helper */
+    READYTORUN_FIXUP_StringHandle               = 0x1B, /* String handle */
+
+    READYTORUN_FIXUP_NewObject                  = 0x1C, /* Dynamically created new helper */
+    READYTORUN_FIXUP_NewArray                   = 0x1D,
+
+    READYTORUN_FIXUP_IsInstanceOf               = 0x1E, /* Dynamically created casting helper */
+    READYTORUN_FIXUP_ChkCast                    = 0x1F,
+
+    READYTORUN_FIXUP_FieldAddress               = 0x20, /* For accessing a cross-module static fields */
+    READYTORUN_FIXUP_CctorTrigger               = 0x21, /* Static constructor trigger */
+
+    READYTORUN_FIXUP_StaticBaseNonGC            = 0x22, /* Dynamically created static base helpers */
+    READYTORUN_FIXUP_StaticBaseGC               = 0x23,
+    READYTORUN_FIXUP_ThreadStaticBaseNonGC      = 0x24,
+    READYTORUN_FIXUP_ThreadStaticBaseGC         = 0x25,
+
+    READYTORUN_FIXUP_FieldBaseOffset            = 0x26, /* Field base offset */
+    READYTORUN_FIXUP_FieldOffset                = 0x27, /* Field offset */
+
+    READYTORUN_FIXUP_TypeDictionary             = 0x28,
+    READYTORUN_FIXUP_MethodDictionary           = 0x29,
+
+    READYTORUN_FIXUP_Check_TypeLayout           = 0x2A, /* size, alignment, HFA, reference map */
+    READYTORUN_FIXUP_Check_FieldOffset          = 0x2B,
+
+    READYTORUN_FIXUP_DelegateCtor               = 0x2C, /* optimized delegate ctor */
+    READYTORUN_FIXUP_DeclaringTypeHandle        = 0x2D,
+
+    READYTORUN_FIXUP_IndirectPInvokeTarget      = 0x2E, /* Target (indirect) of an inlined pinvoke */
+    READYTORUN_FIXUP_PInvokeTarget              = 0x2F, /* Target of an inlined pinvoke */
+
+    READYTORUN_FIXUP_Check_InstructionSetSupport= 0x30, /* Define the set of instruction sets that must be supported/unsupported to use the fixup */
+
+    READYTORUN_FIXUP_Verify_FieldOffset         = 0x31, /* Generate a runtime check to ensure that the field offset matches between compile and runtime. Unlike Check_FieldOffset, this will generate a runtime failure instead of silently dropping the method */
+    READYTORUN_FIXUP_Verify_TypeLayout          = 0x32, /* Generate a runtime check to ensure that the type layout (size, alignment, HFA, reference map) matches between compile and runtime. Unlike Check_TypeLayout, this will generate a runtime failure instead of silently dropping the method */
+
+    READYTORUN_FIXUP_Check_VirtualFunctionOverride = 0x33, /* Generate a runtime check to ensure that virtual function resolution has equivalent behavior at runtime as at compile time. If not equivalent, code will not be used */
+    READYTORUN_FIXUP_Verify_VirtualFunctionOverride = 0x34, /* Generate a runtime check to ensure that virtual function resolution has equivalent behavior at runtime as at compile time. If not equivalent, generate runtime failure. */
+};
+
+//
+// Intrinsics and helpers
+//
+
+enum ReadyToRunHelper
+{
+    READYTORUN_HELPER_Invalid                   = 0x00,
+
+    // Not a real helper - handle to current module passed to delay load helpers.
+    READYTORUN_HELPER_Module                    = 0x01,
+    READYTORUN_HELPER_GSCookie                  = 0x02,
+    READYTORUN_HELPER_IndirectTrapThreads       = 0x03,
+
+    //
+    // Delay load helpers
+    //
+
+    // All delay load helpers use custom calling convention:
+    // - scratch register - address of indirection cell. 0 = address is inferred from callsite.
+    // - stack - section index, module handle
+    READYTORUN_HELPER_DelayLoad_MethodCall      = 0x08,
+
+    READYTORUN_HELPER_DelayLoad_Helper          = 0x10,
+    READYTORUN_HELPER_DelayLoad_Helper_Obj      = 0x11,
+    READYTORUN_HELPER_DelayLoad_Helper_ObjObj   = 0x12,
+
+    // JIT helpers
+
+    // Exception handling helpers
+    READYTORUN_HELPER_Throw                     = 0x20,
+    READYTORUN_HELPER_Rethrow                   = 0x21,
+    READYTORUN_HELPER_Overflow                  = 0x22,
+    READYTORUN_HELPER_RngChkFail                = 0x23,
+    READYTORUN_HELPER_FailFast                  = 0x24,
+    READYTORUN_HELPER_ThrowNullRef              = 0x25,
+    READYTORUN_HELPER_ThrowDivZero              = 0x26,
+
+    // Write barriers
+    READYTORUN_HELPER_WriteBarrier              = 0x30,
+    READYTORUN_HELPER_CheckedWriteBarrier       = 0x31,
+    READYTORUN_HELPER_ByRefWriteBarrier         = 0x32,
+
+    // Array helpers
+    READYTORUN_HELPER_Stelem_Ref                = 0x38,
+    READYTORUN_HELPER_Ldelema_Ref               = 0x39,
+
+    READYTORUN_HELPER_MemSet                    = 0x40,
+    READYTORUN_HELPER_MemCpy                    = 0x41,
+
+    // PInvoke helpers
+    READYTORUN_HELPER_PInvokeBegin              = 0x42,
+    READYTORUN_HELPER_PInvokeEnd                = 0x43,
+    READYTORUN_HELPER_GCPoll                    = 0x44,
+    READYTORUN_HELPER_ReversePInvokeEnter       = 0x45,
+    READYTORUN_HELPER_ReversePInvokeExit        = 0x46,
+
+    // Get string handle lazily
+    READYTORUN_HELPER_GetString                 = 0x50,
+
+    // Used by /Tuning for Profile optimizations
+    READYTORUN_HELPER_LogMethodEnter            = 0x51,
+
+    // Reflection helpers
+    READYTORUN_HELPER_GetRuntimeTypeHandle      = 0x54,
+    READYTORUN_HELPER_GetRuntimeMethodHandle    = 0x55,
+    READYTORUN_HELPER_GetRuntimeFieldHandle     = 0x56,
+
+    READYTORUN_HELPER_Box                       = 0x58,
+    READYTORUN_HELPER_Box_Nullable              = 0x59,
+    READYTORUN_HELPER_Unbox                     = 0x5A,
+    READYTORUN_HELPER_Unbox_Nullable            = 0x5B,
+    READYTORUN_HELPER_NewMultiDimArr            = 0x5C,
+
+    // Helpers used with generic handle lookup cases
+    READYTORUN_HELPER_NewObject                 = 0x60,
+    READYTORUN_HELPER_NewArray                  = 0x61,
+    READYTORUN_HELPER_CheckCastAny              = 0x62,
+    READYTORUN_HELPER_CheckInstanceAny          = 0x63,
+    READYTORUN_HELPER_GenericGcStaticBase       = 0x64,
+    READYTORUN_HELPER_GenericNonGcStaticBase    = 0x65,
+    READYTORUN_HELPER_GenericGcTlsBase          = 0x66,
+    READYTORUN_HELPER_GenericNonGcTlsBase       = 0x67,
+    READYTORUN_HELPER_VirtualFuncPtr            = 0x68,
+
+    // Long mul/div/shift ops
+    READYTORUN_HELPER_LMul                      = 0xC0,
+    READYTORUN_HELPER_LMulOfv                   = 0xC1,
+    READYTORUN_HELPER_ULMulOvf                  = 0xC2,
+    READYTORUN_HELPER_LDiv                      = 0xC3,
+    READYTORUN_HELPER_LMod                      = 0xC4,
+    READYTORUN_HELPER_ULDiv                     = 0xC5,
+    READYTORUN_HELPER_ULMod                     = 0xC6,
+    READYTORUN_HELPER_LLsh                      = 0xC7,
+    READYTORUN_HELPER_LRsh                      = 0xC8,
+    READYTORUN_HELPER_LRsz                      = 0xC9,
+    READYTORUN_HELPER_Lng2Dbl                   = 0xCA,
+    READYTORUN_HELPER_ULng2Dbl                  = 0xCB,
+
+    // 32-bit division helpers
+    READYTORUN_HELPER_Div                       = 0xCC,
+    READYTORUN_HELPER_Mod                       = 0xCD,
+    READYTORUN_HELPER_UDiv                      = 0xCE,
+    READYTORUN_HELPER_UMod                      = 0xCF,
+
+    // Floating point conversions
+    READYTORUN_HELPER_Dbl2Int                   = 0xD0,
+    READYTORUN_HELPER_Dbl2IntOvf                = 0xD1,
+    READYTORUN_HELPER_Dbl2Lng                   = 0xD2,
+    READYTORUN_HELPER_Dbl2LngOvf                = 0xD3,
+    READYTORUN_HELPER_Dbl2UInt                  = 0xD4,
+    READYTORUN_HELPER_Dbl2UIntOvf               = 0xD5,
+    READYTORUN_HELPER_Dbl2ULng                  = 0xD6,
+    READYTORUN_HELPER_Dbl2ULngOvf               = 0xD7,
+
+    // Floating point ops
+    READYTORUN_HELPER_DblRem                    = 0xE0,
+    READYTORUN_HELPER_FltRem                    = 0xE1,
+    READYTORUN_HELPER_DblRound                  = 0xE2,
+    READYTORUN_HELPER_FltRound                  = 0xE3,
+
+#ifdef FEATURE_EH_FUNCLETS
+    // Personality rountines
+    READYTORUN_HELPER_PersonalityRoutine        = 0xF0,
+    READYTORUN_HELPER_PersonalityRoutineFilterFunclet = 0xF1,
+#endif
+
+    // Synchronized methods
+    READYTORUN_HELPER_MonitorEnter              = 0xF8,
+    READYTORUN_HELPER_MonitorExit               = 0xF9,
+
+    //
+    // Deprecated/legacy
+    //
+
+    // JIT32 x86-specific write barriers
+    READYTORUN_HELPER_WriteBarrier_EAX          = 0x100,
+    READYTORUN_HELPER_WriteBarrier_EBX          = 0x101,
+    READYTORUN_HELPER_WriteBarrier_ECX          = 0x102,
+    READYTORUN_HELPER_WriteBarrier_ESI          = 0x103,
+    READYTORUN_HELPER_WriteBarrier_EDI          = 0x104,
+    READYTORUN_HELPER_WriteBarrier_EBP          = 0x105,
+    READYTORUN_HELPER_CheckedWriteBarrier_EAX   = 0x106,
+    READYTORUN_HELPER_CheckedWriteBarrier_EBX   = 0x107,
+    READYTORUN_HELPER_CheckedWriteBarrier_ECX   = 0x108,
+    READYTORUN_HELPER_CheckedWriteBarrier_ESI   = 0x109,
+    READYTORUN_HELPER_CheckedWriteBarrier_EDI   = 0x10A,
+    READYTORUN_HELPER_CheckedWriteBarrier_EBP   = 0x10B,
+
+    // JIT32 x86-specific exception handling
+    READYTORUN_HELPER_EndCatch                  = 0x110,
+
+    // Stack probing helper
+    READYTORUN_HELPER_StackProbe                = 0x111,
+
+    READYTORUN_HELPER_GetCurrentManagedThreadId = 0x112,
+};
+
+#include "readytoruninstructionset.h"
+
+//
+// Exception info
+//
+
+struct READYTORUN_EXCEPTION_LOOKUP_TABLE_ENTRY
+{
+    DWORD MethodStart;
+    DWORD ExceptionInfo;
+};
+
+struct READYTORUN_EXCEPTION_CLAUSE
+{
+    CorExceptionFlag    Flags;
+    DWORD               TryStartPC;
+    DWORD               TryEndPC;
+    DWORD               HandlerStartPC;
+    DWORD               HandlerEndPC;
+    union {
+        mdToken         ClassToken;
+        DWORD           FilterOffset;
+    };
+};
+
+enum ReadyToRunRuntimeConstants : DWORD
+{
+    READYTORUN_PInvokeTransitionFrameSizeInPointerUnits = 11,
+#ifdef TARGET_X86
+    READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits = 5,
+#else
+    READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits = 2,
+#endif
+};
+
+enum ReadyToRunHFAElemType : DWORD
+{
+    READYTORUN_HFA_ELEMTYPE_None = 0,
+    READYTORUN_HFA_ELEMTYPE_Float32 = 1,
+    READYTORUN_HFA_ELEMTYPE_Float64 = 2,
+    READYTORUN_HFA_ELEMTYPE_Vector64 = 3,
+    READYTORUN_HFA_ELEMTYPE_Vector128 = 4,
+};
+
+#endif // __READYTORUN_H__
diff --git a/src/inc/readytoruninstructionset.h b/src/inc/readytoruninstructionset.h
new file mode 100644 (file)
index 0000000..1b66c6e
--- /dev/null
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED
+// FROM /src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt
+// using /src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.bat
+
+#ifndef READYTORUNINSTRUCTIONSET_H
+#define READYTORUNINSTRUCTIONSET_H
+enum ReadyToRunInstructionSet
+{
+    READYTORUN_INSTRUCTION_Sse=1,
+    READYTORUN_INSTRUCTION_Sse2=2,
+    READYTORUN_INSTRUCTION_Sse3=3,
+    READYTORUN_INSTRUCTION_Ssse3=4,
+    READYTORUN_INSTRUCTION_Sse41=5,
+    READYTORUN_INSTRUCTION_Sse42=6,
+    READYTORUN_INSTRUCTION_Avx=7,
+    READYTORUN_INSTRUCTION_Avx2=8,
+    READYTORUN_INSTRUCTION_Aes=9,
+    READYTORUN_INSTRUCTION_Bmi1=10,
+    READYTORUN_INSTRUCTION_Bmi2=11,
+    READYTORUN_INSTRUCTION_Fma=12,
+    READYTORUN_INSTRUCTION_Lzcnt=13,
+    READYTORUN_INSTRUCTION_Pclmulqdq=14,
+    READYTORUN_INSTRUCTION_Popcnt=15,
+    READYTORUN_INSTRUCTION_ArmBase=16,
+    READYTORUN_INSTRUCTION_AdvSimd=17,
+    READYTORUN_INSTRUCTION_Crc32=18,
+    READYTORUN_INSTRUCTION_Sha1=19,
+    READYTORUN_INSTRUCTION_Sha256=20,
+    READYTORUN_INSTRUCTION_Atomics=21,
+    READYTORUN_INSTRUCTION_X86Base=22,
+    READYTORUN_INSTRUCTION_Dp=23,
+    READYTORUN_INSTRUCTION_Rdm=24,
+    READYTORUN_INSTRUCTION_AvxVnni=25,
+
+};
+
+#endif // READYTORUNINSTRUCTIONSET_H
diff --git a/src/inc/registrywrapper.h b/src/inc/registrywrapper.h
new file mode 100644 (file)
index 0000000..8504d9f
--- /dev/null
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// File: registrywrapper.h
+//
+// Wrapper around Win32 Registry Functions allowing redirection of .NET
+// Framework root registry location
+//
+//*****************************************************************************
+#ifndef __REGISTRYWRAPPER_H
+#define __REGISTRYWRAPPER_H
+
+
+#define ClrRegCreateKeyEx RegCreateKeyExW
+#define ClrRegOpenKeyEx RegOpenKeyExW
+#define IsNgenOffline() false
+
+
+#endif // __REGISTRYWRAPPER_H
diff --git a/src/inc/resource.h b/src/inc/resource.h
new file mode 100644 (file)
index 0000000..7a8f148
--- /dev/null
@@ -0,0 +1,595 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//{{NO_DEPENDENCIES}}
+// Used by mscorrc.rc
+//
+
+
+// For (failing) hresults of facility FACILITY_URT, we store
+// unparameterized description strings in the range
+// 0x6000..0x9000.
+#define MSG_FOR_URT_HR(hr) (0x6000 + (HRESULT_CODE(hr)))
+#define MAX_URT_HRESULT_CODE 0x3000
+
+#define HR_FOR_URT_MSG(code) (((code) >=0x6000 && (code) <= 0x6000+MAX_URT_HRESULT_CODE) ? \
+                                 MAKE_HRESULT(SEVERITY_ERROR, FACILITY_URT, (code) - 0x6000) : \
+                                 (code))
+
+#ifndef HRESULT_CODE
+#define HRESULT_CODE(hr)    ((hr) & 0xFFFF)
+#endif // HRESULT_CODE
+
+
+//-----------------------------------------------------------------------------
+// Resource strings for MDA descriptions.
+//-----------------------------------------------------------------------------
+
+#define MDARC_DEBUGGER_FIBER_MODE_NOT_SUPPORTED 0x1934
+
+#define IDS_RTL                                 0x01F5
+
+#define IDS_DS_ACTIVESESSIONS                   0x1701
+#define IDS_DS_DATASOURCENAME                   0x1702
+#define IDS_DS_DATASOURCEREADONLY               0x1703
+#define IDS_DS_DBMSNAME                         0x1704
+#define IDS_DS_DBMSVER                          0x1705
+#define IDS_DS_IDENTIFIERCASE                   0x1706
+#define IDS_DS_DSOTHREADMODEL                   0x1707
+
+#define IDS_EE_NDIRECT_UNSUPPORTED_SIG          0x1708
+#define IDS_EE_NDIRECT_BADNATL                  0x170a
+#define IDS_EE_NDIRECT_LOADLIB_WIN              0x170b
+#define IDS_EE_NDIRECT_GETPROCADDRESS_WIN       0x170c
+#define IDS_EE_COM_UNSUPPORTED_SIG              0x170d
+#define IDS_EE_NOSYNCHRONIZED                   0x170f
+#define IDS_EE_NDIRECT_BADNATL_THISCALL         0x1710
+#define IDS_EE_MULTIPLE_CALLCONV_UNSUPPORTED    0x1711
+
+#define IDS_EE_LOAD_BAD_MAIN_SIG                0x1712
+#define IDS_EE_COM_UNSUPPORTED_TYPE             0x1713
+
+#define IDS_EE_NOTNDIRECT                       0x1719
+#define IDS_EE_RETHROW_NOT_ALLOWED              0x171d
+#define IDS_EE_INVALID_OLE_VARIANT              0x171e
+
+#define IDS_EE_FILE_NOT_FOUND                   0x80070002
+#define IDS_EE_PATH_TOO_LONG                    0x8007006F
+#define IDS_EE_PROC_NOT_FOUND                   0x8007007F
+#define IDS_EE_ALREADY_EXISTS                   0x800700B7
+#define IDS_EE_BAD_USER_PROFILE                 0x800704E5
+#define IDS_INET_E_CANNOT_CONNECT               0x1799 // 0x800C0004
+#define IDS_INET_E_RESOURCE_NOT_FOUND           0x1a60 // 0x800C0005
+#define IDS_INET_E_CONNECTION_TIMEOUT           0x1a1e // 0x800C000B
+#define IDS_INET_E_SECURITY_PROBLEM             0x800C000E
+
+#define IDS_EE_TO_MANY_ARGUMENTS_IN_MAIN        0x1721
+#define IDS_EE_FAILED_TO_FIND_MAIN              0x1722
+#define IDS_EE_ILLEGAL_TOKEN_FOR_MAIN           0x1723
+#define IDS_EE_MAIN_METHOD_MUST_BE_STATIC       0x1724
+#define IDS_EE_MAIN_METHOD_HAS_INVALID_RTN      0x1725
+#define IDS_EE_VTABLECALLSNOTSUPPORTED          0x1726
+
+#define IDS_EE_BADMARSHALFIELD_STRING           0x1727
+#define IDS_EE_BADMARSHALFIELD_NOCUSTOMMARSH    0x1728
+#define IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE 0x172a
+#define IDS_EE_BADMARSHALFIELD_LAYOUTCLASS      0x172b
+#define IDS_EE_BADMARSHALFIELD_ARRAY            0x172c
+
+#define IDS_EE_BADMARSHALPARAM_NO_LPTSTR        0x172d
+
+#define IDS_EE_SAFEARRAYTYPEMISMATCH            0x1738
+#define IDS_EE_SAFEARRAYRANKMISMATCH            0x1739
+#define IDS_EE_BADMARSHAL_GENERIC               0x173a
+#define IDS_EE_BADMARSHAL_CHAR                  0x173b
+#define IDS_EE_BADMARSHAL_BOOLEAN               0x173c
+#define IDS_EE_BADMARSHAL_I1                    0x173d
+#define IDS_EE_BADMARSHAL_I2                    0x173e
+#define IDS_EE_BADMARSHAL_I4                    0x173f
+#define IDS_EE_BADMARSHAL_I8                    0x1740
+#define IDS_EE_BADMARSHAL_I                     0x1741
+#define IDS_EE_BADMARSHAL_R4                    0x1742
+#define IDS_EE_BADMARSHAL_R8                    0x1743
+#define IDS_EE_BADMARSHAL_PTR                   0x1745
+#define IDS_EE_BADMARSHAL_NOLAYOUT              0x1746
+#define IDS_EE_BADMARSHALPARAM_STRING           0x1747
+#define IDS_EE_BADMARSHALPARAM_STRINGBUILDER    0x1748
+#define IDS_EE_BADMARSHAL_DELEGATE              0x1749
+#define IDS_EE_BADMARSHAL_FNPTR                 0x174a
+#define IDS_EE_BADMARSHAL_INTERFACE             0x174b
+#define IDS_EE_BADMARSHAL_CLASS                 0x174c
+#define IDS_EE_BADMARSHAL_VALUETYPE             0x174d
+#define IDS_EE_BADMARSHAL_OBJECT                0x174e
+#define IDS_EE_BADMARSHALFIELD_OBJECT           0x174f
+#define IDS_EE_BADMARSHALPARAM_DECIMAL          0x1750
+#define IDS_EE_BADMARSHAL_GUID                  0x1751
+#define IDS_EE_BADMARSHAL_DATETIME              0x1753
+#define IDS_EE_BADMARSHAL_ARRAY                 0x1754
+#define IDS_EE_BADMARSHAL_BADMANAGED            0x1756
+#define IDS_EE_SRC_OBJ_NOT_COMOBJECT            0x1757
+#define IDS_EE_CANNOT_COERCE_COMOBJECT          0x1759
+#define IDS_EE_BADMARSHAL_AUTOLAYOUT            0x175a
+#define IDS_EE_BADMARSHAL_RESTRICTION           0x175d
+#define IDS_EE_BADMARSHAL_ASANYRESTRICTION      0x175f
+#define IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION 0x1760
+#define IDS_EE_BADMARSHAL_AWORESTRICTION        0x1761
+#define IDS_EE_BADMARSHAL_ARGITERATORRESTRICTION 0x1765
+#define IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION  0x1766
+
+#define IDS_EE_ADUNLOAD_NOT_ALLOWED             0x1767
+
+#define IDS_CANNOT_MARSHAL                      0x1770
+#define IDS_CANNOT_MARSHAL_RECURSIVE_DEF        0x1771
+#define IDS_EE_HASH_VAL_FAILED                  0x1772
+
+
+#define IDS_CLASSLOAD_GENERAL                   0x80131522
+#define IDS_CLASSLOAD_BADFORMAT                 0x1774
+#define IDS_CLASSLOAD_BYREFARRAY                0x1775
+#define IDS_CLASSLOAD_BYREFLIKEARRAY            0x1776
+#define IDS_CLASSLOAD_MISSINGMETHOD             0x1777
+#define IDS_CLASSLOAD_STATICVIRTUAL             0x1778
+#define IDS_CLASSLOAD_REDUCEACCESS              0x1779
+#define IDS_CLASSLOAD_BADPINVOKE                0x177a
+#define IDS_CLASSLOAD_VALUECLASSTOOLARGE        0x177b
+#define IDS_CLASSLOAD_NOTIMPLEMENTED            0x177c
+#define IDS_CLASSLOAD_PARENTNULL                0x177d
+#define IDS_CLASSLOAD_PARENTINTERFACE           0x177e
+#define IDS_CLASSLOAD_INTERFACEOBJECT           0x177f
+#define IDS_CLASSLOAD_INTERFACENULL             0x1780
+#define IDS_CLASSLOAD_NOTINTERFACE              0x1781
+#define IDS_CLASSLOAD_VALUEINSTANCEFIELD        0x1782
+#define IDS_CLASSLOAD_EXPLICIT_GENERIC          0x1783
+#define IDS_CLASSLOAD_RANK_TOOLARGE             0x1785
+#define IDS_CLASSLOAD_BAD_UNMANAGED_RVA         0x1787
+#define IDS_CLASSLOAD_ENCLOSING                 0x1789
+#define IDS_CLASSLOAD_EXPLICIT_LAYOUT           0x178a
+#define IDS_CLASSLOAD_SEALEDPARENT              0x178b
+#define IDS_CLASSLOAD_NOMETHOD_NAME             0x178c
+#define IDS_CLASSLOAD_BADSPECIALMETHOD          0x178e
+#define IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND    0x178f
+#define IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES      0x1790
+#define IDS_CLASSLOAD_MI_ACCESS_FAILURE         0x1791
+#define IDS_CLASSLOAD_MI_BADSIGNATURE           0x1793
+#define IDS_CLASSLOAD_MI_NOTIMPLEMENTED         0x1794
+#define IDS_CLASSLOAD_MI_MUSTBEVIRTUAL          0x1796
+#define IDS_CLASSLOAD_MISSINGMETHODRVA          0x1797
+#define IDS_CLASSLOAD_FIELDTOOLARGE             0x1798
+#define IDS_CLASSLOAD_CANTEXTEND                0x179a
+#define IDS_CLASSLOAD_ZEROSIZE                  0x179b
+#define IDS_CLASSLOAD_TYPESPEC                  0x179c
+#define IDS_CLASSLOAD_BAD_FIELD                 0x179d
+#define IDS_CLASSLOAD_MI_ILLEGAL_BODY           0x179e
+#define IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_BODY     0x17a0
+#define IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL     0x17a1
+#define IDS_CLASSLOAD_MI_SEALED_DECL            0x17a2
+#define IDS_CLASSLOAD_MI_FINAL_DECL             0x17a3
+#define IDS_CLASSLOAD_MI_NONVIRTUAL_DECL        0x17a4
+#define IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH     0x17a5
+#define IDS_CLASSLOAD_MI_MISSING_SIG_BODY       0x17a6
+#define IDS_CLASSLOAD_MI_MISSING_SIG_DECL       0x17a7
+#define IDS_CLASSLOAD_MI_BADRETURNTYPE          0x17a8
+#define IDS_CLASSLOAD_STATICVIRTUAL_NOTIMPL     0x17a9
+
+#define IDS_CLASSLOAD_TOOMANYGENERICARGS        0x17ab
+#define IDS_ERROR                               0x17b0
+#define IDS_DEBUG_SERVICE_CAPTION               0x17b4
+#define IDS_DEBUG_USERBREAKPOINT                0x17b6
+#define IDS_DEBUG_UNHANDLEDEXCEPTION            0x17b7
+#define IDS_DEBUG_UNHANDLEDEXCEPTION_IPC        0x17b8
+#define IDS_PERFORMANCEMON_FUNCNOTFOUND         0x17bb
+#define IDS_PERFORMANCEMON_FUNCNOTFOUND_TITLE   0x17bc
+#define IDS_PERFORMANCEMON_PSAPINOTFOUND        0x17bd
+#define IDS_PERFORMANCEMON_PSAPINOTFOUND_TITLE  0x17be
+
+#define IDS_DEBUG_UNHANDLED_EXCEPTION_MSG       0x17c0
+#define IDS_DEBUG_USER_BREAKPOINT_MSG           0x17c1
+
+#define IDS_INVALID_REDIM                       0x17c3
+#define IDS_INVALID_PINVOKE_CALLCONV            0x17c4
+#define IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET   0x17c7
+#define IDS_EE_BADPINVOKEFIELD_NOTMARSHALABLE   0x17c9
+#define IDS_WRONGSIZEARRAY_IN_NSTRUCT           0x17ca
+
+#define IDS_EE_INVALIDLCIDPARAM                 0x17cd
+#define IDS_EE_BADMARSHAL_NESTEDARRAY           0x17ce
+#define IDS_EE_INVALIDCOMSOURCEITF              0x17d1
+#define IDS_EE_CANNOT_COERCE_BYREF_VARIANT      0x17d2
+#define IDS_EE_WRAPPER_MUST_HAVE_DEF_CONS       0x17d3
+#define IDS_EE_INVALID_STD_DISPID_NAME          0x17d4
+#define IDS_EE_NO_IDISPATCH_ON_TARGET           0x17d5
+#define IDS_EE_NON_STD_NAME_WITH_STD_DISPID     0x17d6
+#define IDS_EE_INVOKE_NEW_ENUM_INVALID_RETURN   0x17d7
+#define IDS_EE_COM_OBJECT_RELEASE_RACE          0x17d8
+#define IDS_EE_COM_OBJECT_NO_LONGER_HAS_WRAPPER 0x17d9
+#define IDS_EE_CALLBACK_NOT_CALLED_FROM_CCTOR   0x17da
+#define IDS_EE_CALLBACK_ALREADY_REGISTERED      0x17de
+#define IDS_EE_NDIRECT_BADNATL_CALLCONV         0x17df
+#define IDS_EE_CANNOTCAST                       0x17e0
+#define IDS_EE_NOTISOMORPHIC                    0x17e1
+
+#define IDS_EE_NOCUSTOMMARSHALER                0x17e7
+#define IDS_EE_SIZECONTROLOUTOFRANGE            0x17e8
+#define IDS_EE_SIZECONTROLBADTYPE               0x17e9
+#define IDS_EE_SAFEARRAYSZARRAYMISMATCH         0x17eb
+#define IDS_EE_INVALID_VT_FOR_CUSTOM_MARHALER   0x17ec
+#define IDS_EE_BAD_COMEXTENDS_CLASS             0x17ed
+
+#define IDS_EE_ERRORTITLE                       0x17f0
+#define IDS_EE_ERRORMESSAGETEMPLATE             0x17f1
+
+#define IDS_EE_LOCAL_COGETCLASSOBJECT_FAILED    0x17f5
+
+#define IDS_EE_MISSING_FIELD                    0x17f7
+#define IDS_EE_MISSING_METHOD                   0x17f8
+
+#define IDS_EE_INTERFACE_NOT_DISPATCH_BASED     0x17f9
+
+#define IDS_EE_UNHANDLED_EXCEPTION              0x17fc
+#define IDS_EE_EXCEPTION_TOSTRING_FAILED        0x17fd
+
+#define IDS_CLASSLOAD_EQUIVALENTSTRUCTMETHODS   0x17fe
+#define IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS    0x17ff
+
+#define IDS_EE_NO_IDISPATCH                     0x1a02
+
+
+#define IDS_EE_SIGTOOCOMPLEX                    0x1a03
+#define IDS_EE_STRUCTTOOCOMPLEX                 0x1a04
+#define IDS_EE_STRUCTARRAYTOOLARGE              0x1a05
+#define IDS_EE_BADMARSHALFIELD_NOSTRINGBUILDER  0x1a06
+#define IDS_EE_NAME_UNKNOWN                     0x1a07
+#define IDS_EE_NO_BACKING_CLASS_FACTORY         0x1a0b
+#define IDS_EE_NAME_UNKNOWN_UNQ                 0x1a0c
+#define IDS_EE_STRING_TOOLONG                   0x1a0d
+#define IDS_EE_VARARG_NOT_SUPPORTED             0x1a0f
+
+#define IDS_EE_INVALID_CA                       0x1a10
+
+#define IDS_EE_THREAD_CANNOT_GET                0x1a15
+#define IDS_EE_THREAD_BAD_STATE                 0x1a1b
+#define IDS_EE_THREAD_ABORT_WHILE_SUSPEND       0x1a1c
+
+#define IDS_EE_NOVARIANTRETURN                  0x1a1d
+
+#define IDS_EE_METHOD_NOT_FOUND_ON_EV_PROV      0x1a24
+#define IDS_EE_BAD_COMEVENTITF_CLASS            0x1a25
+
+#define IDS_EE_COREXEMAIN2_FAILED_TITLE         0x1a2b
+#define IDS_EE_COREXEMAIN2_FAILED_TEXT          0x1a2c
+
+#define IDS_EE_ICUSTOMMARSHALERNOTIMPL          0x1a2e
+#define IDS_EE_GETINSTANCENOTIMPL               0x1a2f
+
+#define IDS_EE_BADMARSHAL_CUSTOMMARSHALER       0x1a30
+
+#define IDS_CLASSLOAD_COMIMPCANNOTHAVELAYOUT    0x1a31
+#define IDS_EE_INVALIDCOMDEFITF                 0x1a32
+#define IDS_EE_COMDEFITFNOTSUPPORTED            0x1a33
+
+#define IDS_EE_CLASS_TO_VARIANT_TLB_NOT_REG     0x1a35
+#define IDS_EE_CANNOT_MAP_TO_MANAGED_VC         0x1a36
+
+#define IDS_EE_MARSHAL_UNMAPPABLE_CHAR          0x1a37
+
+#define IDS_EE_BADMARSHAL_SAFEHANDLENATIVETOCOM 0x1a3a
+#define IDS_EE_BADMARSHAL_ABSTRACTOUTSAFEHANDLE 0x1a3b
+#define IDS_EE_BADMARSHAL_RETURNSHCOMTONATIVE   0x1a3c
+#define IDS_EE_BADMARSHAL_SAFEHANDLE            0x1a3d
+
+#define IDS_EE_SAFEHANDLECLOSED                 0x1a3f
+#define IDS_EE_SAFEHANDLECANNOTSETHANDLE        0x1a40
+
+#define IDS_EE_BADMARSHAL_ABSTRACTRETSAFEHANDLE 0x1a44
+#define IDS_EE_SH_IN_VARIANT_NOT_SUPPORTED      0x1a47
+
+#define IDS_EE_BADMARSHAL_SYSARRAY              0x1a48
+#define IDS_EE_VAR_WRAP_IN_VAR_NOT_SUPPORTED    0x1a49
+#define IDS_EE_RECORD_NON_SUPPORTED_FIELDS      0x1a4a
+
+#define IDS_CLASSLOAD_TYPEWRONGNUMGENERICARGS   0x1a4b
+#define IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET   0x1a4d
+
+#define IDS_CLASSLOAD_INVALIDINSTANTIATION      0x1a59
+
+#define IDS_EE_CLASSLOAD_INVALIDINSTANTIATION      0x1a59
+#define IDS_EE_BADMARSHALFIELD_ZEROLENGTHFIXEDSTRING 0x1a5a
+
+#define IDS_EE_BADMARSHAL_CRITICALHANDLENATIVETOCOM 0x1a62
+#define IDS_EE_BADMARSHAL_ABSTRACTOUTCRITICALHANDLE 0x1a63
+#define IDS_EE_BADMARSHAL_RETURNCHCOMTONATIVE       0x1a64
+#define IDS_EE_BADMARSHAL_CRITICALHANDLE            0x1a65
+
+#define IDS_EE_BADMARSHAL_ABSTRACTRETCRITICALHANDLE 0x1a6a
+#define IDS_EE_CH_IN_VARIANT_NOT_SUPPORTED          0x1a6b
+
+#define IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_OVERRIDE 0x1a6f
+#define IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_IMPLEMENTATION 0x1a70
+#define IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_LOCAL_METHOD_IMPL 0x1a71
+#define IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_PARENT_METHOD_IMPL 0x1a72
+#define IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL 0x1a73
+
+#define IDS_EE_NDIRECT_BADNATL_VARARGS_CALLCONV     0x1a75
+
+#define IDS_CLASSLOAD_VARIANCE_IN_METHOD_ARG    0x1a79
+#define IDS_CLASSLOAD_VARIANCE_IN_METHOD_RESULT 0x1a7a
+#define IDS_CLASSLOAD_VARIANCE_IN_BASE          0x1a7b
+#define IDS_CLASSLOAD_VARIANCE_IN_INTERFACE     0x1a7c
+#define IDS_CLASSLOAD_VARIANCE_IN_CONSTRAINT    0x1a7d
+#define IDS_CLASSLOAD_VARIANCE_CLASS            0x1a7e
+#define IDS_CLASSLOAD_BADVARIANCE               0x1a7f
+
+#define IDS_CLASSLOAD_OVERLAPPING_INTERFACES 0x1a80
+#define IDS_CLASSLOAD_32BITCLRLOADING64BITASSEMBLY 0x1a81
+#define IDS_EE_ASSEMBLY_GETTYPE_CANNONT_HAVE_ASSEMBLY_SPEC     0x1a84
+
+#define IDS_EE_CANNOT_HAVE_ASSEMBLY_SPEC        0x1a86
+#define IDS_EE_NEEDS_ASSEMBLY_SPEC              0x1a87
+
+#define IDS_EE_FILELOAD_ERROR_GENERIC           0x1a88
+
+#define IDS_EE_BADMARSHAL_UNSUPPORTED_SIG       0x1a89
+#define IDS_EE_BADMARSHAL_STRINGARRAY           0x1a8a
+#define IDS_EE_BADMARSHAL_OBJECTARRAY           0x1a8b
+#define IDS_EE_BADMARSHAL_DATETIMEARRAY         0x1a8c
+#define IDS_EE_BADMARSHAL_DECIMALARRAY          0x1a8d
+#define IDS_EE_BADMARSHAL_SAFEHANDLEARRAY       0x1a8f
+#define IDS_EE_BADMARSHAL_CRITICALHANDLEARRAY   0x1a90
+#define IDS_EE_BADMARSHALFIELD_ERROR_MSG        0x1a92
+#define IDS_EE_BADMARSHAL_ERROR_MSG             0x1a93
+#define IDS_EE_COM_INVISIBLE_PARENT             0x1a97
+
+#define IDS_EE_REMOTE_COGETCLASSOBJECT_FAILED   0x1a98
+#define IDS_EE_CREATEINSTANCE_FAILED            0x1a99
+#define IDS_EE_CREATEINSTANCE_LIC_FAILED        0x1a9a
+
+#define IDS_EE_RCW_INVALIDCAST_ITF              0x1a9b
+#define IDS_EE_RCW_INVALIDCAST_EVENTITF         0x1a9c
+#define IDS_EE_RCW_INVALIDCAST_IENUMERABLE      0x1a9d
+#define IDS_EE_RCW_INVALIDCAST_MNGSTDITF        0x1a9e
+#define IDS_EE_RCW_INVALIDCAST_COMOBJ_TO_MD     0x1a9f
+#define IDS_EE_RCW_INVALIDCAST_TO_NON_COMOBJTYPE 0x1aa0
+#define IDS_EE_RCW_INVALIDCAST_MD_TO_MD         0x1aa1
+
+#define IDS_EE_GENERIC                          0x1aa2
+#define IDS_EE_BADMARSHAL_GENERICS_RESTRICTION  0x1aa3
+
+#define IDS_EE_THREAD_ABORT                     0x1aa4
+#define IDS_EE_THREAD_INTERRUPTED               0x1aa5
+#define IDS_EE_OUT_OF_MEMORY                    0x1aa6
+
+#define IDS_EE_ATTEMPT_TO_CREATE_GENERIC_CCW    0x1aa9
+#define IDS_EE_ATTEMPT_TO_CREATE_NON_ABSTRACT_CCW    0x1aaa
+#define IDS_EE_COMIMPORT_METHOD_NO_INTERFACE    0x1aab
+#define IDS_EE_OUT_OF_MEMORY_WITHIN_RANGE       0x1aac
+#define IDS_EE_ARRAY_DIMENSIONS_EXCEEDED        0x1aad
+#define IDS_EE_OUT_OF_SYNCBLOCKS                0x1aae
+
+#define IDS_CLASSLOAD_MI_CANNOT_OVERRIDE        0x1ab3
+#define IDS_CLASSLOAD_COLLECTIBLEFIXEDVTATTR    0x1ab6
+#define IDS_CLASSLOAD_EQUIVALENTBADTYPE         0x1ab7
+#define IDS_EE_CODEEXECUTION_CONTAINSGENERICVAR 0x1abb
+#define IDS_CLASSLOAD_WRONGCPU                  0x1abc
+#define IDS_EE_CREATEINSTANCEFROMAPP_FAILED     0x1abd
+
+#define IDS_IBC_MISSING_EXTERNAL_TYPE           0x1ac5
+#define IDS_IBC_MISSING_EXTERNAL_METHOD         0x1ac6
+#define IDS_EE_HWINTRINSIC_NGEN_DISALLOWED      0x1ac7
+#define IDS_CLASSLOAD_MI_FINAL_IMPL             0x1ac8
+#define IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE        0x1ac9
+#define IDS_CLASSLOAD_UNSUPPORTED_DISPATCH      0x1aca
+#define IDS_CLASSLOAD_METHOD_NOT_IMPLEMENTED    0x1acb
+
+#define BFA_INVALID_TOKEN_TYPE                  0x2001
+#define BFA_INVALID_TOKEN                       0x2003
+#define BFA_UNABLE_TO_GET_NESTED_PROPS          0x2005
+#define BFA_METHOD_TOKEN_OUT_OF_RANGE           0x2006
+#define BFA_METHOD_NAME_TOO_LONG                0x2007
+#define BFA_METHOD_IN_A_ENUM                    0x2009
+#define BFA_METHOD_WITH_NONZERO_RVA             0x200a
+#define BFA_ABSTRACT_METHOD_WITH_RVA            0x200b
+#define BFA_RUNTIME_METHOD_WITH_RVA             0x200c
+#define BFA_INTERNAL_METHOD_WITH_RVA            0x200d
+#define BFA_AB_METHOD_IN_AB_CLASS               0x200e
+#define BFA_NONVIRT_AB_METHOD                   0x200f
+#define BFA_NONAB_NONCCTOR_METHOD_ON_INT        0x2010
+#define BFA_VIRTUAL_PINVOKE_METHOD              0x2011
+#define BFA_VIRTUAL_STATIC_METHOD               0x2012
+#define BFA_VIRTUAL_INSTANCE_CTOR               0x2013
+#define BFA_VIRTUAL_NONAB_INT_METHOD            0x2014
+#define BFA_NONVIRT_INST_INT_METHOD             0x2015
+#define BFA_SYNC_METHOD_IN_VT                   0x2016
+#define BFA_NONSTATIC_GLOBAL_METHOD             0x2017
+#define BFA_GLOBAL_INST_CTOR                    0x2018
+#define BFA_BAD_PLACE_FOR_GENERIC_METHOD        0x2019
+#define BFA_GENERIC_METHOD_RUNTIME_IMPL         0x201a
+#define BFA_BAD_RUNTIME_IMPL                    0x201b
+#define BFA_BAD_FLAGS_ON_DELEGATE               0x201c
+#define BFA_UNKNOWN_DELEGATE_METHOD             0x201d
+#define BFA_GENERIC_METHODS_INST                0x201e
+#define BFA_BAD_FIELD_TOKEN                     0x201f
+#define BFA_INVALID_FIELD_ACC_FLAGS             0x2020
+#define BFA_FIELD_LITERAL_AND_INIT              0x2021
+#define BFA_NONSTATIC_GLOBAL_FIELD              0x2022
+#define BFA_INSTANCE_FIELD_IN_INT               0x2023
+#define BFA_INSTANCE_FIELD_IN_ENUM              0x2024
+#define BFA_NONVIRT_NO_SEARCH                   0x2025
+#define BFA_MANAGED_NATIVE_NYI                  0x2027
+#define BFA_BAD_IMPL_FLAGS                      0x2028
+#define BFA_BAD_UNMANAGED_ENTRY_POINT           0x2029
+#define BFA_GENCODE_NOT_BE_VARARG               0x202b
+#define BFA_CANNOT_INHERIT_FROM_DELEGATE        0x202c
+#define BFA_DELEGATE_CLASS_NOTSEALED            0x202d
+#define BFA_ENCLOSING_TYPE_NOT_FOUND            0x202e
+#define BFA_ILLEGAL_DELEGATE_METHOD             0x202f
+#define BFA_MISSING_DELEGATE_METHOD             0x2030
+#define BFA_MULT_TYPE_SAME_NAME                 0x2031
+#define BFA_INVALID_METHOD_TOKEN                0x2032
+#define BFA_ECALLS_MUST_BE_IN_SYS_MOD           0x2034
+#define BFA_CANT_GET_CLASSLAYOUT                0x2035
+#define BFA_CALLCONV_NOT_LOCAL_SIG              0x2036
+#define BFA_BAD_CLASS_TOKEN                     0x2037
+#define BFA_BAD_IL_RANGE                        0x2038
+#define BFA_METHODDEF_WO_TYPEDEF_PARENT         0x2039
+#define BFA_METHODDEF_PARENT_NO_MEMBERS         0x203a
+#define BFA_INVALID_TOKEN_IN_MANIFESTRES        0x203c
+#define BFA_EMPTY_ASSEMDEF_NAME                 0x203d
+#define BFA_BAD_IL                              0x203e
+#define BFA_CLASSLOAD_VALUETYPEMISMATCH         0x203f
+#define BFA_METHODDECL_NOT_A_METHODDEF          0x2040
+#define BFA_DUPLICATE_DELEGATE_METHOD           0x2041
+#define BFA_ECALLS_MUST_HAVE_ZERO_RVA           0x2042
+#define BFA_METADATA_CORRUPT                    0x2043
+#define BFA_BAD_SIGNATURE                       0x2044
+#define BFA_TYPEREG_NAME_TOO_LONG               0x2045
+#define BFA_BAD_TYPEREF_TOKEN                   0x2046
+#define BFA_BAD_CLASS_INT_CA                    0x2047
+#define BFA_BAD_CLASS_INT_CA_FORMAT             0x2048
+#define BFA_BAD_COMPLUS_SIG                     0x2049
+#define BFA_BAD_ELEM_IN_SIZEOF                  0x204b
+#define BFA_IJW_IN_COLLECTIBLE_ALC              0x204c
+
+#define IDS_CLASSLOAD_INTERFACE_NO_ACCESS       0x204f
+
+#define BFA_BAD_CA_HEADER                       0x2050
+#define BFA_BAD_STRING_TOKEN                    0x2052
+#define BFA_BAD_STRING_TOKEN_RANGE              0x2053
+#define BFA_FIXUP_WRONG_PLATFORM                0x2054
+#define BFA_UNEXPECTED_GENERIC_TOKENTYPE        0x2055
+#define BFA_MDARRAY_BADRANK                     0x2056
+#define BFA_SDARRAY_BADRANK                     0x2057
+#define BFA_BAD_PACKING_SIZE                    0x2058
+#define BFA_UNEXPECTED_ARRAY_TYPE               0x2059
+#define BFA_BAD_VISIBILITY                      0x205a
+#define BFA_FAMILY_ON_GLOBAL                    0x205b
+#define BFA_NOFIND_EXPORTED_TYPE                0x205c
+#define BFA_NOT_AN_ARRAY                        0x205d
+#define BFA_EXPECTED_METHODDEF_OR_MEMBERREF     0x205e
+
+#define IDS_CLASSLOAD_BAD_METHOD_COUNT          0x2062
+#define IDS_CLASSLOAD_BAD_FIELD_COUNT           0x2063
+#define IDS_CLASSLOAD_MUST_BE_BYVAL             0x2064
+#define IDS_CLASSLOAD_BAD_VARIANCE_SIG          0x2065
+#define IDS_CLASSLOAD_VARIANCE_IN_DELEGATE      0x2066
+
+#define BFA_UNEXPECTED_FIELD_SIGNATURE          0x2068
+#define BFA_UNEXPECTED_TOKEN_AFTER_CLASSVALTYPE 0x2069
+#define BFA_FNPTR_CANNOT_BE_A_FIELD             0x206a
+#define BFA_FNPTR_CANNOT_BE_GENERIC             0x206b
+#define BFA_UNEXPECTED_TOKEN_AFTER_GENINST      0x206c
+#define BFA_TYPEDBYREFCANNOTHAVEBYREF           0x206e
+
+#define IDS_CLASSLOAD_MI_BAD_SIG                0x2070
+
+#define IDS_EE_TOOMANYFIELDS                    0x2072
+
+#define IDS_EE_NDIRECT_GETPROCADDRESS_NONAME    0x2073
+#define IDS_EE_CLASS_CONSTRAINTS_VIOLATION      0x2076
+#define IDS_EE_METHOD_CONSTRAINTS_VIOLATION     0x2077
+#define IDS_CLASSLOAD_TOO_MANY_METHODS          0x2078
+#define IDS_CLASSLOAD_ENUM_EXTRA_GENERIC_TYPE_PARAM 0x2079
+
+#define IDS_CLASSLOAD_GENERICTYPE_RECURSIVE     0x207D
+#define IDS_EE_JIT_COMPILER_ERROR               0x207F
+
+#define IDS_ER_APPLICATION                      0x2082
+#define IDS_ER_UNKNOWN                          0x2083
+#define IDS_ER_FRAMEWORK_VERSION                0x2084
+#define IDS_ER_UNHANDLEDEXCEPTION               0x2085
+#define IDS_ER_UNHANDLEDEXCEPTIONMSG            0x2086
+#define IDS_ER_MANAGEDFAILFAST                  0x2087
+#define IDS_ER_MANAGEDFAILFASTMSG               0x2088
+#define IDS_ER_UNMANAGEDFAILFAST                0x2089
+#define IDS_ER_STACK_OVERFLOW                   0x208a
+#define IDS_ER_STACK                            0x208b
+#define IDS_ER_WORDAT                           0x208c
+#define IDS_ER_UNMANAGEDFAILFASTMSG             0x208d
+#define IDS_ER_UNHANDLEDEXCEPTIONINFO           0x208e
+#define IDS_ER_MESSAGE_TRUNCATE                 0x208f
+
+#define IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED  0x2090
+#define IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED      0x2091
+
+#define IDS_EE_BADMARSHALFIELD_DECIMAL          0x2099
+
+#define IDS_EE_CANNOTCASTSAME                   0x209a
+#define IDS_EE_CANNOTCAST_HELPER_BYTE           0x209b
+#define IDS_EE_CANNOTCAST_HELPER_PATH           0x209c
+
+// For ForwardInteropStubAttribute
+#ifdef FEATURE_COMINTEROP
+#define IDS_EE_INTEROP_STUB_CA_MUST_BE_WITHIN_SAME_ASSEMBLY         0x2107
+#define IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_GENERIC       0x2108
+#define IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_INTERFACE     0x2109
+#define IDS_EE_INTEROP_STUB_CA_STUB_METHOD_MISSING                  0x2110
+#define IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD             0x2111
+#endif
+
+#define IDS_EE_INTEROP_CODE_SIZE_COMMENT        0x2112
+
+#define BFA_REFERENCE_ASSEMBLY                  0x2113
+
+#define IDS_E_FIELDACCESS                       0x2114
+#define IDS_E_METHODACCESS                      0x2115
+#define IDS_E_TYPEACCESS                        0x2116
+
+// Profiler error messages for event log
+#define IDS_E_PROF_NO_CLSID                     0x2500
+#define IDS_E_PROF_INTERNAL_INIT                0x2501
+#define IDS_E_PROF_BAD_CLSID                    0x2502
+#define IDS_E_PROF_NO_CALLBACK_IFACE            0x2503
+#define IDS_E_PROF_CCI_FAILED                   0x2504
+#define IDS_E_PROF_INIT_CALLBACK_FAILED         0x2505
+#define IDS_PROF_SUPPLEMENTARY_INFO             0x2506
+#define IDS_PROF_LOAD_COMPLETE                  0x2507
+#define IDS_E_PROF_BAD_PATH                     0x2508
+#define IDS_E_PROF_NOTIFICATION_DISABLED        0x2509
+#define IDS_PROF_ALREADY_LOADED                 0x250A
+#define IDS_E_PROF_NOTIFICATION_LIMIT_EXCEEDED  0x250B
+#define IDS_E_PROF_NOT_ATTACHABLE               0x250E
+#define IDS_E_PROF_UNHANDLED_EXCEPTION_ON_LOAD  0x250F
+#define IDS_PROF_ATTACH_REQUEST_RECEIVED        0x2512
+#define IDS_PROF_DETACH_INITIATED               0x2513
+#define IDS_PROF_DETACH_COMPLETE                0x2514
+#define IDS_PROF_DETACH_THREAD_ERROR            0x2515
+#define IDS_PROF_CANCEL_ACTIVATION              0x2516
+#define IDS_PROF_V2PROFILER_DISABLED            0x2517
+#define IDS_PROF_V2PROFILER_ENABLED             0x2518
+#define IDS_PROF_PROFILER_DISABLED              0x251A
+
+#define IDS_ER_CODECONTRACT_FAILED              0x251B
+#define IDS_ER_CODECONTRACT_DETAILMSG           0x251C
+
+#define IDS_E_PROF_TIMEOUT_WAITING_FOR_CONCURRENT_GC    0x251D
+
+#define IDS_EE_CANNOTCAST_NOMARSHAL             0x2629
+#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
+#define IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE           0x262e
+#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+
+#define IDS_HOST_ASSEMBLY_RESOLVER_ASSEMBLY_ALREADY_LOADED_IN_CONTEXT                  0x2636
+#define IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED          0x2637
+#define IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT                        0x2638
+
+#define IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES                               0x263a
+
+#define IDS_CLASSLOAD_BYREFLIKE_STATICFIELD        0x263b
+#define IDS_CLASSLOAD_BYREFLIKE_INSTANCEFIELD      0x263c
+#define IDS_EE_NDIRECT_LOADLIB_LINUX               0x263e
+#define IDS_EE_NDIRECT_LOADLIB_MAC                 0x263f
+#define IDS_EE_NDIRECT_GETPROCADDRESS_UNIX         0x2640
+#define IDS_EE_ERROR_COM                           0x2641
+
+#define IDS_EE_CANNOT_SET_INITONLY_STATIC_FIELD    0x2643
+
+#define IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL         0x2644
+#define IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO         0x2645
+#define IDS_EE_BADMARSHAL_STRING_OUT               0x2646
+#define IDS_EE_BADMARSHAL_COPYCTORRESTRICTION      0x2647
+#define IDS_EE_BADMARSHAL_DELEGATE_TLB_INTERFACE   0x2649
+#define IDS_EE_THREAD_APARTMENT_NOT_SUPPORTED      0x264A
+#define IDS_EE_NO_IINSPECTABLE                     0x264B
+#define IDS_EE_BADMARSHAL_MARSHAL_DISABLED         0x264C
+#define IDS_EE_NDIRECT_DISABLEDMARSHAL_SETLASTERROR 0x264D
+#define IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID        0x264E
+#define IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG 0x264F
+#define IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS     0x2650
diff --git a/src/inc/safewrap.h b/src/inc/safewrap.h
new file mode 100644 (file)
index 0000000..c2f260a
--- /dev/null
@@ -0,0 +1,168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// SafeWrap.h
+//
+
+//
+// This file contains wrapper functions for Win32 API's that take SStrings
+// and use CLR-safe holders.
+//*****************************************************************************
+
+
+/*
+    Guidelines for SafeWrapper APIs:
+Most of these are 'common-sense', plus a few arbitrary decisions thrown in for
+consistency's sake.
+
+- THROWING: Throw on oom, but return all other failure codes.
+    The rationale here is that SString operations already throw, so to make these APIs
+    non-throwing would require an extra EX_TRY/EX_CATCH. Most callees will want to throw
+    on OOM anyways. So making these APIs non-throwing would mean an extra try/catch in
+    the caller + an extra check at the callee. We can eliminate that overhead and just make
+    it throwing.
+
+    Return non-oom failure codes because callees actually freqeuntly expect an API to fail.
+    For example, the callee will have special handling for file-not-found.
+
+    For convenience, you could add a no-throwing wrapper version of the API:
+        ClrGetEnvironmentVariable   <-- default throws on oom.
+        ClrGetEnvironmentVariableNoThrow <-- never throws.
+
+- NAMING: Prefix the name with 'Clr', just like we do for win32 APIs going through hosting.
+
+- DON'T FORGET CONTRACTS: Most of these APIs will likely be Throws/GC_Notrigger.
+    Also use PRECONDITIONs + POSTCONDITIONS when possible.
+
+- SIGNATURES: Keep the method signture as close the the original win32 API as possible.
+    - Preserve the return type + value. (except allow it to throw on oom). If the return value
+        should be a holder, then use that as an out-parameter at the end of the argument list.
+        We don't want to return holders because that will cause the dtors to be called.
+    - For input strings use 'const SString &' instead of 'LPCWSTR'.
+    - Change ('out' string, length) pairs to 'SString &' (this is the convention the rest of the CLR uses for SStrings)
+    - Use Holders where appropriate.
+    - Preserve other parameters.
+
+- USE SSTRINGS TO AVOID BUFFER OVERRUN ISSUES: Repeated here for emphasis. Use SStrings when
+    applicable to make it very easy to verify the code does not have buffer overruns.
+    This will also simplify callsites from having to figure out the length of the output string.
+
+- USE YOUR BEST JUDGEMENT: The primary goal of these API wrappers is to embrace 'security-safe' practices.
+    Certainly take any additional steps to that goal. For example, it may make sense to eliminate
+    corner case inputs for a given API or to break a single confusing API up into several discrete and
+    move obvious APIs.
+
+*/
+#ifndef _safewrap_h_
+#define _safewrap_h_
+
+#include "holder.h"
+
+class SString;
+bool ClrGetEnvironmentVariable(LPCSTR szEnvVarName, SString & value);
+bool ClrGetEnvironmentVariableNoThrow(LPCSTR szEnvVarName, SString & value);
+void ClrGetModuleFileName(HMODULE hModule, SString & value);
+
+void ClrGetCurrentDirectory(SString & value);
+
+
+/* --------------------------------------------------------------------------- *
+ * Simple wrapper around WszFindFirstFile/WszFindNextFile
+ * --------------------------------------------------------------------------- */
+class ClrDirectoryEnumerator
+{
+    WIN32_FIND_DATAW    data;
+    FindHandleHolder    dirHandle;
+    BOOL                fFindNext; // Skip FindNextFile first time around
+
+public:
+    ClrDirectoryEnumerator(LPCWSTR pBaseDirectory, LPCWSTR pMask = W("*"));
+    bool Next();
+
+    LPCWSTR GetFileName()
+    {
+        return data.cFileName;
+    }
+
+    DWORD GetFileAttributes()
+    {
+        return data.dwFileAttributes;
+    }
+
+    void Close()
+    {
+        dirHandle.Clear();
+    }
+};
+
+// Read a REG_SZ (null-terminated string) value from the registry.  Throws.
+void ClrRegReadString(HKEY hKey, const SString & szValueName, SString & value);
+
+/* --------------------------------------------------------------------------- *
+ * Simple wrapper around RegisterEventSource/ReportEvent/DeregisterEventSource
+ * --------------------------------------------------------------------------- */
+// Returns ERROR_SUCCESS if succeessful in reporting to event log, or
+// Windows error code to indicate the specific error.
+DWORD ClrReportEvent(
+    LPCWSTR     pEventSource,
+    WORD        wType,
+    WORD        wCategory,
+    DWORD       dwEventID,
+    PSID        lpUserSid,
+    WORD        wNumStrings,
+    LPCWSTR     *lpStrings,
+    DWORD       dwDataSize = 0,
+    LPVOID      lpRawData = NULL);
+
+DWORD ClrReportEvent(
+    LPCWSTR     pEventSource,
+    WORD        wType,
+    WORD        wCategory,
+    DWORD       dwEventID,
+    PSID        lpUserSid,
+    LPCWSTR     pMessage);
+
+//*****************************************************************************
+// This provides a wrapper around GetFileSize() that forces it to fail
+// if the file is >4g and pdwHigh is NULL. Other than that, it acts like
+// the genuine GetFileSize().
+//
+//
+//*****************************************************************************
+DWORD inline SafeGetFileSize(HANDLE hFile, DWORD *pdwHigh)
+{
+    if (pdwHigh != NULL)
+    {
+        return ::GetFileSize(hFile, pdwHigh);
+    }
+    else
+    {
+        DWORD hi;
+        DWORD lo = ::GetFileSize(hFile, &hi);
+        if (lo == 0xffffffff && GetLastError() != NO_ERROR)
+        {
+            return lo;
+        }
+        // api succeeded. is the file too large?
+        if (hi != 0)
+        {
+            // there isn't really a good error to set here...
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return 0xffffffff;
+        }
+
+        if (lo == 0xffffffff)
+        {
+            // note that a success return of (hi=0,lo=0xffffffff) will be
+            // treated as an error by the caller. Again, that's part of the
+            // price of being a slacker and not handling the high dword.
+            // We'll set a lasterror for them to pick up.
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        }
+
+        return lo;
+    }
+
+}
+
+#endif // _safewrap_h_
diff --git a/src/inc/sbuffer.h b/src/inc/sbuffer.h
new file mode 100644 (file)
index 0000000..05c75fa
--- /dev/null
@@ -0,0 +1,574 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// --------------------------------------------------------------------------------
+// SBuffer.h  (Safe Buffer)
+//
+
+// --------------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------------
+// SBuffer is a relatively safe way to manipulate a dynamically
+// allocated data buffer.  An SBuffer is conceptually a simple array
+// of bytes.  It maintains both a conceptual size and an actual allocated size.
+//
+// SBuffer provides safe access to the data buffer by providing rich high
+// level functionality (like insertion, deleteion, copying,  comparison, and
+// iteration) without exposing direct pointers to its buffers.
+//
+// For interoperability, SBuffers can expose their buffers - either as readonly
+// by BYTE * or void * cases, or as writable by the OpenRawBuffer/CloseRawBuffer
+// entry points.  Use of these should be limited wherever possible though; as there
+// is always a possibilility of buffer overrun.
+//
+// To mimimize heap allocations, the InlineSBuffer template will preallocate a fixed
+// size buffer inline with the SBuffer object itself.  It will use this buffer unless
+// it needs a bigger one, in which case it transparently moves on to using the heap.
+// The StackSBuffer class instatiates the InlineSBuffer with a standard heuristic
+// stack preallocation size.
+//
+// SBuffer is "subclassable" to add content typeing to the buffer. See SArray and
+// SString for examples.
+// --------------------------------------------------------------------------------
+
+
+#ifndef _SBUFFER_H_
+#define _SBUFFER_H_
+
+#include "clrtypes.h"
+#include "iterator.h"
+#include "check.h"
+#include "daccess.h"
+#include "memoryrange.h"
+
+// ================================================================================
+// Macros for computing padding
+// ================================================================================
+
+#define ALIGNMENT(size) \
+    (( ((size)^((size)-1)) >> 1) +1)
+
+#define ALIGN(size, align) \
+    (((size)+((align)-1)) & ~((align)-1))
+
+#define PAD(size, align) \
+    (ALIGN((size), (align)) - (size))
+
+// ================================================================================
+// SBuffer : base class for safe buffers
+// ================================================================================
+
+typedef DPTR(class SBuffer) PTR_SBuffer;
+
+class SBuffer
+{
+  public:
+    //--------------------------------------------------------------------
+    // Flags and constants
+    //--------------------------------------------------------------------
+
+    enum ImmutableFlag
+    {
+        Immutable
+    };
+
+    enum PreallocFlag
+    {
+        Prealloc
+    };
+
+    //--------------------------------------------------------------------
+    // Types
+    //--------------------------------------------------------------------
+
+  public:
+    class CIterator;
+    friend class CIterator;
+
+    class Iterator;
+    friend class Iterator;
+
+    //--------------------------------------------------------------------
+    // Initializers and constructors
+    //--------------------------------------------------------------------
+
+  public:
+    // Constructors
+    SBuffer();
+    SBuffer(COUNT_T size);
+    SBuffer(const BYTE *buffer, COUNT_T size);
+    explicit SBuffer(const SBuffer &buffer);
+
+    // Immutable constructor should ONLY be used if buffer will
+    // NEVER BE FREED OR MODIFIED. PERIOD. .
+    SBuffer(ImmutableFlag immutable, const BYTE *buffer, COUNT_T size);
+
+    // Prealloc should be allocated inline with SBuffer - it must have the same
+    // lifetime as SBuffer's memory.
+    SBuffer(PreallocFlag prealloc, void *buffer, COUNT_T size);
+
+    ~SBuffer();
+
+    void Clear();
+
+    void Set(const SBuffer &buffer);
+    void Set(const BYTE *buffer, COUNT_T size);
+    void SetImmutable(const BYTE *buffer, COUNT_T size);
+
+    //--------------------------------------------------------------------
+    // Buffer size routines.  A buffer has an externally visible size, but
+    // it also has an internal allocation size which may be larger.
+    //--------------------------------------------------------------------
+
+    // Get and set size of buffer.  Note that the actual size of the
+    // internally allocated memory block may be bigger.
+    COUNT_T GetSize() const;
+    void SetSize(COUNT_T count);
+
+    // Grow size of buffer to maximum amount without reallocating.
+    void MaximizeSize();
+
+    //--------------------------------------------------------------------
+    // Buffer allocation routines
+    //--------------------------------------------------------------------
+
+    // Return the current available allocation space of the buffer.
+    COUNT_T GetAllocation() const;
+
+    // Preallocate some memory you expect to use.  This can prevent
+    // multiple reallocations.  Note this does not change the visible
+    // size of the buffer.
+    void Preallocate(COUNT_T allocation) const;
+
+    // Shrink memory usage of buffer to minimal amount.  Note that
+    // this does not change the visible size of the buffer.
+    void Trim() const;
+
+    //--------------------------------------------------------------------
+    // Content manipulation routines
+    //--------------------------------------------------------------------
+
+    void Zero();
+    void Fill(BYTE value);
+    void Fill(const Iterator &to, BYTE value, COUNT_T size);
+
+    // Internal copy. "Copy" leaves from range as is; "Move"
+    // leaves from range in uninitialized state.
+    // (This distinction is more important when using from a
+    // typed wrapper than in the base SBuffer class.)
+    //
+    // NOTE: Copy vs Move is NOT based on whether ranges overlap
+    // or not.  Ranges may overlap in either case.
+    //
+    // Note that both Iterators must be on THIS buffer.
+    void Copy(const Iterator &to, const CIterator &from, COUNT_T size);
+    void Move(const Iterator &to, const CIterator &from, COUNT_T size);
+
+    // External copy.
+    void Copy(const Iterator &i, const SBuffer &source);
+    void Copy(const Iterator &i, const void *source, COUNT_T size);
+    void Copy(void *dest, const CIterator &i, COUNT_T size);
+
+    // Insert bytes at the given iterator location.
+    void Insert(const Iterator &i, const SBuffer &source);
+    void Insert(const Iterator &i, COUNT_T size);
+
+    // Delete bytes at the given iterator location
+    void Delete(const Iterator &i, COUNT_T size);
+
+    // Replace bytes at the given iterator location
+    void Replace(const Iterator &i, COUNT_T deleteSize, const SBuffer &insert);
+    void Replace(const Iterator &i, COUNT_T deleteSize, COUNT_T insertSize);
+
+    // Compare entire buffer; return -1, 0, 1
+    int Compare(const SBuffer &compare) const;
+    int Compare(const BYTE *match, COUNT_T size) const;
+
+    // Compare entire buffer; return TRUE or FALSE
+    BOOL Equals(const SBuffer &compare) const;
+    BOOL Equals(const BYTE *match, COUNT_T size) const;
+
+    // Match portion of this buffer to given bytes; return TRUE or FALSE
+    BOOL Match(const CIterator &i, const SBuffer &match) const;
+    BOOL Match(const CIterator &i, const BYTE *match, COUNT_T size) const;
+
+    //--------------------------------------------------------------------
+    // Iterators
+    //
+    // Note that any iterator returned is not
+    // valid after any operation which may resize the buffer, unless
+    // the operation was performed on that particular iterator.
+    //--------------------------------------------------------------------
+
+    CIterator Begin() const;
+    CIterator End() const;
+
+    Iterator Begin();
+    Iterator End();
+
+    BYTE & operator[] (int index);
+    const BYTE & operator[] (int index) const;
+
+    //--------------------------------------------------------------------
+    // Raw buffer access
+    //
+    // Accessing a raw buffer via pointer is inherently more dangerous than
+    // other uses of this API, and should be avoided if at all possible.
+    // It is primarily provided for compatibility with existing APIs.
+    //
+    // Note that any buffer pointer returned is not
+    // valid after any operation which may resize the buffer.
+    //--------------------------------------------------------------------
+
+    // Casting operators return the existing buffer as
+    // a raw const pointer.  Note that the pointer is valid only
+    // until the buffer is modified via an API.
+    operator const void *() const;
+    operator const BYTE *() const;
+
+    // To write directly to the SString's underlying buffer:
+    // 1) Call OpenRawBuffer() and pass it the count of bytes
+    // you need.
+    // 2) That returns a pointer to the raw buffer which you can write to.
+    // 3) When you are done writing to the pointer, call CloseBuffer()
+    // and pass it the count of bytes you actually wrote.
+    // The pointer from step 1 is now invalid.
+
+    // example usage:
+    // void GetInfo(SBuffer &buf)
+    // {
+    //      BYTE *p = buf.OpenRawBuffer(3);
+    //      OSGetSomeInfo(p, 3);
+    //      buf.CloseRawBuffer();
+    // }
+
+    // You should open the buffer, write the data, and immediately close it.
+    // No sbuffer operations are valid while the buffer is opened.
+    //
+    // In a debug build, Open/Close will do lots of little checks to make sure
+    // you don't buffer overflow while it's opened. In a retail build, this
+    // is a very streamlined action.
+
+    // Open the raw buffer for writing count bytes
+    BYTE *OpenRawBuffer(COUNT_T maxCount);
+
+    // Call after OpenRawBuffer().
+
+    // Provide the count of bytes actually used. This will make sure the
+    // SBuffer's size is correct.
+    void CloseRawBuffer(COUNT_T actualCount);
+
+    // Close the buffer. Assumes that we completely filled the buffer
+    // that OpenRawBuffer() gave back.
+    void CloseRawBuffer();
+
+    //--------------------------------------------------------------------
+    // Check routines. These are typically used internally, but may be
+    // called externally if desired.
+    //--------------------------------------------------------------------
+
+    CHECK CheckBufferClosed() const;
+    static CHECK CheckSize(COUNT_T size);
+    static CHECK CheckAllocation(COUNT_T allocation);
+    CHECK CheckIteratorRange(const CIterator &i) const;
+    CHECK CheckIteratorRange(const CIterator &i, COUNT_T size) const;
+
+    CHECK Check() const;
+    CHECK Invariant() const;
+    CHECK InternalInvariant() const;
+
+  protected:
+
+    //--------------------------------------------------------------------
+    // Internal helper routines
+    //--------------------------------------------------------------------
+
+    // Preserve = preserve contents while reallocating
+    typedef enum
+    {
+        DONT_PRESERVE = 0,
+        PRESERVE = 1,
+    } Preserve;
+
+    void Resize(COUNT_T size, Preserve preserve = PRESERVE);
+    void ResizePadded(COUNT_T size, Preserve preserve = PRESERVE);
+    void TweakSize(COUNT_T size);
+    void ReallocateBuffer(COUNT_T allocation, Preserve preserve);
+    void EnsureMutable() const;
+
+    //--------------------------------------------------------------------
+    // We define some extra flags and fields for subclasses (these are specifically
+    // designed for SString, but use otherwise if desired.)
+    //--------------------------------------------------------------------
+
+    BOOL IsFlag1() const;
+    void SetFlag1();
+    void ClearFlag1();
+
+    BOOL IsFlag2() const;
+    void SetFlag2();
+    void ClearFlag2();
+
+    BOOL IsFlag3() const;
+    void SetFlag3();
+    void ClearFlag3();
+
+    INT GetRepresentationField() const;
+    void SetRepresentationField(int value);
+
+  protected:
+
+    //--------------------------------------------------------------------
+    // Flag access
+    //--------------------------------------------------------------------
+
+    BOOL IsAllocated() const;
+    void SetAllocated();
+    void ClearAllocated();
+
+    BOOL IsImmutable() const;
+    void SetImmutable();
+    void ClearImmutable();
+
+#if _DEBUG
+    BOOL IsOpened() const;
+    void SetOpened();
+    void ClearOpened();
+#endif
+
+    //--------------------------------------------------------------------
+    // Buffer management routines
+    //--------------------------------------------------------------------
+
+    // Allocate and free a memory buffer
+    BYTE *NewBuffer(COUNT_T allocation);
+    void DeleteBuffer(BYTE *buffer, COUNT_T allocation);
+
+    // Use existing buffer
+    BYTE *UseBuffer(BYTE *buffer, COUNT_T *allocation);
+
+    CHECK CheckBuffer(const BYTE* buffer, COUNT_T allocation) const;
+
+    // Manipulates contents of the buffer via the plugins below, but
+    // adds some debugging checks.  Should always call through here rather
+    // than directly calling the extensibility points.
+    void DebugMoveBuffer(_Out_writes_bytes_(size) BYTE *to, BYTE *from, COUNT_T size);
+    void DebugCopyConstructBuffer(_Out_writes_bytes_(size) BYTE *to, const BYTE *from, COUNT_T size);
+    void DebugConstructBuffer(BYTE *buffer, COUNT_T size);
+    void DebugDestructBuffer(BYTE *buffer, COUNT_T size);
+
+    void DebugStompUnusedBuffer(BYTE *buffer, COUNT_T size);
+#ifdef _DEBUG
+    static BOOL EnsureGarbageCharOnly(const BYTE *buffer, COUNT_T size);
+#endif
+    CHECK CheckUnusedBuffer(const BYTE *buffer, COUNT_T size) const;
+
+#ifdef DACCESS_COMPILE
+public:
+
+    // Expose the raw Target address of the buffer to DAC.
+    // This does not do any marshalling. This can be useful if the caller wants to allocate the buffer on
+    // its own heap so that it can survive Flush calls.
+    MemoryRange DacGetRawBuffer() const
+    {
+        SUPPORTS_DAC;
+        PTR_VOID p = dac_cast<PTR_VOID>((TADDR) m_buffer);
+        return MemoryRange(p, GetSize());
+    }
+
+protected:
+
+    // Return a host copy of the buffer, allocated on the DAC heap (and thus invalidated at the next call to Flush).
+    void* DacGetRawContent(void) const
+    {
+        SUPPORTS_DAC;
+
+        // SBuffers are used in DAC in two ways - buffers in the host, and marshalled buffers from the target.
+        // This is a problem - we can't reason about the address space of the buffer statically, and instead rely on
+        // the dynamic usage (i.e. the methods are basically bifurcated into those you can use on host instances,
+        // and those you can use on marshalled copies).
+        // Ideally we'll have two versions of the SBuffer code - one that's marshalled (normal DACization) and one
+        // that isn't (host-only utility).  This is the "dual-mode DAC problem".
+        // But this only affects a couple classes, and so for now we'll ignore the problem - causing a bunch of DacCop
+        // violations.
+        DACCOP_IGNORE(CastBetweenAddressSpaces, "SBuffer has the dual-mode DAC problem");
+        DACCOP_IGNORE(FieldAccess, "SBuffer has the dual-mode DAC problem");
+        TADDR bufAddr = (TADDR)m_buffer;
+
+        return DacInstantiateTypeByAddress(bufAddr, m_size, true);
+    }
+
+    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) const
+    {
+        SUPPORTS_DAC;
+
+        if (flags != CLRDATA_ENUM_MEM_TRIAGE)
+        {
+            DacEnumMemoryRegion((TADDR)m_buffer, m_size);
+        }
+    }
+#endif
+
+    //----------------------------------------------------------------------------
+    // Iterator base class
+    //----------------------------------------------------------------------------
+
+    friend class CheckedIteratorBase<SBuffer>;
+
+    class EMPTY_BASES_DECL Index : public CheckedIteratorBase<SBuffer>
+    {
+        friend class SBuffer;
+
+        friend class CIterator;
+        friend class Indexer<const BYTE, CIterator>;
+
+        friend class Iterator;
+        friend class Indexer<BYTE, Iterator>;
+
+      protected:
+        BYTE* m_ptr;
+
+        Index();
+        Index(SBuffer *container, SCOUNT_T index);
+        BYTE &GetAt(SCOUNT_T delta) const;
+        void Skip(SCOUNT_T delta);
+        SCOUNT_T Subtract(const Index &i) const;
+
+        CHECK DoCheck(SCOUNT_T delta) const;
+
+        void Resync(const SBuffer *container, BYTE *value) const;
+    };
+
+  public:
+
+    class EMPTY_BASES_DECL CIterator : public Index, public Indexer<const BYTE, CIterator>
+    {
+        friend class SBuffer;
+
+    public:
+        CIterator()
+        {
+        }
+
+        CIterator(const SBuffer *buffer, int index)
+          : Index(const_cast<SBuffer*>(buffer), index)
+        {
+        }
+    };
+
+    class EMPTY_BASES_DECL Iterator : public Index, public Indexer<BYTE, Iterator>
+    {
+        friend class SBuffer;
+
+    public:
+        operator const CIterator &() const
+        {
+            return *(const CIterator *)this;
+        }
+
+        operator CIterator &()
+        {
+            return *(CIterator *)this;
+        }
+
+        Iterator()
+        {
+        }
+
+        Iterator(SBuffer *buffer, int index)
+          : Index(buffer, index)
+        {
+        }
+
+    };
+
+
+    //----------------------------------------------------------------------------
+    // Member and data declarations
+    //----------------------------------------------------------------------------
+
+  private:
+    enum
+    {
+        REPRESENTATION_MASK     = 0x07,
+        ALLOCATED               = 0x08,
+        IMMUTABLE               = 0x10,
+        OPENED                  = 0x20,
+        FLAG1                   = 0x40,
+        FLAG2                   = 0x80,
+        FLAG3                   = 0x100,
+    };
+
+    COUNT_T   m_size;           // externally visible size
+    COUNT_T   m_allocation;     // actual allocated size
+    UINT32    m_flags;          // @todo: steal flags from sizes
+
+  protected:
+    union {
+        BYTE     *m_buffer;
+        WCHAR    *m_asStr;     // For debugging, view as a unicode string
+    };
+
+#if _DEBUG
+  protected:
+    // We will update the "revision" of the buffer every time it is potentially reallocation,
+    // so we can tell when iterators are no longer valid.
+    int m_revision;
+#endif
+};
+
+// ================================================================================
+// InlineSBuffer : Tlempate for an SBuffer with preallocated buffer space
+// ================================================================================
+
+#define BUFFER_ALIGNMENT 4
+
+template <COUNT_T size>
+class EMPTY_BASES_DECL InlineSBuffer : public SBuffer
+{
+ private:
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4200) // zero sized array
+#pragma warning(disable:4324) // don't complain if DECLSPEC_ALIGN actually pads
+    DECLSPEC_ALIGN(BUFFER_ALIGNMENT) BYTE m_prealloc[size];
+#pragma warning(pop)
+#else
+     // use UINT64 to get maximum alignment of the memory
+     UINT64 m_prealloc[ALIGN(size,sizeof(UINT64))/sizeof(UINT64)];
+#endif // _MSC_VER
+
+ public:
+    InlineSBuffer()
+      : SBuffer(Prealloc, (BYTE*)m_prealloc, size)
+    {
+        WRAPPER_NO_CONTRACT;
+    }
+};
+
+
+// a 1K sized buffer filled with $ that we'll use in debug builds for verification
+#define GARBAGE_FILL_DWORD  0x24242424 // $$$$
+#define GARBAGE_FILL_BUFFER_ITEMS 16
+#define GARBAGE_FILL_BUFFER_SIZE GARBAGE_FILL_BUFFER_ITEMS*sizeof(DWORD)
+// ================================================================================
+// StackSBuffer : SBuffer with relatively large preallocated buffer for stack use
+// ================================================================================
+
+#define STACK_ALLOC 256
+
+typedef InlineSBuffer<STACK_ALLOC> StackSBuffer;
+
+// ================================================================================
+// Inline definitions
+// ================================================================================
+
+/// a wrapper for templates and such, that use "==".
+/// more expensive than a typical "==", though
+inline BOOL  operator == (const SBuffer& b1,const SBuffer& b2)
+{
+    return b1.Equals(b2);
+};
+
+#include <sbuffer.inl>
+
+#endif  // _SBUFFER_H_
diff --git a/src/inc/sbuffer.inl b/src/inc/sbuffer.inl
new file mode 100644 (file)
index 0000000..3da80bc
--- /dev/null
@@ -0,0 +1,1701 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+
+#ifndef _SBUFFER_INL_
+#define _SBUFFER_INL_
+
+#include "sbuffer.h"
+
+#if defined(_MSC_VER)
+#pragma inline_depth (20)
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4702) // Disable bogus unreachable code warning
+#endif // _MSC_VER
+
+inline SBuffer::SBuffer(PreallocFlag flag, void *buffer, COUNT_T size)
+  : m_size(0),
+    m_allocation(NULL),
+    m_flags(0),
+    m_buffer(NULL)
+{
+    CONTRACT_VOID
+    {
+        CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(buffer));
+        PRECONDITION(CheckSize(size));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    m_buffer = UseBuffer((BYTE *) buffer, &size);
+    m_allocation = size;
+
+#ifdef _DEBUG
+    m_revision = 0;
+#endif
+
+    RETURN;
+}
+
+inline SBuffer::SBuffer()
+  : m_size(0),
+    m_allocation(0),
+    m_flags(0),
+    m_buffer(NULL)
+{
+    CONTRACT_VOID
+    {
+        CONSTRUCTOR_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+#ifdef _DEBUG
+    m_revision = 0;
+#endif
+
+    RETURN;
+}
+
+inline SBuffer::SBuffer(COUNT_T size)
+  : m_size(0),
+    m_allocation(0),
+    m_flags(0),
+    m_buffer(NULL)
+{
+    CONTRACT_VOID
+    {;
+        CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckSize(size));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Resize(size);
+
+#ifdef _DEBUG
+    m_revision = 0;
+#endif
+
+    RETURN;
+}
+
+inline SBuffer::SBuffer(const SBuffer &buffer)
+  : m_size(0),
+    m_allocation(0),
+    m_flags(0),
+    m_buffer(NULL)
+{
+    CONTRACT_VOID
+    {
+        CONSTRUCTOR_CHECK;
+        PRECONDITION(buffer.Check());
+        POSTCONDITION(Equals(buffer));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Set(buffer);
+
+#ifdef _DEBUG
+    m_revision = 0;
+#endif
+
+    RETURN;
+}
+
+inline SBuffer::SBuffer(const BYTE *buffer, COUNT_T size)
+  : m_size(0),
+    m_allocation(0),
+    m_flags(0),
+    m_buffer(NULL)
+{
+    CONTRACT_VOID
+    {
+        CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(buffer));
+        PRECONDITION(CheckSize(size));
+        POSTCONDITION(Equals(buffer, size));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Set(buffer, size);
+
+#ifdef _DEBUG
+    m_revision = 0;
+#endif
+
+    RETURN;
+}
+
+
+inline SBuffer::SBuffer(ImmutableFlag immutable, const BYTE *buffer, COUNT_T size)
+  : m_size(size),
+    m_allocation(size),
+    m_flags(IMMUTABLE),
+    m_buffer(const_cast<BYTE*>(buffer))
+{
+    CONTRACT_VOID
+    {
+        CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(buffer));
+        PRECONDITION(CheckSize(size));
+        POSTCONDITION(Equals(buffer, size));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+#ifdef _DEBUG
+    m_revision = 0;
+#endif
+
+    RETURN;
+}
+
+inline SBuffer::~SBuffer()
+{
+    CONTRACT_VOID
+    {
+        NOTHROW;
+        DESTRUCTOR_CHECK;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (IsAllocated())
+    {
+        DeleteBuffer(m_buffer, m_allocation);
+    }
+
+#ifdef _DEBUG
+    m_revision = 0;
+#endif
+
+    RETURN;
+}
+
+inline void SBuffer::Set(const SBuffer &buffer)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(buffer.Check());
+        POSTCONDITION(Equals(buffer));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (buffer.IsImmutable()
+        && (IsImmutable() || m_allocation < buffer.GetSize()))
+    {
+        // Share immutable block rather than reallocate and copy
+        // (Note that we prefer to copy to our buffer if we
+        // don't have to reallocate it.)
+
+        if (IsAllocated())
+            DeleteBuffer(m_buffer, m_allocation);
+
+        m_size = buffer.m_size;
+        m_allocation = buffer.m_allocation;
+        m_buffer = buffer.m_buffer;
+        m_flags = buffer.m_flags;
+
+#if _DEBUG
+        // Increment our revision to invalidate iterators
+        m_revision++;
+#endif
+
+    }
+    else
+    {
+        Resize(buffer.m_size, DONT_PRESERVE);
+        EnsureMutable();
+
+        // PreFix seems to think it can choose m_allocation==0 and buffer.m_size > 0 here.
+        // From the code for Resize and EnsureMutable, this is clearly impossible.
+        PREFIX_ASSUME( (this->m_buffer != NULL) || (buffer.m_size == 0) );
+
+        MoveMemory(m_buffer, buffer.m_buffer, buffer.m_size);
+    }
+
+    RETURN;
+}
+
+inline void SBuffer::Set(const BYTE *buffer, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckSize(size));
+        POSTCONDITION(Equals(buffer, size));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Resize(size);
+    EnsureMutable();
+
+    // PreFix seems to think it can choose m_allocation==0 and size > 0 here.
+    // From the code for Resize, this is clearly impossible.
+    PREFIX_ASSUME( (this->m_buffer != NULL) || (size == 0) );
+
+    MoveMemory(m_buffer, buffer, size);
+
+    RETURN;
+}
+
+inline void SBuffer::SetImmutable(const BYTE *buffer, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckSize(size));
+        POSTCONDITION(Equals(buffer, size));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+
+    }
+    CONTRACT_END;
+
+    SBuffer temp(Immutable, buffer, size);
+
+    {
+        // This can't really throw
+        CONTRACT_VIOLATION(ThrowsViolation);
+        Set(temp);
+    }
+
+    RETURN;
+}
+
+inline COUNT_T SBuffer::GetSize() const
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+
+    return m_size;
+}
+
+inline void SBuffer::SetSize(COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckSize(size));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Resize(size);
+
+    RETURN;
+}
+
+inline void SBuffer::MaximizeSize()
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if (!IsImmutable())
+        Resize(m_allocation);
+
+    RETURN;
+}
+
+inline COUNT_T SBuffer::GetAllocation() const
+{
+    CONTRACT(COUNT_T)
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    RETURN m_allocation;
+}
+
+inline void SBuffer::Preallocate(COUNT_T allocation) const
+{
+    CONTRACT_VOID
+    {
+        if (allocation) THROWS; else NOTHROW;
+        INSTANCE_CHECK;
+        PRECONDITION(CheckAllocation(allocation));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (allocation > m_allocation)
+        const_cast<SBuffer *>(this)->ReallocateBuffer(allocation, PRESERVE);
+
+    RETURN;
+}
+
+inline void SBuffer::Trim() const
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if (!IsImmutable())
+        const_cast<SBuffer *>(this)->ReallocateBuffer(m_size, PRESERVE);
+
+    RETURN;
+}
+
+inline void SBuffer::Zero()
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    ZeroMemory(m_buffer, m_size);
+
+    RETURN;
+}
+
+inline void SBuffer::Fill(BYTE value)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    memset(m_buffer, value, m_size);
+
+    RETURN;
+}
+
+inline void SBuffer::Fill(const Iterator &i, BYTE value, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i, size));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    memset(i.m_ptr, value, size);
+
+    RETURN;
+}
+
+inline void SBuffer::Copy(const Iterator &to, const CIterator &from, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(to, size));
+        PRECONDITION(CheckIteratorRange(from, size));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    DebugDestructBuffer(to.m_ptr, size);
+
+    DebugCopyConstructBuffer(to.m_ptr, from.m_ptr, size);
+
+    RETURN;
+}
+
+inline void SBuffer::Move(const Iterator &to, const CIterator &from, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(to, size));
+        PRECONDITION(CheckIteratorRange(from, size));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    DebugDestructBuffer(to.m_ptr, size);
+
+    DebugMoveBuffer(to.m_ptr, from.m_ptr, size);
+
+    DebugConstructBuffer(from.m_ptr, size);
+
+    RETURN;
+}
+
+inline void SBuffer::Copy(const Iterator &i, const SBuffer &source)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i, source.GetSize()));
+        PRECONDITION(source.Check());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    DebugDestructBuffer(i.m_ptr, source.m_size);
+
+    DebugCopyConstructBuffer(i.m_ptr, source.m_buffer, source.m_size);
+
+    RETURN;
+}
+
+inline void SBuffer::Copy(const Iterator &i, const void *source, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckSize(size));
+        PRECONDITION(CheckIteratorRange(i, size));
+        PRECONDITION(CheckPointer(source, size == 0 ? NULL_OK : NULL_NOT_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    DebugDestructBuffer(i.m_ptr, size);
+
+    DebugCopyConstructBuffer(i.m_ptr, (const BYTE *) source, size);
+
+    RETURN;
+}
+
+inline void SBuffer::Copy(void *dest, const CIterator &i, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckSize(size));
+        PRECONDITION(CheckIteratorRange(i, size));
+        PRECONDITION(CheckPointer(dest, size == 0 ? NULL_OK : NULL_NOT_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    memcpy(dest, i.m_ptr, size);
+
+    RETURN;
+}
+
+inline void SBuffer::Insert(const Iterator &i, const SBuffer &source)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        PRECONDITION(CheckIteratorRange(i,0));
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Replace(i, 0, source.GetSize());
+    Copy(i, source, source.GetSize());
+
+    RETURN;
+}
+
+inline void SBuffer::Insert(const Iterator &i, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        PRECONDITION(CheckIteratorRange(i,0));
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Replace(i, 0, size);
+
+    RETURN;
+}
+
+inline void SBuffer::Clear()
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Delete(Begin(), GetSize());
+
+    RETURN;
+}
+
+inline void SBuffer::Delete(const Iterator &i, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i, size));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Replace(i, size, 0);
+
+    RETURN;
+}
+
+inline void SBuffer::Replace(const Iterator &i, COUNT_T deleteSize, const SBuffer &insert)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i, deleteSize));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Replace(i, deleteSize, insert.GetSize());
+    Copy(i, insert, insert.GetSize());
+
+    RETURN;
+}
+
+inline int SBuffer::Compare(const SBuffer &compare) const
+{
+    CONTRACT(int)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(compare.Check());
+        POSTCONDITION(RETVAL == -1 || RETVAL == 0 || RETVAL == 1);
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    RETURN Compare(compare.m_buffer, compare.m_size);
+}
+
+inline int SBuffer::Compare(const BYTE *compare, COUNT_T size) const
+{
+    CONTRACT(int)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(compare));
+        PRECONDITION(CheckSize(size));
+        POSTCONDITION(RETVAL == -1 || RETVAL == 0 || RETVAL == 1);
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    COUNT_T smaller;
+    int equals;
+    int result;
+
+    if (m_size < size)
+    {
+        smaller = m_size;
+        equals = -1;
+    }
+    else if (m_size > size)
+    {
+        smaller = size;
+        equals = 1;
+    }
+    else
+    {
+        smaller = size;
+        equals = 0;
+    }
+
+    result = memcmp(m_buffer, compare, size);
+
+    if (result == 0)
+        RETURN equals;
+    else
+        RETURN result;
+}
+
+inline BOOL SBuffer::Equals(const SBuffer &compare) const
+{
+    CONTRACT(int)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(compare.Check());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    RETURN Equals(compare.m_buffer, compare.m_size);
+}
+
+inline BOOL SBuffer::Equals(const BYTE *compare, COUNT_T size) const
+{
+    CONTRACT(int)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(compare));
+        PRECONDITION(CheckSize(size));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if (m_size != size)
+        RETURN FALSE;
+    else
+        RETURN (memcmp(m_buffer, compare, size) == 0);
+}
+
+inline BOOL SBuffer::Match(const CIterator &i, const SBuffer &match) const
+{
+    CONTRACT(int)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(match.Check());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    RETURN Match(i, match.m_buffer, match.m_size);
+}
+
+inline BOOL SBuffer::Match(const CIterator &i, const BYTE *match, COUNT_T size) const
+{
+    CONTRACT(int)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(match));
+        PRECONDITION(CheckSize(size));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    COUNT_T remaining = (COUNT_T) (m_buffer + m_size - i.m_ptr);
+
+    if (remaining < size)
+        RETURN FALSE;
+
+    RETURN (memcmp(i.m_ptr, match, size) == 0);
+}
+
+//----------------------------------------------------------------------------
+// EnsureMutable
+// Ensures that the buffer is mutable
+//----------------------------------------------------------------------------
+inline void SBuffer::EnsureMutable() const
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckBufferClosed());
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (IsImmutable())
+        const_cast<SBuffer *>(this)->ReallocateBuffer(m_allocation, PRESERVE);
+
+    RETURN;
+}
+
+//----------------------------------------------------------------------------
+// Resize
+// Change the visible size of the buffer; realloc if necessary
+//----------------------------------------------------------------------------
+FORCEINLINE void SBuffer::Resize(COUNT_T size, Preserve preserve)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckSize(size));
+        POSTCONDITION(GetSize() == size);
+        POSTCONDITION(m_allocation >= GetSize());
+        POSTCONDITION(CheckInvariant(*this));
+        if (size > 0) THROWS; else NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+#ifdef _DEBUG
+    // Change our revision
+    m_revision++;
+#endif
+
+    SCOUNT_T delta = size - m_size;
+
+    if (delta < 0)
+        DebugDestructBuffer(m_buffer + size, -delta);
+
+    // Only actually allocate if we are growing
+    if (size > m_allocation)
+        ReallocateBuffer(size, preserve);
+
+    if (delta > 0)
+        DebugConstructBuffer(m_buffer + m_size, delta);
+
+    m_size = size;
+
+    RETURN;
+}
+
+//----------------------------------------------------------------------------
+// ResizePadded
+// Change the visible size of the buffer; realloc if necessary
+// add extra space to minimize further growth
+//----------------------------------------------------------------------------
+inline void SBuffer::ResizePadded(COUNT_T size, Preserve preserve)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckSize(size));
+        POSTCONDITION(GetSize() == size);
+        POSTCONDITION(m_allocation >= GetSize());
+        POSTCONDITION(CheckInvariant(*this));
+        if (size > 0) THROWS; else NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+#ifdef _DEBUG
+    // Change our revision
+    m_revision++;
+#endif
+
+    SCOUNT_T delta = size - m_size;
+
+    if (delta < 0)
+        DebugDestructBuffer(m_buffer + size, -delta);
+
+    // Only actually allocate if we are growing
+    if (size > m_allocation)
+    {
+        COUNT_T padded = (size*3)/2;
+
+        ReallocateBuffer(padded, preserve);
+    }
+
+    if (delta > 0)
+        DebugConstructBuffer(m_buffer + m_size, delta);
+
+    m_size = size;
+
+    RETURN;
+}
+
+//----------------------------------------------------------------------------
+// TweakSize
+// An optimized form of Resize, which can only adjust the size within the
+// currently allocated range, and never reallocates
+//----------------------------------------------------------------------------
+inline void SBuffer::TweakSize(COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckSize(size));
+        PRECONDITION(size <= GetAllocation());
+        POSTCONDITION(GetSize() == size);
+        POSTCONDITION(CheckInvariant(*this));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+#ifdef _DEBUG
+    // Change our revision
+    m_revision++;
+#endif
+
+    SCOUNT_T delta = size - m_size;
+
+    if (delta < 0)
+        DebugDestructBuffer(m_buffer + size, -delta);
+    else
+        DebugConstructBuffer(m_buffer + m_size, delta);
+
+    m_size = size;
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// SBuffer allocates all memory via NewBuffer & DeleteBuffer members.
+// If SBUFFER_CANARY_CHECKS is defined, NewBuffer will place Canaries at the start
+// and end of the buffer to detect overflows.
+//-----------------------------------------------------------------------------
+
+#ifdef _DEBUG
+#define SBUFFER_CANARY_CHECKS 1
+#endif
+
+#ifdef SBUFFER_CANARY_CHECKS
+
+// The value we place at the start/end of the buffer,
+static const UINT64 SBUFFER_CANARY_VALUE = UI64(0xD00BED00BED00BAA);
+
+// Expose the quantity of padding needed when providing a prealloced
+// buffer. This is an unrolled version of the actualAllocation calculated
+// below for use as a constant value for InlineSString<X> to use. It is
+// padded with one additional sizeof(SBUFFER_CANARY_VALUE) to account for
+// possible alignment problems issues (pre- and post-padding).
+#define SBUFFER_PADDED_SIZE(desiredUsefulSize) \
+    ((((SIZE_T)(desiredUsefulSize) + sizeof(SBUFFER_CANARY_VALUE) - 1) & \
+    ~(sizeof(SBUFFER_CANARY_VALUE)-1)) + 3 * sizeof(SBUFFER_CANARY_VALUE))
+
+#else // SBUFFER_CANARY_CHECKS
+
+#define SBUFFER_PADDED_SIZE(desiredUsefulSize) (desiredUsefulSize)
+
+#endif // SBUFFER_CANARY_CHECKS else
+
+// Must match expected guaranteed alignment of new []
+#ifdef ALIGN_ACCESS
+static const int SBUFFER_ALIGNMENT = ALIGN_ACCESS;
+#else
+// This is only 4 bytes on win98 and below
+static const int SBUFFER_ALIGNMENT = 4;
+#endif
+
+//----------------------------------------------------------------------------
+// Allocate memory, use canaries.
+//----------------------------------------------------------------------------
+inline BYTE *SBuffer::NewBuffer(COUNT_T allocation)
+{
+    CONTRACT(BYTE*)
+    {
+        PRECONDITION(CheckSize(allocation));
+        PRECONDITION(allocation > 0);
+        POSTCONDITION(CheckPointer(RETVAL));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+#ifdef SBUFFER_CANARY_CHECKS
+
+    COUNT_T alignPadding = AlignmentPad(allocation, sizeof(SBUFFER_CANARY_VALUE));
+    COUNT_T actualAllocation= sizeof(SBUFFER_CANARY_VALUE) + allocation + alignPadding + sizeof(SBUFFER_CANARY_VALUE);
+    BYTE *raw = new BYTE [actualAllocation];
+
+    *(UINT64*) raw = SBUFFER_CANARY_VALUE;
+    *(UINT64*) (raw + sizeof(SBUFFER_CANARY_VALUE) + allocation + alignPadding) = SBUFFER_CANARY_VALUE;
+
+    BYTE *buffer = raw + sizeof(SBUFFER_CANARY_VALUE);
+
+#else
+
+    BYTE *buffer = new BYTE [allocation];
+
+#endif
+
+    DebugStompUnusedBuffer(buffer, allocation);
+
+    CONSISTENCY_CHECK(CheckBuffer(buffer, allocation));
+
+    RETURN buffer;
+}
+
+//----------------------------------------------------------------------------
+// Use existing memory, use canaries.
+//----------------------------------------------------------------------------
+inline BYTE *SBuffer::UseBuffer(BYTE *buffer, COUNT_T *allocation)
+{
+    CONTRACT(BYTE*)
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC_HOST_ONLY;
+        PRECONDITION(CheckPointer(buffer));
+        PRECONDITION(CheckSize(*allocation));
+//        POSTCONDITION(CheckPointer(RETVAL));
+        POSTCONDITION(CheckSize(*allocation));
+    }
+    CONTRACT_END;
+
+#ifdef SBUFFER_CANARY_CHECKS
+
+    COUNT_T prepad = AlignmentPad((SIZE_T) buffer, sizeof(SBUFFER_CANARY_VALUE));
+    COUNT_T postpad = AlignmentTrim((SIZE_T) buffer+*allocation, sizeof(SBUFFER_CANARY_VALUE));
+
+    SCOUNT_T usableAllocation = *allocation - prepad - sizeof(SBUFFER_CANARY_VALUE) - sizeof(SBUFFER_CANARY_VALUE) - postpad;
+    if (usableAllocation <= 0)
+    {
+        buffer = NULL;
+        *allocation = 0;
+    }
+    else
+    {
+        BYTE *result = buffer + prepad + sizeof(SBUFFER_CANARY_VALUE);
+
+        *(UINT64*) (buffer + prepad) = SBUFFER_CANARY_VALUE;
+        *(UINT64*) (buffer + prepad + sizeof(SBUFFER_CANARY_VALUE) + usableAllocation) = SBUFFER_CANARY_VALUE;
+
+        buffer = result;
+        *allocation = usableAllocation;
+    }
+
+#endif
+
+    DebugStompUnusedBuffer(buffer, *allocation);
+
+    CONSISTENCY_CHECK(CheckBuffer(buffer, *allocation));
+
+    RETURN buffer;
+}
+
+//----------------------------------------------------------------------------
+// Free memory allocated by NewHelper
+//----------------------------------------------------------------------------
+inline void SBuffer::DeleteBuffer(BYTE *buffer, COUNT_T allocation)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CheckSize(allocation));
+        POSTCONDITION(CheckPointer(buffer));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    CONSISTENCY_CHECK(CheckBuffer(buffer, allocation));
+
+#ifdef SBUFFER_CANARY_CHECKS
+
+    delete [] (buffer - sizeof(SBUFFER_CANARY_VALUE));
+
+#else
+
+    delete [] buffer;
+
+#endif
+
+    RETURN;
+}
+
+//----------------------------------------------------------------------------
+// Check the buffer at the given address. The memory must have been a pointer
+// returned by NewHelper.
+//----------------------------------------------------------------------------
+inline CHECK SBuffer::CheckBuffer(const BYTE *buffer, COUNT_T allocation) const
+{
+    CONTRACT_CHECK
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        PRECONDITION(CheckPointer(buffer));
+    }
+    CONTRACT_CHECK_END;
+
+    if (allocation > 0)
+    {
+#ifdef SBUFFER_CANARY_CHECKS
+        const BYTE *raw = buffer - sizeof(SBUFFER_CANARY_VALUE);
+
+        COUNT_T alignPadding    = ((allocation + (sizeof(SBUFFER_CANARY_VALUE) - 1)) & ~((sizeof(SBUFFER_CANARY_VALUE) - 1))) - allocation;
+
+        CHECK_MSG(*(UINT64*) raw == SBUFFER_CANARY_VALUE, "SBuffer underflow");
+        CHECK_MSG(*(UINT64*) (raw + sizeof(SBUFFER_CANARY_VALUE) + allocation + alignPadding) == SBUFFER_CANARY_VALUE, "SBuffer overflow");
+
+#endif
+
+        CHECK_MSG((((SIZE_T)buffer) & (SBUFFER_ALIGNMENT-1)) == 0, "SBuffer not properly aligned");
+    }
+
+    CHECK_OK;
+}
+
+
+inline BYTE *SBuffer::OpenRawBuffer(COUNT_T size)
+{
+    CONTRACT(BYTE*)
+    {
+#if _DEBUG
+        PRECONDITION_MSG(!IsOpened(), "Can't nest calls to OpenBuffer()");
+#endif
+        PRECONDITION(CheckSize(size));
+        POSTCONDITION(GetSize() == size);
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    Resize(size);
+    EnsureMutable();
+
+#if _DEBUG
+    SetOpened();
+#endif
+
+    RETURN m_buffer;
+}
+
+//----------------------------------------------------------------------------
+// Close an open buffer. Assumes that we wrote exactly number of characters
+// we requested in OpenBuffer.
+//----------------------------------------------------------------------------
+inline void SBuffer::CloseRawBuffer()
+{
+    CONTRACT_VOID
+    {
+#if _DEBUG
+        PRECONDITION(IsOpened());
+#endif
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    CloseRawBuffer(m_size);
+
+    RETURN;
+}
+
+//----------------------------------------------------------------------------
+// CloseBuffer() tells the SBuffer that we're done using the unsafe buffer.
+// finalSize is the count of bytes actually used (so we can set m_count).
+// This is important if we request a buffer larger than what we actually
+// used.
+//----------------------------------------------------------------------------
+inline void SBuffer::CloseRawBuffer(COUNT_T finalSize)
+{
+    CONTRACT_VOID
+    {
+#if _DEBUG
+        PRECONDITION_MSG(IsOpened(),  "Can only CloseRawBuffer() after a call to OpenRawBuffer()");
+#endif
+        PRECONDITION(CheckSize(finalSize));
+        PRECONDITION_MSG(finalSize <= GetSize(), "Can't use more characters than requested via OpenRawBuffer()");
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+#if _DEBUG
+    ClearOpened();
+#endif
+
+    TweakSize(finalSize);
+
+    CONSISTENCY_CHECK(CheckBuffer(m_buffer, m_allocation));
+
+    RETURN;
+}
+
+inline SBuffer::operator const void *() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (void *) m_buffer;
+}
+
+inline SBuffer::operator const BYTE *() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return m_buffer;
+}
+
+inline BYTE &SBuffer::operator[](int index)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_buffer[index];
+}
+
+inline const BYTE &SBuffer::operator[](int index) const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_buffer[index];
+}
+
+inline SBuffer::Iterator SBuffer::Begin()
+{
+    CONTRACT(SBuffer::Iterator)
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    // This is a bit unfortunate to have to do here, but it's our
+    // last opportunity before possibly doing a *i= with the iterator
+    EnsureMutable();
+
+    RETURN Iterator(this, 0);
+}
+
+inline SBuffer::Iterator SBuffer::End()
+{
+    CONTRACT(SBuffer::Iterator)
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    // This is a bit unfortunate to have to do here, but it's our
+    // last opportunity before possibly doing a *i= with the iterator
+    EnsureMutable();
+
+    RETURN Iterator(this, m_size);
+}
+
+inline SBuffer::CIterator SBuffer::Begin() const
+{
+    CONTRACT(SBuffer::CIterator)
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    RETURN SBuffer::CIterator(this, 0);
+}
+
+inline SBuffer::CIterator SBuffer::End() const
+{
+    CONTRACT(SBuffer::CIterator)
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    RETURN CIterator(const_cast<SBuffer*>(this), m_size);
+}
+
+inline BOOL SBuffer::IsAllocated() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (m_flags & ALLOCATED) != 0;
+}
+
+inline void SBuffer::SetAllocated()
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    m_flags |= ALLOCATED;
+}
+
+inline void SBuffer::ClearAllocated()
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    m_flags &= ~ALLOCATED;
+}
+
+inline BOOL SBuffer::IsImmutable() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (m_flags & IMMUTABLE) != 0;
+}
+
+inline void SBuffer::SetImmutable()
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    m_flags |= IMMUTABLE;
+}
+
+inline void SBuffer::ClearImmutable()
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    m_flags &= ~IMMUTABLE;
+}
+
+inline BOOL SBuffer::IsFlag1() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (m_flags & FLAG1) != 0;
+}
+
+inline void SBuffer::SetFlag1()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    m_flags |= FLAG1;
+}
+
+inline void SBuffer::ClearFlag1()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    m_flags &= ~FLAG1;
+}
+
+inline BOOL SBuffer::IsFlag2() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (m_flags & FLAG2) != 0;
+}
+
+inline void SBuffer::SetFlag2()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    m_flags |= FLAG2;
+}
+
+inline void SBuffer::ClearFlag2()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    m_flags &= ~FLAG2;
+}
+
+inline BOOL SBuffer::IsFlag3() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (m_flags & FLAG3) != 0;
+}
+
+inline void SBuffer::SetFlag3()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    m_flags |= FLAG3;
+}
+
+inline void SBuffer::ClearFlag3()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    m_flags &= ~FLAG3;
+}
+
+inline int SBuffer::GetRepresentationField() const
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+
+    return (m_flags & REPRESENTATION_MASK);
+}
+
+inline void SBuffer::SetRepresentationField(int value)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION((value & ~REPRESENTATION_MASK) == 0);
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    m_flags &= ~REPRESENTATION_MASK;
+    m_flags |= value;
+
+    RETURN;
+}
+
+#if _DEBUG
+inline BOOL SBuffer::IsOpened() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (m_flags & OPENED) != 0;
+}
+
+inline void SBuffer::SetOpened()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    m_flags |= OPENED;
+}
+
+inline void SBuffer::ClearOpened()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    m_flags &= ~OPENED;
+}
+#endif
+
+inline void SBuffer::DebugMoveBuffer(_Out_writes_bytes_(size) BYTE *to, BYTE *from, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(to, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckPointer(from, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckSize(size));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (size == 0) // special case
+      RETURN;
+
+    // Handle overlapping ranges
+    if (to > from && to < from + size)
+        CONSISTENCY_CHECK(CheckUnusedBuffer(from + size, (COUNT_T) (to - from)));
+    else if (to < from && to + size > from)
+        CONSISTENCY_CHECK(CheckUnusedBuffer(to, (COUNT_T) (from - to)));
+    else
+        CONSISTENCY_CHECK(CheckUnusedBuffer(to, size));
+
+    memmove(to, from, size);
+
+    // Handle overlapping ranges
+    if (to > from && to < from + size)
+        DebugStompUnusedBuffer(from, (COUNT_T) (to - from));
+    else if (to < from && to + size > from)
+        DebugStompUnusedBuffer(to + size, (COUNT_T) (from - to));
+    else
+        DebugStompUnusedBuffer(from, size);
+
+    RETURN;
+}
+
+inline void SBuffer::DebugCopyConstructBuffer(_Out_writes_bytes_(size) BYTE *to, const BYTE *from, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(to, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckPointer(from, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckSize(size));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (size != 0) {
+        CONSISTENCY_CHECK(CheckUnusedBuffer(to, size));
+        memmove(to, from, size);
+    }
+
+    RETURN;
+}
+
+inline void SBuffer::DebugConstructBuffer(BYTE *buffer, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckSize(size));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+        DEBUG_ONLY;
+    }
+    CONTRACT_END;
+
+    if (size != 0) {
+      CONSISTENCY_CHECK(CheckUnusedBuffer(buffer, size));
+    }
+
+    RETURN;
+}
+
+inline void SBuffer::DebugDestructBuffer(BYTE *buffer, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckSize(size));
+        NOTHROW;
+        GC_NOTRIGGER;
+        DEBUG_ONLY;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (size != 0)
+    {
+        DebugStompUnusedBuffer(buffer, size);
+    }
+
+    RETURN;
+}
+
+static const BYTE GARBAGE_FILL_CHARACTER = '$';
+
+extern const DWORD g_garbageFillBuffer[];
+
+inline void SBuffer::DebugStompUnusedBuffer(BYTE *buffer, COUNT_T size)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
+        PRECONDITION(CheckSize(size));
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        DEBUG_ONLY;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+#if _DEBUG
+    if (!IsImmutable()
+        || buffer < m_buffer || buffer > m_buffer + m_allocation) // Allocating a new buffer
+    {
+        // Whack the memory
+        if (size > GARBAGE_FILL_BUFFER_SIZE) size = GARBAGE_FILL_BUFFER_SIZE;
+        memset(buffer, GARBAGE_FILL_CHARACTER, size);
+    }
+#endif
+
+    RETURN;
+}
+
+#if _DEBUG
+inline BOOL SBuffer::EnsureGarbageCharOnly(const BYTE *buffer, COUNT_T size)
+{
+    LIMITED_METHOD_CONTRACT;
+    BOOL bRet = TRUE;
+    if (size > GARBAGE_FILL_BUFFER_SIZE)
+    {
+        size = GARBAGE_FILL_BUFFER_SIZE;
+    }
+    if (bRet && size > 0)
+    {
+        bRet &= (memcmp(buffer, g_garbageFillBuffer, size) == 0);
+    }
+    return bRet;
+}
+#endif
+
+inline CHECK SBuffer::CheckUnusedBuffer(const BYTE *buffer, COUNT_T size) const
+{
+    WRAPPER_NO_CONTRACT;
+    // This check is too expensive.
+#if 0 // _DEBUG
+    if (!IsImmutable()
+        || buffer < m_buffer || buffer > m_buffer + m_allocation) // Allocating a new buffer
+    {
+        if (!SBuffer::EnsureGarbageCharOnly(buffer, size))
+        {
+            CHECK_FAIL("Overwrite of unused buffer region found");
+        }
+    }
+#endif
+    CHECK_OK;
+}
+
+inline CHECK SBuffer::Check() const
+{
+    WRAPPER_NO_CONTRACT;
+    CHECK(CheckBufferClosed());
+    CHECK_OK;
+}
+
+inline CHECK SBuffer::Invariant() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    CHECK_OK;
+}
+
+inline CHECK SBuffer::InternalInvariant() const
+{
+    WRAPPER_NO_CONTRACT;
+    CHECK(m_size <= m_allocation);
+
+    CHECK(CheckUnusedBuffer(m_buffer + m_size, m_allocation - m_size));
+
+    if (IsAllocated())
+        CHECK(CheckBuffer(m_buffer, m_allocation));
+
+    CHECK_OK;
+}
+
+inline CHECK SBuffer::CheckBufferClosed() const
+{
+    WRAPPER_NO_CONTRACT;
+#if _DEBUG
+    CHECK_MSG(!IsOpened(), "Cannot use buffer API while raw open is in progress");
+#endif
+    CHECK_OK;
+}
+
+inline CHECK SBuffer::CheckSize(COUNT_T size)
+{
+    LIMITED_METHOD_CONTRACT;
+    // !todo: add any range checking here
+    CHECK_OK;
+}
+
+inline CHECK SBuffer::CheckAllocation(COUNT_T size)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    // !todo: add any range checking here
+    CHECK_OK;
+}
+
+inline CHECK SBuffer::CheckIteratorRange(const CIterator &i) const
+{
+    WRAPPER_NO_CONTRACT;
+    CHECK(i.Check());
+    CHECK(i.CheckContainer(this));
+    CHECK(i >= Begin());
+    CHECK(i < End());
+    CHECK_OK;
+}
+
+inline CHECK SBuffer::CheckIteratorRange(const CIterator &i, COUNT_T size) const
+{
+    WRAPPER_NO_CONTRACT;
+    CHECK(i.Check());
+    CHECK(i.CheckContainer(this));
+    CHECK(i >= Begin());
+    CHECK(i + size <= End());
+    CHECK_OK;
+}
+
+inline SBuffer::Index::Index()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    m_ptr = NULL;
+}
+
+inline SBuffer::Index::Index(SBuffer *container, SCOUNT_T index)
+  : CheckedIteratorBase<SBuffer>(container)
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    m_ptr = container->m_buffer + index;
+}
+
+inline BYTE &SBuffer::Index::GetAt(SCOUNT_T delta) const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return m_ptr[delta];
+}
+
+inline void SBuffer::Index::Skip(SCOUNT_T delta)
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    m_ptr += delta;
+}
+
+inline SCOUNT_T SBuffer::Index::Subtract(const Index &i) const
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    return (SCOUNT_T) (m_ptr - i.m_ptr);
+}
+
+inline CHECK SBuffer::Index::DoCheck(SCOUNT_T delta) const
+{
+    WRAPPER_NO_CONTRACT;
+#if _DEBUG
+    CHECK(m_ptr + delta >= GetContainerDebug()->m_buffer);
+    CHECK(m_ptr + delta < GetContainerDebug()->m_buffer + GetContainerDebug()->m_size);
+#endif
+    CHECK_OK;
+}
+
+inline void SBuffer::Index::Resync(const SBuffer *buffer, BYTE *value) const
+{
+    CONTRACT_VOID
+    {
+        // INSTANCE_CHECK -  Iterator is out of sync with its object now by definition
+        POSTCONDITION(CheckPointer(this));
+        PRECONDITION(CheckPointer(buffer));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    const_cast<Index*>(this)->CheckedIteratorBase<SBuffer>::Resync(const_cast<SBuffer*>(buffer));
+    const_cast<Index*>(this)->m_ptr = value;
+
+    RETURN;
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+
+#endif  // _SBUFFER_INL_
diff --git a/src/inc/securityutil.h b/src/inc/securityutil.h
new file mode 100644 (file)
index 0000000..1cda814
--- /dev/null
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#ifndef SECURITYUTIL_H
+#define SECURITYUTIL_H
+
+#include "winnt.h"
+
+// Security utility class. This is currently used by the debugger right-side and dbgshim to figure out the
+// SECURITY_ATTRIBUTES to use on various IPC objects (named events, etc.).
+// This is pretty debugger specific, and so perhaps doesn't actually belong in utilcode (that's just the most
+// convenient way to share it between mscordbi and dbgshim.dll).  This is also a pretty big mess.  All of
+// this ACL craziness is already gone in Arrowhead, so it's not a high priority to clean this up.
+class SecurityUtil
+{
+public:
+
+    //
+    // This will generate ACL containing the current process and
+    // an allowed ACE on the target process of the given pid.
+    //
+    // Host should free returned *ppACL by calling FreeACL
+    //
+    static HRESULT GetACLOfPid(DWORD pid, PACL *ppACL);
+
+    static void FreeACL(PACL pACL);
+
+    static HRESULT GetMandatoryLabelFromProcess(HANDLE hProcess, LPBYTE * ppbLabel);
+    static DWORD * GetIntegrityLevelFromMandatorySID(PSID psidIntegrityLevelLabel);
+
+    // instance functions. SecurityUtil is used to minimized memory allocation when converting
+    // pACL to SECURITY_ATTRIBUTES
+    // The needed memory to hold SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR are embedded
+    // in the SecurityUtil instance.
+    //
+    SecurityUtil(PACL pACL);
+    ~SecurityUtil();
+    HRESULT Init();
+    HRESULT Init(HANDLE pid);
+    HRESULT GetSA(SECURITY_ATTRIBUTES **PPSA);
+private:
+    HRESULT SetSecurityDescriptorMandatoryLabel(PSID psidIntegrityLevelLabel);
+    SECURITY_ATTRIBUTES m_SA;
+    SECURITY_DESCRIPTOR m_SD;
+    PACL                m_pACL;
+    // Saved by SetSecurityDescriptorMandatoryLabel so that the memory can be deleted properly
+    PACL                m_pSacl;
+    bool                m_fInitialized;
+};
+
+#endif // !SECURITYUTIL_H
diff --git a/src/inc/securitywrapper.h b/src/inc/securitywrapper.h
new file mode 100644 (file)
index 0000000..63d7e17
--- /dev/null
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// File: SecurityWrapper.h
+//
+// Wrapper around Win32 Security functions
+//
+//*****************************************************************************
+
+
+#ifndef _SECURITY_WRAPPER_H
+#define _SECURITY_WRAPPER_H
+
+#ifdef TARGET_UNIX
+#error This file should not be included on non-Windows platforms.
+#endif
+
+//-----------------------------------------------------------------------------
+// Wrapper around a PSID.
+// This class does not own the memory.
+//-----------------------------------------------------------------------------
+class Sid
+{
+public:
+    // Initial the Sid wrapper around an existing SID.
+    Sid(PSID pSid);
+    static bool Equals(const Sid & a, const Sid & b) { return Equals(a.m_pSid, b.m_pSid); }
+    static bool Equals(const Sid & a, PSID b)        { return Equals(a.m_pSid, b); }
+    static bool Equals(PSID a, const Sid & b)        { return Equals(a, b.m_pSid); }
+    static bool Equals(PSID a, PSID b);
+
+    PSID RawSid() { return m_pSid; }
+protected:
+    // Pointer to Sid buffer. We don't owner the data.
+    PSID m_pSid;
+};
+
+//-----------------------------------------------------------------------------
+// Wrapper around a PSID with buffer.
+//-----------------------------------------------------------------------------
+class SidBuffer
+{
+public:
+    SidBuffer();
+    ~SidBuffer();
+
+    // Get the underlying sid
+    Sid GetSid();
+
+    // Do we not have a sid? This will be true if init fails.
+    bool IsNull() { return m_pBuffer == NULL; }
+
+    // Go to definitions to see detailed comments
+    HRESULT InitFromProcessNoThrow(DWORD pid);
+    void InitFromProcess(DWORD pid); // throws
+    HRESULT InitFromProcessUserNoThrow(DWORD pid);
+    void InitFromProcessUser(DWORD pid); // throws
+    HRESULT InitFromProcessAppContainerSidNoThrow(DWORD pid);
+
+protected:
+    BYTE * m_pBuffer;
+};
+
+//-----------------------------------------------------------------------------
+// Access Control List.
+//-----------------------------------------------------------------------------
+class Dacl
+{
+public:
+    Dacl(PACL pAcl);
+
+    SIZE_T GetAceCount();
+    ACE_HEADER * GetAce(SIZE_T dwAceIndex);
+protected:
+    PACL m_acl;
+};
+
+//-----------------------------------------------------------------------------
+// Represent a win32 SECURITY_DESCRIPTOR object.
+// (Note there's a "SecurityDescriptor" class in the VM for managed goo,
+// so we prefix this with "Win32" to avoid a naming collision.)
+//-----------------------------------------------------------------------------
+class Win32SecurityDescriptor
+{
+public:
+    Win32SecurityDescriptor();
+    ~Win32SecurityDescriptor();
+
+    HRESULT InitFromHandleNoThrow(HANDLE h);
+    void InitFromHandle(HANDLE h); // throws
+
+    // Gets the owner SID from this SecurityDescriptor.
+    HRESULT GetOwnerNoThrow( PSID* ppSid );
+    Sid GetOwner(); // throws
+    Dacl GetDacl(); // throws
+
+protected:
+    PSECURITY_DESCRIPTOR m_pDesc;
+};
+
+
+#endif // _SECURITY_WRAPPER_H
index 82430e6f058f5b564b9b97205e391311fe65b9cd..e7fb503c6bf80d75b7b76051fdf49364c69aac93 100644 (file)
@@ -9,16 +9,22 @@
 #ifndef _H_SIGPARSER
 #define _H_SIGPARSER
 
+#ifndef LIMITED_METHOD_DAC_CONTRACT 
 #define LIMITED_METHOD_DAC_CONTRACT ((void)0)
+#endif
+#ifndef LIMITED_METHOD_CONTRACT 
 #define LIMITED_METHOD_CONTRACT ((void)0)
+#endif
+#ifndef WRAPPER_NO_CONTRACT 
 #define WRAPPER_NO_CONTRACT ((void)0)
+#endif
+#ifndef SUPPORTS_DAC 
 #define SUPPORTS_DAC ((void)0)
-
+#endif
 #ifndef _ASSERT
 #define _ASSERT _ASSERTE
 #endif
 
-#include "utilcode.h"
 #include "corhdr.h"
 
 #include <minipal/utils.h>
diff --git a/src/inc/sstring.h b/src/inc/sstring.h
new file mode 100644 (file)
index 0000000..c2c3b9c
--- /dev/null
@@ -0,0 +1,1033 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// SString.h  (Safe String)
+//
+
+// ---------------------------------------------------------------------------
+
+// ------------------------------------------------------------------------------------------
+// SString is the "standard" string representation for the EE.  Its has two purposes.
+// (1) it provides an easy-to-use, relatively efficient, string class for APIs to standardize
+//      on.
+// (2) it completely encapsulates all "unsafe" string operations - that is, string operations
+//      which yield possible buffer overrun bugs.  Typesafe use of this API should help guarantee
+//      safety.
+//
+// A SString is conceptually unicode, although the internal conversion might be delayed as long as possible
+// Basically it's up to the implementation whether conversion takes place immediately or is delayed, and if
+// delayed, what operations trigger the conversion.
+//
+// Note that anywhere you express a "position" in a string, it is in terms of the Unicode representation of the
+// string.
+//
+// If you need a direct non-unicode representation, you will have to provide a fresh SString which can
+// receive a conversion operation if necessary.
+//
+// The alternate encodings available are:
+// 1. ASCII - string consisting entirely of ASCII (7 bit) characters.  This is the only 1 byte encoding
+//    guaranteed to be fixed width. Such a string is also a valid instance of all the other 1 byte string
+//    representations, and we take advantage of this fact.
+// 2. UTF-8 - standard multibyte unicode encoding.
+// 3. ANSI - Potentially multibyte encoding using the ANSI page determined by GetACP().
+//
+// @todo: Note that we could also provide support for several other cases (but currently do not.)
+//  - Page specified by GetOEMCP() (OEM page)
+//  - Arbitrary page support
+//
+// @todo: argument & overflow/underflow checking needs to be added
+// ------------------------------------------------------------------------------------------
+
+
+#ifndef _SSTRING_H_
+#define _SSTRING_H_
+
+#include "utilcode.h"
+#include "sbuffer.h"
+#include "debugmacros.h"
+
+// ==========================================================================================
+// Documentational typedefs: use these to indicate specific representations of 8 bit strings:
+// ==========================================================================================
+
+// Note that LPCSTR means ASCII (7-bit) only!
+
+typedef CHAR ASCII;
+typedef ASCII *LPASCII;
+typedef const ASCII *LPCASCII;
+
+typedef CHAR ANSI;
+typedef ANSI *LPANSI;
+typedef const ANSI *LPCANSI;
+
+typedef CHAR UTF8;
+typedef UTF8 *LPUTF8;
+typedef const UTF8 *LPCUTF8;
+
+// ==========================================================================================
+// SString is the base class for safe strings.
+// ==========================================================================================
+
+
+typedef DPTR(class SString) PTR_SString;
+class EMPTY_BASES_DECL SString : private SBuffer
+{
+    friend struct _DacGlobals;
+
+private:
+    enum Representation
+    {
+        // Note: bits are meaningful:      xVS  V == Variable?  S == Single byte width?
+        REPRESENTATION_EMPTY    = 0x00, // 000
+        REPRESENTATION_UNICODE  = 0x04, // 100
+        REPRESENTATION_ASCII    = 0x01, // 001
+        REPRESENTATION_UTF8     = 0x03, // 011
+        REPRESENTATION_ANSI     = 0x07, // 111
+
+        REPRESENTATION_VARIABLE_MASK    = 0x02,
+        REPRESENTATION_SINGLE_MASK      = 0x01,
+        REPRESENTATION_MASK             = 0x07,
+    };
+
+    // Minimum guess for Printf buffer size
+    const static COUNT_T MINIMUM_GUESS = 20;
+
+
+#ifdef _DEBUG
+    // Used to have a public ctor of this form - made it too easy to lose
+    // utf8 info by accident. Now you have to specify the representation type
+    // explicitly - this privator ctor prevents reinsertion of this ctor.
+    explicit SString(const ASCII *)
+    {
+        _ASSERTE(!"Don't call this.");
+    }
+#endif
+
+  protected:
+    class Index;
+    class UIndex;
+
+    friend class Index;
+    friend class UIndex;
+
+  public:
+
+    // UIterator is character-level assignable.
+    class UIterator;
+
+    // CIterators/Iterator'string must be modified by SString APIs.
+    class CIterator;
+    class Iterator;
+
+    // Tokens for constructor overloads
+    enum tagUTF8Literal { Utf8Literal };
+    enum tagLiteral { Literal };
+    enum tagUTF8 { Utf8 };
+    enum tagANSI { Ansi };
+    enum tagASCII {Ascii };
+
+    static void Startup();
+    static CHECK CheckStartup();
+
+    static const SString &Empty();
+
+    SString();
+
+    explicit SString(const SString &s);
+
+    SString(const SString &s1, const SString &s2);
+    SString(const SString &s1, const SString &s2, const SString &s3);
+    SString(const SString &s1, const SString &s2, const SString &s3, const SString &s4);
+    SString(const SString &s, const CIterator &i, COUNT_T length);
+    SString(const SString &s, const CIterator &start, const CIterator &end);
+    SString(const WCHAR *string);
+    SString(const WCHAR *string, COUNT_T count);
+    SString(enum tagASCII dummyTag, const ASCII *string);
+    SString(enum tagASCII dummyTag, const ASCII *string, COUNT_T count);
+    SString(enum tagUTF8 dummytag, const UTF8 *string);
+    SString(enum tagUTF8 dummytag, const UTF8 *string, COUNT_T count);
+    SString(enum tagANSI dummytag, const ANSI *string);
+    SString(enum tagANSI dummytag, const ANSI *string, COUNT_T count);
+    SString(WCHAR character);
+
+    // NOTE: Literals MUST be read-only never-freed strings.
+    SString(enum tagLiteral dummytag, const CHAR *literal);
+    SString(enum tagUTF8Literal dummytag, const UTF8 *literal);
+    SString(enum tagLiteral dummytag, const WCHAR *literal);
+    SString(enum tagLiteral dummytag, const WCHAR *literal, COUNT_T count);
+
+    // Set this string to the concatenation of s1,s2,s3,s4
+    void Set(const SString &s);
+    void Set(const SString &s1, const SString &s2);
+    void Set(const SString &s1, const SString &s2, const SString &s3);
+    void Set(const SString &s1, const SString &s2, const SString &s3, const SString &s4);
+
+    // Set this string to the substring of s, starting at i, of length characters.
+    void Set(const SString &s, const CIterator &i, COUNT_T length);
+
+    // Set this string to the substring of s, starting at start and ending at end (exclusive)
+    void Set(const SString &s, const CIterator &start, const CIterator &end);
+
+    // Set this string to a copy of the given string
+    void Set(const WCHAR *string);
+    void SetASCII(const ASCII *string);
+    void SetUTF8(const UTF8 *string);
+    void SetANSI(const ANSI *string);
+
+    // Set this string to a copy of the first count chars of the given string
+    void Set(const WCHAR *string, COUNT_T count);
+
+    // Set this string to a prellocated copy of a given string.
+    // The caller is the owner of the bufffer and has to coordinate its lifetime.
+    void SetPreallocated(const WCHAR *string, COUNT_T count);
+
+    void SetASCII(const ASCII *string, COUNT_T count);
+
+    void SetUTF8(const UTF8 *string, COUNT_T count);
+    void SetANSI(const ANSI *string, COUNT_T count);
+
+    // Set this string to the unicode character
+    void Set(WCHAR character);
+
+    // Set this string to the UTF8 character
+    void SetUTF8(CHAR character);
+
+    // This this string to the given literal. We share the mem and don't make a copy.
+    void SetLiteral(const CHAR *literal);
+    void SetLiteral(const WCHAR *literal);
+
+    // ------------------------------------------------------------------
+    // Public operations
+    // ------------------------------------------------------------------
+
+    // Normalizes the string representation to unicode.  This can be used to
+    // make basic read-only operations non-failing.
+    void Normalize() const;
+
+    // Return the number of characters in the string (excluding the terminating NULL).
+    COUNT_T GetCount() const;
+    BOOL IsEmpty() const;
+
+    // Return whether a single byte string has all characters which fit in the ASCII set.
+    // (Note that this will return FALSE if the string has been converted to unicode for any
+    // reason.)
+    BOOL IsASCII() const;
+
+    // !!!!!!!!!!!!!! WARNING about case insensitive operations !!!!!!!!!!!!!!!
+    //
+    //                 THIS IS NOT SUPPORTED FULLY ON WIN9x
+    //      SString case-insensitive comparison is based off LCMapString,
+    //      which does not work on characters outside the current OS code page.
+    //
+    //      Case insensitive code in SString is primarily targeted at
+    //      supporting path comparisons, which is supported correctly on 9x,
+    //      since file system names are limited to the OS code page.
+    //
+    // !!!!!!!!!!!!!! WARNING about case insensitive operations !!!!!!!!!!!!!!!
+
+    // Compute a content-based hash value
+    ULONG Hash() const;
+    ULONG HashCaseInsensitive() const;
+
+    // Do a string comparison. Return 0 if the strings
+    // have the same value,  -1 if this is "less than" s, or 1 if
+    // this is "greater than" s.
+    int Compare(const SString &s) const;
+    int CompareCaseInsensitive(const SString &s) const; // invariant locale
+
+    // Do a case sensitive string comparison. Return TRUE if the strings
+    // have the same value FALSE if not.
+    BOOL Equals(const SString &s) const;
+    BOOL EqualsCaseInsensitive(const SString &s) const; // invariant locale
+
+    // Match s to a portion of the string starting at the position.
+    // Return TRUE if the strings have the same value
+    // (regardless of representation), FALSE if not.
+    BOOL Match(const CIterator &i, const SString &s) const;
+    BOOL MatchCaseInsensitive(const CIterator &i, const SString &s) const; // invariant locale
+
+    BOOL Match(const CIterator &i, WCHAR c) const;
+    BOOL MatchCaseInsensitive(const CIterator &i, WCHAR c) const; // invariant locale
+
+    // Like match, but advances the iterator past the match
+    // if successful
+    BOOL Skip(CIterator &i, const SString &s) const;
+    BOOL Skip(CIterator &i, WCHAR c) const;
+
+    // Start searching for a match of the given string, starting at
+    // the given iterator point.
+    // If a match exists, move the iterator to point to the nearest
+    // occurrence of s in the string and return TRUE.
+    // If no match exists, return FALSE and leave the iterator unchanged.
+    BOOL Find(CIterator &i, const SString &s) const;
+    BOOL Find(CIterator &i, const WCHAR *s) const;
+    BOOL FindASCII(CIterator &i, const ASCII *s) const;
+    BOOL FindUTF8(CIterator &i, const UTF8 *s) const;
+    BOOL Find(CIterator &i, WCHAR c) const;
+
+    BOOL FindBack(CIterator &i, const SString &s) const;
+    BOOL FindBack(CIterator &i, const WCHAR *s) const;
+    BOOL FindBackASCII(CIterator &i, const ASCII *s) const;
+    BOOL FindBackUTF8(CIterator &i, const UTF8 *s) const;
+    BOOL FindBack(CIterator &i, WCHAR c) const;
+
+    // Returns TRUE if this string begins with the contents of s
+    BOOL BeginsWith(const SString &s) const;
+    BOOL BeginsWithCaseInsensitive(const SString &s) const; // invariant locale
+
+    // Returns TRUE if this string ends with the contents of s
+    BOOL EndsWith(const SString &s) const;
+    BOOL EndsWithCaseInsensitive(const SString &s) const; // invariant locale
+
+    // Sets this string to an empty string "".
+    void Clear();
+
+    // Truncate the string to the iterator position
+    void Truncate(const Iterator &i);
+
+    // Append s to the end of this string.
+    void Append(const SString &s);
+    void Append(const WCHAR *s);
+    void AppendASCII(const CHAR *s);
+    void AppendUTF8(const CHAR *s);
+
+    // Append char c to the end of this string.
+    void Append(const WCHAR c);
+    void AppendUTF8(const CHAR c);
+
+    // Insert s into this string at the 'position'th character.
+    void Insert(const Iterator &i, const SString &s);
+    void Insert(const Iterator &i, const WCHAR *s);
+    void InsertASCII(const Iterator &i, const CHAR *s);
+    void InsertUTF8(const Iterator &i, const CHAR *s);
+
+    // Delete substring position + length
+    void Delete(const Iterator &i, COUNT_T length);
+
+    // Replace character at i with c
+    void Replace(const Iterator &i, WCHAR c);
+
+    // Replace substring at (i,i+length) with s
+    void Replace(const Iterator &i, COUNT_T length, const SString &s);
+
+    // Make sure that string buffer has room to grow
+    void Preallocate(COUNT_T characters) const;
+
+    // Shrink buffer size as much as possible (reallocate if necessary.)
+    void Trim() const;
+
+    // ------------------------------------------------------------------
+    // Iterators:
+    // ------------------------------------------------------------------
+
+    // SString splits iterators into two categories.
+    //
+    // CIterator and Iterator are cheap to create, but allow only read-only
+    // access to the string.
+    //
+    // UIterator forces a unicode conversion, but allows
+    // assignment to individual string characters.  They are also a bit more
+    // efficient once created.
+
+    // ------------------------------------------------------------------
+    // UIterator:
+    // ------------------------------------------------------------------
+
+ protected:
+
+    class EMPTY_BASES_DECL UIndex : public SBuffer::Index
+    {
+        friend class SString;
+        friend class Indexer<WCHAR, UIterator>;
+
+      protected:
+
+        UIndex();
+        UIndex(SString *string, SCOUNT_T index);
+        WCHAR &GetAt(SCOUNT_T delta) const;
+        void Skip(SCOUNT_T delta);
+        SCOUNT_T Subtract(const UIndex &i) const;
+        CHECK DoCheck(SCOUNT_T delta) const;
+
+        WCHAR *GetUnicode() const;
+    };
+
+ public:
+
+    class EMPTY_BASES_DECL UIterator : public UIndex, public Indexer<WCHAR, UIterator>
+    {
+        friend class SString;
+
+    public:
+        UIterator()
+        {
+        }
+
+        UIterator(SString *string, int index)
+          : UIndex(string, index)
+        {
+        }
+    };
+
+    UIterator BeginUnicode();
+    UIterator EndUnicode();
+
+    // For CIterator & Iterator, we try our best to iterate the string without
+    // modifying it. (Currently, we do require an ASCII or Unicode string
+    // for simple WCHAR retrival, but you could imagine being more flexible
+    // going forward - perhaps even supporting iterating multibyte encodings
+    // directly.)
+    //
+    // Because of the runtime-changable nature of the string, CIterators
+    // require an extra member to record the character size. They also
+    // are unable to properly implement GetAt as required by the template
+    // (since there may not be a direct WCHAR pointer), so they provide
+    // further customization in a subclass.
+    //
+    // Normally the user expects to cast Iterators to CIterators transparently, so
+    // we provide a constructor on CIterator to support this.
+
+ protected:
+
+    class EMPTY_BASES_DECL Index : public SBuffer::Index
+    {
+        friend class SString;
+
+        friend class Indexer<const WCHAR, CIterator>;
+        friend class Indexer<WCHAR, Iterator>;
+
+      protected:
+        int               m_characterSizeShift;
+
+        Index();
+        Index(SString *string, SCOUNT_T index);
+        BYTE &GetAt(SCOUNT_T delta) const;
+        void Skip(SCOUNT_T delta);
+        SCOUNT_T Subtract(const Index &i) const;
+        CHECK DoCheck(SCOUNT_T delta) const;
+
+        void Resync(const SString *string, BYTE *ptr) const;
+
+        const WCHAR *GetUnicode() const;
+        const CHAR *GetASCII() const;
+
+      public:
+        // Note these should supercede the Indexer versions
+        // since this class comes first in the inheritence list
+        WCHAR operator*() const;
+        void operator->() const;
+        WCHAR operator[](int index) const;
+    };
+
+ public:
+
+    class EMPTY_BASES_DECL CIterator : public Index, public Indexer<const WCHAR, CIterator>
+    {
+        friend class SString;
+
+      public:
+        const Iterator &ConstCast() const
+        {
+            return *(const Iterator *)this;
+        }
+
+        Iterator &ConstCast()
+        {
+            return *(Iterator *)this;
+        }
+
+        operator const SBuffer::CIterator &() const
+        {
+            return *(const SBuffer::CIterator *)this;
+        }
+
+        operator SBuffer::CIterator &()
+        {
+            return *(SBuffer::CIterator *)this;
+        }
+
+        CIterator()
+        {
+        }
+
+        CIterator(const SString *string, int index)
+          : Index(const_cast<SString *>(string), index)
+        {
+        }
+
+        // explicitly resolve these for gcc
+        WCHAR operator*() const { return Index::operator*(); }
+        void operator->() const { Index::operator->(); }
+        WCHAR operator[](int index) const { return Index::operator[](index); }
+    };
+
+    class EMPTY_BASES_DECL Iterator : public Index, public Indexer<WCHAR, Iterator>
+    {
+        friend class SString;
+
+      public:
+        operator const CIterator &() const
+        {
+            return *(const CIterator *)this;
+        }
+
+        operator CIterator &()
+        {
+            return *(CIterator *)this;
+        }
+
+        operator const SBuffer::Iterator &() const
+        {
+            return *(const SBuffer::Iterator *)this;
+        }
+
+        operator SBuffer::Iterator &()
+        {
+            return *(SBuffer::Iterator *)this;
+        }
+
+        Iterator()
+        {
+        }
+
+        Iterator(SString *string, int index)
+          : Index(string, index)
+        {
+            SUPPORTS_DAC;
+        }
+
+        // explicitly resolve these for gcc
+        WCHAR operator*() const { return Index::operator*(); }
+        void operator->() const { Index::operator->(); }
+        WCHAR operator[](int index) const { return Index::operator[](index); }
+    };
+
+    CIterator Begin() const;
+    CIterator End() const;
+
+    Iterator Begin();
+    Iterator End();
+
+    // ------------------------------------------------------------------
+    // Conversion:
+    // ------------------------------------------------------------------
+
+    // Get a const pointer to the string in the current representation.
+    // This pointer can not be cached because it will become invalid if
+    // the SString changes representation or reallocates its buffer.
+
+    // You can always get a unicode string.  This will force a conversion
+    // if necessary.
+    const WCHAR *GetUnicode() const;
+    const WCHAR *GetUnicode(const CIterator &i) const;
+
+    void LowerCase();
+    void UpperCase();
+
+    // Helper function to convert string in-place to lower-case (no allocation overhead for SString instance)
+    static void LowerCase(__inout_z LPWSTR wszString);
+
+    // These routines will use the given scratch string if necessary
+    // to perform a conversion to the desired representation
+
+    // Use a local declaration of InlineScratchBuffer or StackScratchBuffer for parameters of
+    // AbstractScratchBuffer.
+    class AbstractScratchBuffer;
+
+    // These routines will use the given scratch buffer if necessary
+    // to perform a conversion to the desired representation.  Note that
+    // the lifetime of the pointer return is limited by BOTH the
+    // scratch string and the source (this) string.
+    //
+    // Typical usage:
+    //
+    // SString *s = ...;
+    // {
+    //   StackScratchBuffer buffer;
+    //   const UTF8 *utf8 = s->GetUTF8(buffer);
+    //   CallFoo(utf8);
+    // }
+    // // No more pointers to returned buffer allowed.
+
+    const UTF8 *GetUTF8(AbstractScratchBuffer &scratch) const;
+    const UTF8 *GetUTF8(AbstractScratchBuffer &scratch, COUNT_T *pcbUtf8) const;
+    const ANSI *GetANSI(AbstractScratchBuffer &scratch) const;
+
+    // Used when the representation is known, throws if the representation doesn't match
+    const UTF8 *GetUTF8NoConvert() const;
+
+    // Converts/copies into the given output string
+    void ConvertToUnicode(SString &dest) const;
+    void ConvertToANSI(SString &dest) const;
+    COUNT_T ConvertToUTF8(SString &dest) const;
+
+    //-------------------------------------------------------------------
+    // Accessing the string contents directly
+    //-------------------------------------------------------------------
+
+    // To write directly to the SString's underlying buffer:
+    // 1) Call OpenXXXBuffer() and pass it the count of characters
+    // you need. (Not including the null-terminator).
+    // 2) That returns a pointer to the raw buffer which you can write to.
+    // 3) When you are done writing to the pointer, call CloseBuffer()
+    // and pass it the count of characters you actually wrote (not including
+    // the null). The pointer from step 1 is now invalid.
+
+    // example usage:
+    // void GetName(SString & str) {
+    //      char * p = str.OpenANSIBuffer(3);
+    //      strcpy(p, "Cat");
+    //      str.CloseBuffer();
+    // }
+
+    // Regarding the null-terminator:
+    // 1) Note that we wrote 4 characters (3 + a null). That's ok. OpenBuffer
+    // allocates 1 extra byte for the null.
+    // 2) If we only wrote 3 characters and no null, that's ok too. CloseBuffer()
+    // will add a null-terminator.
+
+    // You should open the buffer, write the data, and immediately close it.
+    // No sstring operations are valid while the buffer is opened.
+    //
+    // In a debug build, Open/Close will do lots of little checks to make sure
+    // you don't buffer overflow while it's opened. In a retail build, this
+    // is a very streamlined action.
+
+
+    // Open the raw buffer for writing countChars characters (not including the null).
+    WCHAR *OpenUnicodeBuffer(COUNT_T maxCharCount);
+    UTF8 *OpenUTF8Buffer(COUNT_T maxSingleCharCount);
+    ANSI *OpenANSIBuffer(COUNT_T maxSingleCharCount);
+
+    //Returns the unicode string, the caller is reponsible for lifetime of the string
+    WCHAR *GetCopyOfUnicodeString();
+
+    // Get the max size that can be passed to OpenUnicodeBuffer without causing allocations.
+    COUNT_T GetUnicodeAllocation();
+
+    // Call after OpenXXXBuffer().
+
+    // Provide the count of characters actually used (not including the
+    // null terminator). This will make sure the SString's size is correct
+    // and that we have a null-terminator.
+    void CloseBuffer(COUNT_T finalCount);
+
+    // Close the buffer. Assumes that we completely filled the buffer
+    // that OpenBuffer() gave back. If we didn't write all the characters,
+    // call CloseBuffer(int) instead.
+    void CloseBuffer();
+
+#ifdef DACCESS_COMPILE
+    // DAC access to string functions.
+    // Note that other accessors above are not DAC-safe and will return TARGET pointers into
+    // the string instead of copying the string over to the host.
+    // @dbgtodo  dac support: Prevent usage of such DAC-unsafe SString APIs in DAC code
+
+    // Instantiate a copy of the raw buffer in the host and return a pointer to it
+    void * DacGetRawContent() const;
+
+    // Instantiate a copy of the raw buffer in the host.  Requires that the underlying
+    // representation is already unicode.
+    const WCHAR * DacGetRawUnicode() const;
+
+    // Copy the string from the target into the provided buffer, converting to unicode if necessary
+    bool DacGetUnicode(COUNT_T                                  bufChars,
+                       _Inout_updates_z_(bufChars) WCHAR * buffer,
+                       COUNT_T *                                needChars) const;
+
+    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) const
+    {
+        SUPPORTS_DAC;
+        SBuffer::EnumMemoryRegions(flags);
+    }
+#endif
+
+    //---------------------------------------------------------------------
+    // Utilities
+    //---------------------------------------------------------------------
+
+    // WARNING: The MBCS version of printf function are factory for globalization
+    // issues when used to format Unicode strings (%S). The Unicode versions are
+    // preferred in this case.
+    void Printf(const CHAR *format, ...);
+    void VPrintf(const CHAR *format, va_list args);
+
+    void Printf(const WCHAR *format, ...);
+    void PPrintf(const WCHAR *format, ...);
+    void VPrintf(const WCHAR *format, va_list args);
+
+    void PVPrintf(const WCHAR *format, va_list args);
+
+    void AppendPrintf(const CHAR *format, ...);
+    void AppendVPrintf(const CHAR *format, va_list args);
+
+    void AppendPrintf(const WCHAR *format, ...);
+    void AppendVPrintf(const WCHAR *format, va_list args);
+
+    BOOL LoadResource(CCompRC::ResourceCategory eCategory, int resourceID);
+    HRESULT LoadResourceAndReturnHR(CCompRC::ResourceCategory eCategory, int resourceID);
+    HRESULT LoadResourceAndReturnHR(CCompRC* pResourceDLL, CCompRC::ResourceCategory eCategory, int resourceID);
+    BOOL FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId,
+                       const SString &arg1 = Empty(), const SString &arg2 = Empty(),
+                       const SString &arg3 = Empty(), const SString &arg4 = Empty(),
+                       const SString &arg5 = Empty(), const SString &arg6 = Empty(),
+                       const SString &arg7 = Empty(), const SString &arg8 = Empty(),
+                       const SString &arg9 = Empty(), const SString &arg10 = Empty());
+
+#if 1
+    // @todo - get rid of this and move it outside of SString
+    void MakeFullNamespacePath(const SString &nameSpace, const SString &name);
+#endif
+
+    //--------------------------------------------------------------------
+    // Operators
+    //--------------------------------------------------------------------
+
+    operator const WCHAR * () const { WRAPPER_NO_CONTRACT; return GetUnicode(); }
+
+    WCHAR operator[](int index) { WRAPPER_NO_CONTRACT; return Begin()[index]; }
+    WCHAR operator[](int index) const { WRAPPER_NO_CONTRACT; return Begin()[index]; }
+
+    SString &operator= (const SString &s) { WRAPPER_NO_CONTRACT; Set(s); return *this; }
+    SString &operator+= (const SString &s) { WRAPPER_NO_CONTRACT; Append(s); return *this; }
+
+    // -------------------------------------------------------------------
+    // Check functions
+    // -------------------------------------------------------------------
+
+    CHECK CheckIteratorRange(const CIterator &i) const;
+    CHECK CheckIteratorRange(const CIterator &i, COUNT_T length) const;
+    CHECK CheckEmpty() const;
+
+    static CHECK CheckCount(COUNT_T count);
+    static CHECK CheckRepresentation(int representation);
+
+#if CHECK_INVARIANTS
+    static CHECK CheckASCIIString(const ASCII *string);
+    static CHECK CheckASCIIString(const ASCII *string, COUNT_T count);
+
+    CHECK Check() const;
+    CHECK Invariant() const;
+    CHECK InternalInvariant() const;
+#endif  // CHECK_INVARIANTS
+
+    // Helpers for CRT function equivalance.
+    static int __cdecl _stricmp(const CHAR *buffer1, const CHAR *buffer2);
+    static int __cdecl _strnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count);
+
+    static int __cdecl _wcsicmp(const WCHAR *buffer1, const WCHAR *buffer2);
+    static int __cdecl _wcsnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count);
+
+    // C++ convenience overloads
+    static int _tstricmp(const CHAR *buffer1, const CHAR *buffer2);
+    static int _tstricmp(const WCHAR *buffer1, const WCHAR *buffer2);
+
+    static int _tstrnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count);
+    static int _tstrnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count);
+
+    // -------------------------------------------------------------------
+    // Internal routines
+    // -------------------------------------------------------------------
+
+
+ protected:
+    // Use this via InlineSString<X>
+    SString(void *buffer, COUNT_T size);
+
+ private:
+    static int CaseCompareHelperA(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count, BOOL stopOnNull, BOOL stopOnCount);
+    static int CaseCompareHelper(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count, BOOL stopOnNull, BOOL stopOnCount);
+
+    // Internal helpers:
+
+    static const BYTE s_EmptyBuffer[2];
+
+    static UINT s_ACP;
+
+    SPTR_DECL(SString,s_Empty);
+
+    COUNT_T GetRawCount() const;
+
+    // Get buffer as appropriate string rep
+    ASCII *GetRawASCII() const;
+    UTF8 *GetRawUTF8() const;
+    ANSI *GetRawANSI() const;
+    WCHAR *GetRawUnicode() const;
+
+    void InitEmpty();
+
+    Representation GetRepresentation() const;
+    void SetRepresentation(Representation representation);
+    BOOL IsRepresentation(Representation representation) const;
+    BOOL IsFixedSize() const;
+    BOOL IsIteratable() const;
+    BOOL IsSingleByte() const;
+
+    int GetCharacterSizeShift() const;
+
+    COUNT_T SizeToCount(COUNT_T size) const;
+    COUNT_T CountToSize(COUNT_T count) const;
+
+    COUNT_T GetBufferSizeInCharIncludeNullChar() const;
+
+    BOOL IsLiteral() const;
+    BOOL IsAllocated() const;
+    BOOL IsBufferOpen() const;
+    BOOL IsASCIIScanned() const;
+    void SetASCIIScanned() const;
+    void SetNormalized() const;
+    BOOL IsNormalized() const;
+    void ClearNormalized() const;
+
+    void EnsureWritable() const;
+    void ConvertToFixed() const;
+    void ConvertToIteratable() const;
+
+    void ConvertASCIIToUnicode(SString &dest) const;
+    void ConvertToUnicode() const;
+    void ConvertToUnicode(const CIterator &i) const;
+
+    const SString &GetCompatibleString(const SString &s, SString &scratch) const;
+    const SString &GetCompatibleString(const SString &s, SString &scratch, const CIterator &i) const;
+    BOOL ScanASCII() const;
+    void NullTerminate();
+
+    void Resize(COUNT_T count, Representation representation,
+                Preserve preserve = DONT_PRESERVE);
+
+    void OpenBuffer(Representation representation, COUNT_T countChars);
+};
+
+// ===========================================================================
+// InlineSString is used for stack allocation of strings, or when the string contents
+// are expected or known to be small.  Note that it still supports expandability via
+// heap allocation if necessary.
+// ===========================================================================
+
+template <COUNT_T MEMSIZE>
+class EMPTY_BASES_DECL InlineSString : public SString
+{
+private:
+    DAC_ALIGNAS(SString)
+    BYTE m_inline[SBUFFER_PADDED_SIZE(MEMSIZE)];
+
+public:
+    FORCEINLINE InlineSString()
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+    }
+
+    FORCEINLINE InlineSString(const SString &s)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(s);
+    }
+
+    FORCEINLINE InlineSString(const SString &s1, const SString &s2)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(s1, s2);
+    }
+
+    FORCEINLINE InlineSString(const SString &s1, const SString &s2, const SString &s3)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(s1, s2, s3);
+    }
+
+    FORCEINLINE InlineSString(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(s1, s2, s3, s4);
+    }
+
+    FORCEINLINE InlineSString(const SString &s, const CIterator &start, const CIterator &end)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(s, start, end);
+    }
+
+    FORCEINLINE InlineSString(const SString &s, const CIterator &i, COUNT_T length)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(s, i, length);
+    }
+
+    FORCEINLINE InlineSString(const WCHAR *string)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(string);
+    }
+
+    FORCEINLINE InlineSString(const WCHAR *string, COUNT_T count)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(string, count);
+    }
+
+    FORCEINLINE InlineSString(enum tagASCII, const CHAR *string)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        SetASCII(string);
+    }
+
+    FORCEINLINE InlineSString(enum tagASCII, const CHAR *string, COUNT_T count)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        SetASCII(string, count);
+    }
+
+    FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 *string)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        SetUTF8(string);
+    }
+
+    FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 *string, COUNT_T count)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        SetUTF8(string, count);
+    }
+
+    FORCEINLINE InlineSString(enum tagANSI dummytag, const ANSI *string)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        SetANSI(string);
+    }
+
+    FORCEINLINE InlineSString(enum tagANSI dummytag, const ANSI *string, COUNT_T count)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        SetANSI(string, count);
+    }
+
+    FORCEINLINE InlineSString(WCHAR character)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(character);
+    }
+
+    FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 character)
+      : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
+    {
+        WRAPPER_NO_CONTRACT;
+        SetUTF8(character);
+    }
+
+    FORCEINLINE InlineSString<MEMSIZE> &operator= (const SString &s)
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(s);
+        return *this;
+    }
+
+    FORCEINLINE InlineSString<MEMSIZE> &operator= (const InlineSString<MEMSIZE> &s)
+    {
+        WRAPPER_NO_CONTRACT;
+        Set(s);
+        return *this;
+    }
+};
+
+// ================================================================================
+// StackSString is a lot like CQuickBytes.  Use it to create an SString object
+// using some stack space as a preallocated buffer.
+// ================================================================================
+
+typedef InlineSString<512> StackSString;
+
+// This is a smaller version for when it is known that the string that's going to
+// be needed is small and it's preferable not to take up the stack space.
+typedef InlineSString<32>  SmallStackSString;
+
+// To be used specifically for path strings.
+#ifdef _DEBUG
+// This is a smaller version for debug builds to exercise the buffer allocation path
+typedef InlineSString<32> PathString;
+typedef InlineSString<2 * 32> LongPathString;
+#else
+// Set it to the current MAX_PATH
+typedef InlineSString<260> PathString;
+typedef InlineSString<2 * 260> LongPathString;
+#endif
+
+// ================================================================================
+// Quick macro to create an SString around a literal string.
+// usage:
+//        s = SL("My literal String");
+// ================================================================================
+
+#define SL(_literal) SString(SString::Literal, _literal)
+
+// ================================================================================
+// ScratchBuffer classes are used by the GetXXX() routines to allocate scratch space in.
+// ================================================================================
+
+class EMPTY_BASES_DECL SString::AbstractScratchBuffer : private SString
+{
+  protected:
+    // Do not use this class directly - use
+    // ScratchBuffer or StackScratchBuffer.
+    AbstractScratchBuffer(void *buffer, COUNT_T size);
+};
+
+template <COUNT_T MEMSIZE>
+class EMPTY_BASES_DECL ScratchBuffer : public SString::AbstractScratchBuffer
+{
+  private:
+    DAC_ALIGNAS(::SString::AbstractScratchBuffer)
+    BYTE m_inline[MEMSIZE];
+
+  public:
+    ScratchBuffer()
+    : AbstractScratchBuffer((void *)m_inline, MEMSIZE)
+    {
+        WRAPPER_NO_CONTRACT;
+    }
+};
+
+typedef ScratchBuffer<256> StackScratchBuffer;
+
+// ================================================================================
+// Special contract definition - THROWS_UNLESS_NORMALIZED
+// this is used for operations which might fail for generalized strings but
+// not if the string has already been converted to unicode.  Rather than just
+// setting this on all conversions to unicode, we only set it when explicitly
+// asked.  This should expose more potential problems.
+// ================================================================================
+
+#define THROWS_UNLESS_NORMALIZED \
+    if (IsNormalized()) NOTHROW; else THROWS
+
+#define THROWS_UNLESS_BOTH_NORMALIZED(s) \
+    if (IsNormalized() && s.IsNormalized()) NOTHROW; else THROWS
+
+#define FAULTS_UNLESS_NORMALIZED(stmt) \
+    if (IsNormalized()) FORBID_FAULT; else INJECT_FAULT(stmt)
+
+#define FAULTS_UNLESS_BOTH_NORMALIZED(s, stmt) \
+    if (IsNormalized() && s.IsNormalized()) FORBID_FAULT; else INJECT_FAULT(stmt)
+
+// ================================================================================
+// Inline definitions
+// ================================================================================
+
+#include <sstring.inl>
+
+#endif  // _SSTRING_H_
diff --git a/src/inc/sstring.inl b/src/inc/sstring.inl
new file mode 100644 (file)
index 0000000..03fc26f
--- /dev/null
@@ -0,0 +1,2228 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+
+#ifndef _SSTRING_INL_
+#define _SSTRING_INL_
+
+#include "sstring.h"
+
+#if defined(_MSC_VER)
+#pragma inline_depth (20)
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4702) // Disable bogus unreachable code warning
+#endif // _MSC_VER
+
+//#define SSTRING_EXTRA_CHECKS
+#ifdef SSTRING_EXTRA_CHECKS
+#define SS_CONTRACT CONTRACT
+#define SS_CONTRACT_VOID CONTRACT_VOID
+#define SS_CONTRACT_END CONTRACT_END
+#define SS_RETURN RETURN
+#define SS_CONSTRUCTOR_CHECK CONSTRUCTOR_CHECK
+#define SS_PRECONDITION PRECONDITION
+#define SS_POSTCONDITION POSTCONDITION
+
+#else //SSTRING_EXTRA_CHECKS
+
+#define SS_CONTRACT(x) CONTRACTL
+#define SS_CONTRACT_VOID CONTRACTL
+#define SS_CONTRACT_END CONTRACTL_END
+#define SS_RETURN return
+#define SS_CONSTRUCTOR_CHECK
+#define SS_PRECONDITION(x)
+#define SS_POSTCONDITION(x)
+//Do I need this instance check at all?
+
+#endif
+
+
+// ---------------------------------------------------------------------------
+// Inline implementations. Pay no attention to that man behind the curtain.
+// ---------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// Default constructor. Sets the string to the empty string.
+//----------------------------------------------------------------------------
+inline SString::SString()
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+#ifdef SSTRING_EXTRA_CHECKS
+    CONTRACT_VOID
+    {
+        CONSTRUCTOR_CHECK;
+        POSTCONDITION(IsEmpty());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    RETURN;
+#else
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+#endif
+}
+
+inline SString::SString(void *buffer, COUNT_T size)
+  : SBuffer(Prealloc, buffer, size)
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(buffer));
+        PRECONDITION(CheckSize(size));
+        SS_POSTCONDITION(IsEmpty());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    if (size < sizeof(WCHAR))
+    {
+        // Ignore the useless buffer
+        SetImmutable(s_EmptyBuffer, sizeof(s_EmptyBuffer));
+    }
+    else
+    {
+        SBuffer::TweakSize(sizeof(WCHAR));
+        GetRawUnicode()[0] = 0;
+    }
+
+    SS_RETURN;
+}
+
+inline SString::SString(const SString &s)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(s.Check());
+        SS_POSTCONDITION(Equals(s));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(s);
+
+    SS_RETURN;
+}
+
+inline SString::SString(const SString &s1, const SString &s2)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(s1.Check());
+        PRECONDITION(s2.Check());
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(s1, s2);
+
+    SS_RETURN;
+}
+
+inline SString::SString(const SString &s1, const SString &s2, const SString &s3)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(s1.Check());
+        PRECONDITION(s2.Check());
+        PRECONDITION(s3.Check());
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(s1, s2, s3);
+
+    SS_RETURN;
+}
+
+inline SString::SString(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(s1.Check());
+        PRECONDITION(s2.Check());
+        PRECONDITION(s3.Check());
+        PRECONDITION(s4.Check());
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    Set(s1, s2, s3, s4);
+
+    SS_RETURN;
+}
+
+inline SString::SString(const SString &s, const CIterator &i, COUNT_T count)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(s.Check());
+        PRECONDITION(i.Check());
+        PRECONDITION(CheckCount(count));
+        SS_POSTCONDITION(s.Match(i, *this));
+        SS_POSTCONDITION(GetRawCount() == count);
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(s, i, count);
+
+    SS_RETURN;
+}
+
+inline SString::SString(const SString &s, const CIterator &start, const CIterator &end)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(s.Check());
+        PRECONDITION(start.Check());
+        PRECONDITION(s.CheckIteratorRange(start));
+        PRECONDITION(end.Check());
+        PRECONDITION(s.CheckIteratorRange(end));
+        PRECONDITION(start <= end);
+        SS_POSTCONDITION(s.Match(start, *this));
+        SS_POSTCONDITION(GetRawCount() == (COUNT_T) (end - start));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(s, start, end);
+
+    SS_RETURN;
+}
+
+inline SString::SString(const WCHAR *string)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(string);
+
+    SS_RETURN;
+}
+
+inline SString::SString(const WCHAR *string, COUNT_T count)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckCount(count));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(string, count);
+
+    SS_RETURN;
+}
+
+inline SString::SString(enum tagASCII, const ASCII *string)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckASCIIString(string));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SetASCII(string);
+
+    SS_RETURN;
+}
+
+inline SString::SString(enum tagASCII, const ASCII *string, COUNT_T count)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckASCIIString(string, count));
+        PRECONDITION(CheckCount(count));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SetASCII(string, count);
+
+    SS_RETURN;
+}
+
+inline SString::SString(tagUTF8 dummytag, const UTF8 *string)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        // !!! Check for illegal UTF8 encoding?
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    SetUTF8(string);
+
+    SS_RETURN;
+}
+
+inline SString::SString(tagUTF8 dummytag, const UTF8 *string, COUNT_T count)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        // !!! Check for illegal UTF8 encoding?
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckCount(count));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SetUTF8(string, count);
+
+    SS_RETURN;
+}
+
+inline SString::SString(tagANSI dummytag, const ANSI *string)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SetANSI(string);
+
+    SS_RETURN;
+}
+
+inline SString::SString(tagANSI dummytag, const ANSI *string, COUNT_T count)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckCount(count));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SetANSI(string, count);
+
+    SS_RETURN;
+}
+
+inline SString::SString(WCHAR character)
+  : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(character);
+
+    SS_RETURN;
+}
+
+inline SString::SString(tagLiteral dummytag, const ASCII *literal)
+  : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (strlen(literal)+1)*sizeof(CHAR))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(literal));
+        PRECONDITION(CheckASCIIString(literal));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    SetRepresentation(REPRESENTATION_ASCII);
+
+    SS_RETURN;
+}
+
+inline SString::SString(tagUTF8Literal dummytag, const UTF8 *literal)
+  : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (strlen(literal)+1)*sizeof(CHAR))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(literal));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SetRepresentation(REPRESENTATION_UTF8);
+
+    SS_RETURN;
+}
+
+inline SString::SString(tagLiteral dummytag, const WCHAR *literal)
+  : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (wcslen(literal)+1)*sizeof(WCHAR))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(literal));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SetRepresentation(REPRESENTATION_UNICODE);
+    SetNormalized();
+
+    SS_RETURN;
+}
+
+inline SString::SString(tagLiteral dummytag, const WCHAR *literal, COUNT_T count)
+  : SBuffer(Immutable, (const BYTE *) literal, (count + 1) * sizeof(WCHAR))
+{
+    SS_CONTRACT_VOID
+    {
+        SS_CONSTRUCTOR_CHECK;
+        PRECONDITION(CheckPointer(literal));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SetRepresentation(REPRESENTATION_UNICODE);
+    SetNormalized();
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to s
+// s - source string
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s.Check());
+        SS_POSTCONDITION(Equals(s));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    SBuffer::Set(s);
+    SetRepresentation(s.GetRepresentation());
+    ClearNormalized();
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to concatenation of s1 and s2
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s1, const SString &s2)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s1.Check());
+        PRECONDITION(s2.Check());
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Preallocate(s1.GetCount() + s2.GetCount());
+
+    Set(s1);
+    Append(s2);
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to concatenation of s1, s2, and s3
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s1, const SString &s2, const SString &s3)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s1.Check());
+        PRECONDITION(s2.Check());
+        PRECONDITION(s3.Check());
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Preallocate(s1.GetCount() + s2.GetCount() + s3.GetCount());
+
+    Set(s1);
+    Append(s2);
+    Append(s3);
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to concatenation of s1, s2, s3, and s4
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s1.Check());
+        PRECONDITION(s2.Check());
+        PRECONDITION(s3.Check());
+        PRECONDITION(s4.Check());
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Preallocate(s1.GetCount() + s2.GetCount() + s3.GetCount() + s4.GetCount());
+
+    Set(s1);
+    Append(s2);
+    Append(s3);
+    Append(s4);
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to the substring from s.
+// s - the source string
+// start - the character to start at
+// length - number of characters to copy from s.
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s, const CIterator &i, COUNT_T count)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s.Check());
+        PRECONDITION(i.Check());
+        PRECONDITION(CheckCount(count));
+        SS_POSTCONDITION(s.Match(i, *this));
+        SS_POSTCONDITION(GetRawCount() == count);
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    // @todo: detect case where we can reuse literal?
+    Resize(count, s.GetRepresentation());
+    SBuffer::Copy(SBuffer::Begin(), i.m_ptr, count<<i.m_characterSizeShift);
+    NullTerminate();
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to the substring from s.
+// s - the source string
+// start - the position to start
+// end - the position to end (exclusive)
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s, const CIterator &start, const CIterator &end)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s.Check());
+        PRECONDITION(start.Check());
+        PRECONDITION(s.CheckIteratorRange(start));
+        PRECONDITION(end.Check());
+        PRECONDITION(s.CheckIteratorRange(end));
+        PRECONDITION(end >= start);
+        SS_POSTCONDITION(s.Match(start, *this));
+        SS_POSTCONDITION(GetRawCount() == (COUNT_T) (end - start));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    Set(s, start, end - start);
+
+    SS_RETURN;
+}
+
+// Return a global empty string
+inline const SString &SString::Empty()
+{
+#ifdef SSTRING_EXTRA_CHECKS
+    CONTRACTL
+    {
+        // POSTCONDITION(RETVAL.IsEmpty());
+        PRECONDITION(CheckStartup());
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+#else
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+#endif
+
+    _ASSERTE(s_Empty != NULL);  // Did you call SString::Startup()?
+    return *s_Empty;
+}
+
+// Get a const pointer to the internal buffer as a unicode string.
+inline const WCHAR *SString::GetUnicode() const
+{
+    SS_CONTRACT(const WCHAR *)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckPointer(RETVAL));
+        if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToUnicode();
+
+    SS_RETURN GetRawUnicode();
+}
+
+// Normalize the string to unicode.  This will make many operations nonfailing.
+inline void SString::Normalize() const
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        SS_POSTCONDITION(IsNormalized());
+        THROWS_UNLESS_NORMALIZED;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToUnicode();
+    SetNormalized();
+
+    SS_RETURN;
+}
+
+// Get a const pointer to the internal buffer as a unicode string.
+inline const WCHAR *SString::GetUnicode(const CIterator &i) const
+{
+    SS_CONTRACT(const WCHAR *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        THROWS_UNLESS_NORMALIZED;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    PRECONDITION(CheckPointer(this));
+
+    ConvertToUnicode(i);
+
+    SS_RETURN i.GetUnicode();
+}
+
+// Append s to the end of this string.
+inline void SString::Append(const SString &s)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(s.Check());
+        THROWS;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    Insert(End(), s);
+
+    SS_RETURN;
+}
+
+inline void SString::Append(const WCHAR *string)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckPointer(string));
+        THROWS;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    // Wrap the string in temporary SString without copying it
+    SString s(SString::Literal, string);
+    s.ClearImmutable();
+    Append(s);
+
+    SS_RETURN;
+}
+
+inline void SString::AppendASCII(const CHAR *string)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckPointer(string));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(SString::Ascii, string);
+    Append(s);
+
+    SS_RETURN;
+}
+
+inline void SString::AppendUTF8(const CHAR *string)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckPointer(string));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(SString::Utf8, string);
+    Append(s);
+
+    SS_RETURN;
+}
+
+inline void SString::Append(const WCHAR c)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    InlineSString<2 * sizeof(c)> s(c);
+    Append(s);
+
+    SS_RETURN;
+}
+
+inline void SString::AppendUTF8(const CHAR c)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        THROWS;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    InlineSString<2 * sizeof(c)> s(SString::Utf8, c);
+    Append(s);
+
+    SS_RETURN;
+}
+
+// Turn this on to test that these if you are testing common scenarios dealing with
+// ASCII strings that do not touch the cases where this family of function differs
+// in behavior for expected reasons.
+//#define VERIFY_CRT_EQUIVALNCE 1
+
+// Helpers for CRT function equivalance.
+/* static */
+inline int __cdecl SString::_stricmp(const CHAR *buffer1, const CHAR *buffer2) {
+    WRAPPER_NO_CONTRACT;
+    int returnValue = CaseCompareHelperA(buffer1, buffer2, 0, TRUE, FALSE);
+#ifdef VERIFY_CRT_EQUIVALNCE
+    _ASSERTE((returnValue == 0) == (::_stricmp(buffer1, buffer2) == 0));
+#endif
+    return returnValue;
+
+}
+
+/* static */
+inline int __cdecl SString::_strnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count) {
+    WRAPPER_NO_CONTRACT;
+    int returnValue = CaseCompareHelperA(buffer1, buffer2, count, TRUE, TRUE);
+#ifdef VERIFY_CRT_EQUIVALNCE
+    _ASSERTE((returnValue == 0) == (::_strnicmp(buffer1, buffer2, count) == 0));
+#endif
+    return returnValue;
+}
+
+/* static */
+inline int __cdecl SString::_wcsicmp(const WCHAR *buffer1, const WCHAR *buffer2) {
+    WRAPPER_NO_CONTRACT;
+    int returnValue = CaseCompareHelper(buffer1, buffer2, 0, TRUE, FALSE);
+#ifdef VERIFY_CRT_EQUIVALNCE
+    _ASSERTE((returnValue == 0) == (::_wcsicmp(buffer1, buffer2) == 0));
+#endif
+    return returnValue;
+
+}
+
+/* static */
+inline int __cdecl SString::_wcsnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count) {
+    WRAPPER_NO_CONTRACT;
+    int returnValue = CaseCompareHelper(buffer1, buffer2, count, TRUE, TRUE);
+#ifdef VERIFY_CRT_EQUIVALNCE
+    _ASSERTE((returnValue == 0) == (::_wcsnicmp(buffer1, buffer2, count) == 0));
+#endif
+    return returnValue;
+}
+
+inline int SString::_tstricmp(const CHAR *buffer1, const CHAR *buffer2)
+{
+    return _stricmp(buffer1, buffer2);
+}
+
+inline int SString::_tstricmp(const WCHAR *buffer1, const WCHAR *buffer2)
+{
+    return _wcsicmp(buffer1, buffer2);
+}
+
+inline int SString::_tstrnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count)
+{
+    return _strnicmp(buffer1, buffer2, count);
+}
+
+inline int SString::_tstrnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count)
+{
+    return _wcsnicmp(buffer1, buffer2, count);
+}
+
+inline BOOL SString::Match(const CIterator &i, WCHAR c) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        NOTHROW;
+    }
+    SS_CONTRACT_END;
+
+    // End() will not throw here
+    CONTRACT_VIOLATION(ThrowsViolation);
+    SS_RETURN (i < End() && i[0] == c);
+}
+
+inline BOOL SString::Skip(CIterator &i, const SString &s) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(s.Check());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+    }
+    SS_CONTRACT_END;
+
+    if (Match(i, s))
+    {
+        i += s.GetRawCount();
+        SS_RETURN TRUE;
+    }
+    else
+        SS_RETURN FALSE;
+}
+
+inline BOOL SString::Skip(CIterator &i, WCHAR c) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        NOTHROW;
+    }
+    SS_CONTRACT_END;
+
+    if (Match(i, c))
+    {
+        i++;
+        SS_RETURN TRUE;
+    }
+    else
+        SS_RETURN FALSE;
+}
+
+// Find string within this string. Return TRUE and update iterator if found
+inline BOOL SString::Find(CIterator &i, const WCHAR *string) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        SS_POSTCONDITION(RETVAL == Match(i, SString(string)));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(string);
+    SS_RETURN Find(i, s);
+}
+
+inline BOOL SString::FindASCII(CIterator &i, const CHAR *string) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(SString::Ascii, string);
+    SS_RETURN Find(i, s);
+}
+
+inline BOOL SString::FindUTF8(CIterator &i, const CHAR *string) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(SString::Utf8, string);
+    SS_RETURN Find(i, s);
+}
+
+inline BOOL SString::FindBack(CIterator &i, const WCHAR *string) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        SS_POSTCONDITION(RETVAL == Match(i, SString(string)));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(string);
+    SS_RETURN FindBack(i, s);
+}
+
+inline BOOL SString::FindBackASCII(CIterator &i, const CHAR *string) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(SString::Ascii, string);
+    SS_RETURN FindBack(i, s);
+}
+
+inline BOOL SString::FindBackUTF8(CIterator &i, const CHAR *string) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(SString::Utf8, string);
+    SS_RETURN FindBack(i, s);
+}
+
+// Insert string at iterator position
+inline void SString::Insert(const Iterator &i, const SString &s)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(s.Check());
+        THROWS;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    Replace(i, 0, s);
+
+    SS_RETURN;
+}
+
+inline void SString::Insert(const Iterator &i, const WCHAR *string)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(string);
+    Replace(i, 0, s);
+
+    SS_RETURN;
+}
+
+inline void SString::InsertASCII(const Iterator &i, const CHAR *string)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(SString::Ascii, string);
+    Replace(i, 0, s);
+
+    SS_RETURN;
+}
+
+inline void SString::InsertUTF8(const Iterator &i, const CHAR *string)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(CheckPointer(string));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    StackSString s(SString::Utf8, string);
+    Replace(i, 0, s);
+
+    SS_RETURN;
+}
+
+// Delete string at iterator position
+inline void SString::Delete(const Iterator &i, COUNT_T length)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i, length));
+        THROWS;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    Replace(i, length, Empty());
+
+    SS_RETURN;
+}
+
+// Preallocate some space for the string buffer
+inline void SString::Preallocate(COUNT_T characters) const
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Assume unicode since we may get converted
+    SBuffer::Preallocate(characters * sizeof(WCHAR));
+}
+
+// Trim unused space from the buffer
+inline void SString::Trim() const
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (GetRawCount() == 0)
+    {
+        // Share the global empty string buffer.
+        const_cast<SString *>(this)->SBuffer::SetImmutable(s_EmptyBuffer, sizeof(s_EmptyBuffer));
+    }
+    else
+    {
+        SBuffer::Trim();
+    }
+}
+
+// RETURN true if the string is empty.
+inline BOOL SString::IsEmpty() const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        NOTHROW;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    SS_RETURN (GetRawCount() == 0);
+}
+
+// RETURN true if the string rep is ASCII.
+inline BOOL SString::IsASCII() const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        NOTHROW;
+    }
+    SS_CONTRACT_END;
+
+    SS_RETURN IsRepresentation(REPRESENTATION_ASCII);
+}
+
+// Get the number of characters in the string (excluding the terminating NULL)
+inline COUNT_T SString::GetCount() const
+{
+    SS_CONTRACT(COUNT_T)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckCount(RETVAL));
+        THROWS_UNLESS_NORMALIZED;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToFixed();
+
+    SS_RETURN SizeToCount(GetSize());
+}
+
+// Private helpers:
+// Return the current size of the string (even if it is multibyte)
+inline COUNT_T SString::GetRawCount() const
+{
+    WRAPPER_NO_CONTRACT;
+
+    return SizeToCount(GetSize());
+}
+
+// Private helpers:
+// get string contents as a particular character set:
+
+inline ASCII *SString::GetRawASCII() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (ASCII *) m_buffer;
+}
+
+inline UTF8 *SString::GetRawUTF8() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (UTF8 *) m_buffer;
+}
+
+inline ANSI *SString::GetRawANSI() const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (ANSI *) m_buffer;
+}
+
+inline WCHAR *SString::GetRawUnicode() const
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    return (WCHAR *)m_buffer;
+}
+
+// Private helper:
+// get the representation (ansi, unicode, utf8)
+inline SString::Representation SString::GetRepresentation() const
+{
+    WRAPPER_NO_CONTRACT;
+
+    return (Representation) SBuffer::GetRepresentationField();
+}
+
+// Private helper.
+// Set the representation.
+inline void SString::SetRepresentation(SString::Representation representation)
+{
+#ifdef SSTRING_EXTRA_CHECKS
+    CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        NOTHROW;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckRepresentation(representation));
+        POSTCONDITION(GetRepresentation() == representation);
+    }
+    CONTRACT_END;
+#else //SSTRING_EXTRA_CHECKS
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+#endif //SSTRING_EXTRA_CHECKS
+
+    SBuffer::SetRepresentationField((int) representation);
+
+    SS_RETURN;
+}
+
+// Private helper:
+// Get the amount to shift the byte size to get a character count
+inline int SString::GetCharacterSizeShift() const
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Note that the flag is backwards; we want the default
+    // value to match the default representation (empty)
+    return (GetRepresentation()&REPRESENTATION_SINGLE_MASK) == 0;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// We know the buffer should be m_count characters. Place a null terminator
+// in the buffer to make our internal string null-terminated at that length.
+//----------------------------------------------------------------------------
+FORCEINLINE void SString::NullTerminate()
+{
+    SUPPORTS_DAC_HOST_ONLY;
+#ifdef SSTRING_EXTRA_CHECKS
+    CONTRACT_VOID
+    {
+        POSTCONDITION(CheckPointer(this));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+#else //SSTRING_EXTRA_CHECKS
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+#endif //SSTRING_EXTRA_CHECKS
+
+    BYTE *end = m_buffer + GetSize();
+
+    if (GetRepresentation()&REPRESENTATION_SINGLE_MASK)
+    {
+        ((CHAR *)end)[-1] = 0;
+    }
+    else
+    {
+        ((WCHAR *)end)[-1] = 0;
+    }
+
+    SS_RETURN;
+}
+
+//----------------------------------------------------------------------------
+// private helper
+// Return true if the string is a literal.
+// A literal string has immutable memory.
+//----------------------------------------------------------------------------
+inline BOOL SString::IsLiteral() const
+{
+    WRAPPER_NO_CONTRACT;
+
+    return SBuffer::IsImmutable() && (m_buffer != s_EmptyBuffer);
+}
+
+//----------------------------------------------------------------------------
+// private helper:
+// RETURN true if the string allocated (and should delete) its buffer.
+// IsAllocated() will RETURN false for Literal strings and
+// stack-based strings (the buffer is on the stack)
+//----------------------------------------------------------------------------
+inline BOOL SString::IsAllocated() const
+{
+    WRAPPER_NO_CONTRACT;
+
+    return SBuffer::IsAllocated();
+}
+
+//----------------------------------------------------------------------------
+// Return true after we call OpenBuffer(), but before we close it.
+// All SString operations are illegal while the buffer is open.
+//----------------------------------------------------------------------------
+#if _DEBUG
+inline BOOL SString::IsBufferOpen() const
+{
+    WRAPPER_NO_CONTRACT;
+
+    return SBuffer::IsOpened();
+}
+#endif
+
+//----------------------------------------------------------------------------
+// Return true if we've scanned the string to see if it is in the ASCII subset.
+//----------------------------------------------------------------------------
+inline BOOL SString::IsASCIIScanned() const
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+
+    return SBuffer::IsFlag1();
+}
+
+//----------------------------------------------------------------------------
+// Set that we've scanned the string to see if it is in the ASCII subset.
+//----------------------------------------------------------------------------
+inline void SString::SetASCIIScanned() const
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    const_cast<SString *>(this)->SBuffer::SetFlag1();
+}
+
+//----------------------------------------------------------------------------
+// Return true if we've normalized the string to unicode
+//----------------------------------------------------------------------------
+inline BOOL SString::IsNormalized() const
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+
+    return SBuffer::IsFlag3();
+}
+
+//----------------------------------------------------------------------------
+// Set that we've normalized the string to unicode
+//----------------------------------------------------------------------------
+inline void SString::SetNormalized() const
+{
+    WRAPPER_NO_CONTRACT;
+
+    const_cast<SString *>(this)->SBuffer::SetFlag3();
+}
+
+//----------------------------------------------------------------------------
+// Clear normalization
+//----------------------------------------------------------------------------
+inline void SString::ClearNormalized() const
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    const_cast<SString *>(this)->SBuffer::ClearFlag3();
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Check to see if the string representation has single byte size
+//----------------------------------------------------------------------------
+inline BOOL SString::IsSingleByte() const
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    return ((GetRepresentation()&REPRESENTATION_SINGLE_MASK) != 0);
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Check to see if the string representation has fixed size characters
+//----------------------------------------------------------------------------
+inline BOOL SString::IsFixedSize() const
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+
+    if (GetRepresentation()&REPRESENTATION_VARIABLE_MASK)
+        return FALSE;
+    else
+        return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Check to see if the string representation is appropriate for iteration
+//----------------------------------------------------------------------------
+inline BOOL SString::IsIteratable() const
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+
+    // Note that in many cases ANSI may be fixed width.  However we
+    // currently still do not allow iterating on them, because we would have to
+    // do character-by-character conversion on a character dereference (which must
+    // go to unicode) .  We may want to adjust this going forward to
+    // depending on perf in the non-ASCII but fixed width ANSI case.
+
+    return ((GetRepresentation()&REPRESENTATION_VARIABLE_MASK) == 0);
+}
+
+//----------------------------------------------------------------------------
+// Private helper
+// Return the size of the given string in bytes
+// in the given representation.
+// count does not include the null-terminator, but the RETURN value does.
+//----------------------------------------------------------------------------
+inline COUNT_T SString::CountToSize(COUNT_T count) const
+{
+    SS_CONTRACT(COUNT_T)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckCount(count));
+        SS_POSTCONDITION(SizeToCount(RETVAL) == count);
+        NOTHROW;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    SS_RETURN (count+1) << GetCharacterSizeShift();
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Return the maxmimum count of characters that could fit in a buffer of
+// 'size' bytes in the given representation.
+// 'size' includes the null terminator, but the RETURN value does not.
+//----------------------------------------------------------------------------
+inline COUNT_T SString::SizeToCount(COUNT_T size) const
+{
+    SS_CONTRACT(COUNT_T)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckSize(size));
+        SS_POSTCONDITION(CountToSize(RETVAL) == size);
+        NOTHROW;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    SS_RETURN (size >> GetCharacterSizeShift()) - 1;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Return the maxmimum count of characters that could fit in the current
+// buffer including NULL terminator.
+//----------------------------------------------------------------------------
+inline COUNT_T SString::GetBufferSizeInCharIncludeNullChar() const
+{
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+
+    return (GetSize() >> GetCharacterSizeShift());
+}
+
+
+
+//----------------------------------------------------------------------------
+// Assert helper
+// Asser that the iterator is within the given string.
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckIteratorRange(const CIterator &i) const
+{
+    CANNOT_HAVE_CONTRACT;
+    CHECK(i >= Begin());
+    CHECK(i <= End()); // Note that it's OK to look at the terminating null
+    CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Assert helper
+// Asser that the iterator is within the given string.
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckIteratorRange(const CIterator &i, COUNT_T length) const
+{
+    CANNOT_HAVE_CONTRACT;
+    CHECK(i >= Begin());
+    CHECK(i + length <= End());  // Note that it's OK to look at the terminating null
+    CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Assert that the string is empty
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckEmpty() const
+{
+    CANNOT_HAVE_CONTRACT;
+    CHECK(IsEmpty());
+    CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Check the range of a count
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckCount(COUNT_T count)
+{
+    CANNOT_HAVE_CONTRACT;
+    CHECK(CheckSize(count*sizeof(WCHAR)));
+    CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Check the representation field
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckRepresentation(int representation)
+{
+    CANNOT_HAVE_CONTRACT;
+    CHECK(representation == REPRESENTATION_EMPTY
+          || representation == REPRESENTATION_UNICODE
+          || representation == REPRESENTATION_ASCII
+          || representation == REPRESENTATION_UTF8
+          || representation == REPRESENTATION_ANSI);
+    CHECK((representation & REPRESENTATION_MASK) == representation);
+
+    CHECK_OK;
+}
+
+#if CHECK_INVARIANTS
+//----------------------------------------------------------------------------
+// Assert helper. Check that the string only uses the ASCII subset of
+// codes.
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckASCIIString(const CHAR *string)
+{
+    CANNOT_HAVE_CONTRACT;
+    if (string != NULL)
+        CHECK(CheckASCIIString(string, (int) strlen(string)));
+    CHECK_OK;
+}
+
+inline CHECK SString::CheckASCIIString(const CHAR *string, COUNT_T count)
+{
+    CANNOT_HAVE_CONTRACT;
+#if _DEBUG
+    const CHAR *sEnd = string + count;
+    while (string < sEnd)
+    {
+        CHECK_MSG((*string & 0x80) == 0x00, "Found non-ASCII character in string.");
+        string++;
+    }
+#endif
+    CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Check routine and invariants.
+//----------------------------------------------------------------------------
+
+inline CHECK SString::Check() const
+{
+    CANNOT_HAVE_CONTRACT;
+    CHECK(SBuffer::Check());
+    CHECK_OK;
+}
+
+inline CHECK SString::Invariant() const
+{
+    CANNOT_HAVE_CONTRACT;
+    CHECK(SBuffer::Invariant());
+    CHECK_OK;
+}
+
+inline CHECK SString::InternalInvariant() const
+{
+    CANNOT_HAVE_CONTRACT;
+    CHECK(SBuffer::InternalInvariant());
+    CHECK(SBuffer::GetSize() >= 2);
+    if (IsNormalized())
+        CHECK(IsRepresentation(REPRESENTATION_UNICODE));
+    CHECK_OK;
+}
+#endif  // CHECK_INVARIANTS
+
+//----------------------------------------------------------------------------
+// Return a writeable buffer that can store 'countChars'+1 unicode characters.
+// Call CloseBuffer when done.
+//----------------------------------------------------------------------------
+inline WCHAR *SString::OpenUnicodeBuffer(COUNT_T countChars)
+{
+    SS_CONTRACT(WCHAR*)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckCount(countChars));
+#if _DEBUG
+        SS_POSTCONDITION(IsBufferOpen());
+#endif
+        SS_POSTCONDITION(GetRawCount() == countChars);
+        SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_UNICODE || countChars == 0);
+        SS_POSTCONDITION(CheckPointer(RETVAL));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    OpenBuffer(REPRESENTATION_UNICODE, countChars);
+    SS_RETURN GetRawUnicode();
+}
+
+//----------------------------------------------------------------------------
+// Return a copy of the underlying  buffer, the caller is responsible for managing
+// the returned memory
+//----------------------------------------------------------------------------
+inline WCHAR *SString::GetCopyOfUnicodeString()
+{
+    SS_CONTRACT(WCHAR*)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckPointer(buffer));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+    NewArrayHolder<WCHAR> buffer = NULL;
+
+    buffer = new WCHAR[GetCount() +1];
+    wcscpy_s(buffer, GetCount() + 1, GetUnicode());
+
+    SS_RETURN buffer.Extract();
+}
+
+//----------------------------------------------------------------------------
+// Return a writeable buffer that can store 'countChars'+1 ansi characters.
+// Call CloseBuffer when done.
+//----------------------------------------------------------------------------
+inline ANSI *SString::OpenANSIBuffer(COUNT_T countChars)
+{
+    SS_CONTRACT(ANSI*)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckCount(countChars));
+#if _DEBUG
+        SS_POSTCONDITION(IsBufferOpen());
+#endif
+        SS_POSTCONDITION(GetRawCount() == countChars);
+        SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_ANSI || countChars == 0);
+        SS_POSTCONDITION(CheckPointer(RETVAL));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    OpenBuffer(REPRESENTATION_ANSI, countChars);
+    SS_RETURN GetRawANSI();
+}
+
+//----------------------------------------------------------------------------
+// Return a writeable buffer that can store 'countChars'+1 ansi characters.
+// Call CloseBuffer when done.
+//----------------------------------------------------------------------------
+inline UTF8 *SString::OpenUTF8Buffer(COUNT_T countBytes)
+{
+    SS_CONTRACT(UTF8*)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckCount(countBytes));
+#if _DEBUG
+        SS_POSTCONDITION(IsBufferOpen());
+#endif
+        SS_POSTCONDITION(GetRawCount() == countBytes);
+        SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_UTF8 || countBytes == 0);
+        SS_POSTCONDITION(CheckPointer(RETVAL));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    OpenBuffer(REPRESENTATION_UTF8, countBytes);
+    SS_RETURN GetRawUTF8();
+}
+
+//----------------------------------------------------------------------------
+// Private helper to open a raw buffer.
+// Called by public functions to open the buffer in the specific
+// representation.
+// While the buffer is opened, all other operations are illegal. Call
+// CloseBuffer() when done.
+//----------------------------------------------------------------------------
+inline void SString::OpenBuffer(SString::Representation representation, COUNT_T countChars)
+{
+#ifdef SSTRING_EXTRA_CHECKS
+    CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION_MSG(!IsBufferOpen(), "Can't nest calls to OpenBuffer()");
+        PRECONDITION(CheckRepresentation(representation));
+        PRECONDITION(CheckSize(countChars));
+#if _DEBUG
+        POSTCONDITION(IsBufferOpen());
+#endif
+        POSTCONDITION(GetRawCount() == countChars);
+        POSTCONDITION(GetRepresentation() == representation || countChars == 0);
+        THROWS;
+    }
+    CONTRACT_END;
+#else
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_THROWS;
+#endif
+
+    Resize(countChars, representation);
+
+    SBuffer::OpenRawBuffer(CountToSize(countChars));
+
+    SS_RETURN;
+}
+
+//----------------------------------------------------------------------------
+// Get the max size that can be passed to OpenUnicodeBuffer without causing
+// allocations.
+//----------------------------------------------------------------------------
+inline COUNT_T SString::GetUnicodeAllocation()
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    COUNT_T allocation = GetAllocation();
+    return ( (allocation > sizeof(WCHAR))
+        ? (allocation - sizeof(WCHAR)) / sizeof(WCHAR) : 0 );
+}
+
+//----------------------------------------------------------------------------
+// Close an open buffer. Assumes that we wrote exactly number of characters
+// we requested in OpenBuffer.
+//----------------------------------------------------------------------------
+inline void SString::CloseBuffer()
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+#if _DEBUG
+        PRECONDITION_MSG(IsBufferOpen(), "Can only CloseBuffer() after a call to OpenBuffer()");
+#endif
+        SS_POSTCONDITION(CheckPointer(this));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    SBuffer::CloseRawBuffer();
+    NullTerminate();
+
+    SS_RETURN;
+}
+
+//----------------------------------------------------------------------------
+// CloseBuffer() tells the SString that we're done using the unsafe buffer.
+// countChars is the count of characters actually used (so we can set m_count).
+// This is important if we request a buffer larger than what we actually
+// used.
+//----------------------------------------------------------------------------
+inline void SString::CloseBuffer(COUNT_T finalCount)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+#if _DEBUG
+        PRECONDITION_MSG(IsBufferOpen(), "Can only CloseBuffer() after a call to OpenBuffer()");
+#endif
+        PRECONDITION(CheckSize(finalCount));
+        SS_POSTCONDITION(CheckPointer(this));
+        SS_POSTCONDITION(GetRawCount() == finalCount);
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    SBuffer::CloseRawBuffer(CountToSize(finalCount));
+    NullTerminate();
+
+    SS_RETURN;
+}
+
+//----------------------------------------------------------------------------
+// EnsureWritable
+// Ensures that the buffer is writable
+//----------------------------------------------------------------------------
+inline void SString::EnsureWritable() const
+{
+#ifdef SSTRING_EXTRA_CHECKS
+    CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        POSTCONDITION(!IsLiteral());
+        THROWS;
+    }
+    CONTRACT_END;
+#else //SSTRING_EXTRA_CHECKS
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_THROWS;
+#endif //SSTRING_EXTRA_CHECKS
+
+    if (IsLiteral())
+        const_cast<SString *>(this)->Resize(GetRawCount(), GetRepresentation(), PRESERVE);
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Convert the internal representation to be a fixed size
+//-----------------------------------------------------------------------------
+inline void SString::ConvertToFixed() const
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        SS_PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(IsFixedSize());
+        THROWS_UNLESS_NORMALIZED;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    // If we're already fixed size, great.
+    if (IsFixedSize())
+        SS_RETURN;
+
+    // See if we can coerce it to ASCII.
+    if (ScanASCII())
+        SS_RETURN;
+
+    // Convert to unicode then.
+    ConvertToUnicode();
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Convert the internal representation to be an iteratable one (current
+// requirements here are that it be trivially convertable to unicode chars.)
+//-----------------------------------------------------------------------------
+inline void SString::ConvertToIteratable() const
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        SS_PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(IsIteratable());
+        THROWS_UNLESS_NORMALIZED;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    // If we're already iteratable, great.
+    if (IsIteratable())
+        SS_RETURN;
+
+    // See if we can coerce it to ASCII.
+    if (ScanASCII())
+        SS_RETURN;
+
+    // Convert to unicode then.
+    ConvertToUnicode();
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Create iterators on the string.
+//-----------------------------------------------------------------------------
+
+inline SString::UIterator SString::BeginUnicode()
+{
+    SS_CONTRACT(SString::UIterator)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckValue(RETVAL));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToUnicode();
+    EnsureWritable();
+
+    SS_RETURN UIterator(this, 0);
+}
+
+inline SString::UIterator SString::EndUnicode()
+{
+    SS_CONTRACT(SString::UIterator)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckValue(RETVAL));
+        THROWS;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToUnicode();
+    EnsureWritable();
+
+    SS_RETURN UIterator(this, GetCount());
+}
+
+//-----------------------------------------------------------------------------
+// Create CIterators on the string.
+//-----------------------------------------------------------------------------
+
+FORCEINLINE SString::CIterator SString::Begin() const
+{
+    SS_CONTRACT(SString::CIterator)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckValue(RETVAL));
+        THROWS_UNLESS_NORMALIZED;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToIteratable();
+
+    SS_RETURN CIterator(this, 0);
+}
+
+FORCEINLINE SString::CIterator SString::End() const
+{
+    SS_CONTRACT(SString::CIterator)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckValue(RETVAL));
+        THROWS_UNLESS_NORMALIZED;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToIteratable();
+
+    SS_RETURN CIterator(this, GetCount());
+}
+
+//-----------------------------------------------------------------------------
+// Create Iterators on the string.
+//-----------------------------------------------------------------------------
+
+FORCEINLINE SString::Iterator SString::Begin()
+{
+    SS_CONTRACT(SString::Iterator)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckValue(RETVAL));
+        THROWS; // EnsureMutable always throws
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToIteratable();
+    EnsureMutable();
+
+    SS_RETURN Iterator(this, 0);
+}
+
+FORCEINLINE SString::Iterator SString::End()
+{
+    SS_CONTRACT(SString::Iterator)
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckValue(RETVAL));
+        THROWS; // EnsureMutable always Throws
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToIteratable();
+    EnsureMutable();
+
+    SS_RETURN Iterator(this, GetCount());
+}
+
+//-----------------------------------------------------------------------------
+// CIterator support routines
+//-----------------------------------------------------------------------------
+
+inline SString::Index::Index()
+{
+    LIMITED_METHOD_CONTRACT;
+}
+
+inline SString::Index::Index(SString *string, SCOUNT_T index)
+  : SBuffer::Index(string, index<<string->GetCharacterSizeShift())
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(string));
+        PRECONDITION(string->IsIteratable());
+        PRECONDITION(DoCheck(0));
+        SS_POSTCONDITION(CheckPointer(this));
+        // POSTCONDITION(Subtract(string->Begin()) == index); contract violation - fix later
+        NOTHROW;
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    m_characterSizeShift = string->GetCharacterSizeShift();
+
+    SS_RETURN;
+}
+
+inline BYTE &SString::Index::GetAt(SCOUNT_T delta) const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return m_ptr[delta<<m_characterSizeShift];
+}
+
+inline void SString::Index::Skip(SCOUNT_T delta)
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    m_ptr += (delta<<m_characterSizeShift);
+}
+
+inline SCOUNT_T SString::Index::Subtract(const Index &i) const
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (SCOUNT_T) ((m_ptr - i.m_ptr)>>m_characterSizeShift);
+}
+
+inline CHECK SString::Index::DoCheck(SCOUNT_T delta) const
+{
+    CANNOT_HAVE_CONTRACT;
+#if _DEBUG
+    const SString *string = (const SString *) GetContainerDebug();
+
+    CHECK(m_ptr + (delta<<m_characterSizeShift) >= string->m_buffer);
+    CHECK(m_ptr + (delta<<m_characterSizeShift) < string->m_buffer + string->GetSize());
+#endif
+    CHECK_OK;
+}
+
+inline void SString::Index::Resync(const SString *string, BYTE *ptr) const
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+
+    SBuffer::Index::Resync(string, ptr);
+
+    const_cast<SString::Index*>(this)->m_characterSizeShift = string->GetCharacterSizeShift();
+}
+
+
+inline const WCHAR *SString::Index::GetUnicode() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (const WCHAR *) m_ptr;
+}
+
+inline const CHAR *SString::Index::GetASCII() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (const CHAR *) m_ptr;
+}
+
+inline WCHAR SString::Index::operator*() const
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+
+    if (m_characterSizeShift == 0)
+        return *(CHAR*)&GetAt(0);
+    else
+        return *(WCHAR*)&GetAt(0);
+}
+
+inline void SString::Index::operator->() const
+{
+    LIMITED_METHOD_CONTRACT;
+}
+
+inline WCHAR SString::Index::operator[](int index) const
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (m_characterSizeShift == 0)
+        return *(CHAR*)&GetAt(index);
+    else
+        return *(WCHAR*)&GetAt(index);
+}
+
+//-----------------------------------------------------------------------------
+// Iterator support routines
+//-----------------------------------------------------------------------------
+
+inline SString::UIndex::UIndex()
+{
+    LIMITED_METHOD_CONTRACT;
+}
+
+inline SString::UIndex::UIndex(SString *string, SCOUNT_T index)
+  : SBuffer::Index(string, index*sizeof(WCHAR))
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(string));
+        PRECONDITION(string->IsRepresentation(REPRESENTATION_UNICODE));
+        PRECONDITION(DoCheck(0));
+        SS_POSTCONDITION(CheckPointer(this));
+        NOTHROW;
+        CANNOT_TAKE_LOCK;
+    }
+    SS_CONTRACT_END;
+
+    SS_RETURN;
+}
+
+inline WCHAR &SString::UIndex::GetAt(SCOUNT_T delta) const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return ((WCHAR*)m_ptr)[delta];
+}
+
+inline void SString::UIndex::Skip(SCOUNT_T delta)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    m_ptr += delta * sizeof(WCHAR);
+}
+
+inline SCOUNT_T SString::UIndex::Subtract(const UIndex &i) const
+{
+    WRAPPER_NO_CONTRACT;
+
+    return (SCOUNT_T) (GetUnicode() - i.GetUnicode());
+}
+
+inline CHECK SString::UIndex::DoCheck(SCOUNT_T delta) const
+{
+    CANNOT_HAVE_CONTRACT;
+#if _DEBUG
+    const SString *string = (const SString *) GetContainerDebug();
+
+    CHECK(GetUnicode() + delta >= string->GetRawUnicode());
+    CHECK(GetUnicode() + delta <= string->GetRawUnicode() + string->GetCount());
+#endif
+
+    CHECK_OK;
+}
+
+inline WCHAR *SString::UIndex::GetUnicode() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (WCHAR*) m_ptr;
+}
+
+//-----------------------------------------------------------------------------
+// Opaque scratch buffer class routines
+//-----------------------------------------------------------------------------
+inline SString::AbstractScratchBuffer::AbstractScratchBuffer(void *buffer, COUNT_T size)
+  : SString(buffer, size)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(buffer));
+        PRECONDITION(CheckCount(size));
+        NOTHROW;
+    }
+    SS_CONTRACT_END;
+
+    SS_RETURN;
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+
+#endif  // _SSTRING_INL_
diff --git a/src/inc/stacktrace.h b/src/inc/stacktrace.h
deleted file mode 100644 (file)
index b843eee..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-
-#ifndef __STACK_TRACE_H__
-#define __STACK_TRACE_H__
-
-HINSTANCE LoadImageHlp();
-HINSTANCE LoadDbgHelp();
-
-#include <specstrings.h>
-
-//
-//--- Constants ---------------------------------------------------------------
-//
-
-#define cchMaxAssertModuleLen 60
-#define cchMaxAssertSymbolLen 257
-#define cfrMaxAssertStackLevels 20
-#define cchMaxAssertExprLen 257
-
-#ifdef HOST_64BIT
-
-#define cchMaxAssertStackLevelStringLen \
-    ((3 * 8) + cchMaxAssertModuleLen + cchMaxAssertSymbolLen + 13)
-    // 3 addresses of at most 8 char, module, symbol, and the extra chars:
-    // 0x<address>: <module>! <symbol> + 0x<offset>\n
-    //FMT_ADDR_BARE   is defined as   "%08x`%08x" on Win64, and as
-    //"%08x" on 32 bit platforms. Hence the difference in the definitions.
-
-#else
-
-#define cchMaxAssertStackLevelStringLen \
-    ((2 * 8) + cchMaxAssertModuleLen + cchMaxAssertSymbolLen + 12)
-    // 2 addresses of at most 8 char, module, symbol, and the extra chars:
-    // 0x<address>: <module>! <symbol> + 0x<offset>\n
-
-#endif
-
-//
-//--- Prototypes --------------------------------------------------------------
-//
-
-/****************************************************************************
-* MagicDeinit *
-*-------------*
-*   Description:
-*       Cleans up for the symbol loading code. Should be called before
-*       exiting in order to free the dynamically loaded imagehlp.dll
-******************************************************************** robch */
-void MagicDeinit(void);
-
-/****************************************************************************
-* GetStringFromStackLevels *
-*--------------------------*
-*   Description:
-*       Retrieves a string from the stack frame. If more than one frame, they
-*       are separated by newlines. Each fram appears in this format:
-*
-*           0x<address>: <module>! <symbol> + 0x<offset>
-******************************************************************** robch */
-void GetStringFromStackLevels(UINT ifrStart, UINT cfrTotal, _Out_writes_(cchMaxAssertStackLevelStringLen * cfrTotal) CHAR *pszString, struct _CONTEXT * pContext = NULL);
-
-/****************************************************************************
-* GetStringFromAddr *
-*-------------------*
-*   Description:
-*       Builds a string from an address in the format:
-*
-*           0x<address>: <module>! <symbol> + 0x<offset>
-******************************************************************** robch */
-void GetStringFromAddr(DWORD_PTR dwAddr, _Out_writes_(cchMaxAssertStackLevelStringLen) LPSTR szString);
-
-#if defined(HOST_X86) && !defined(TARGET_UNIX)
-/****************************************************************************
-* ClrCaptureContext *
-*-------------------*
-*   Description:
-*       Exactly the contents of RtlCaptureContext for Win7 - Win2K doesn't
-*       support this, so we need it for CoreCLR 4, if we require Win2K support
-****************************************************************************/
-extern "C" void __stdcall ClrCaptureContext(_Out_ PCONTEXT ctx);
-#else // HOST_X86 && !TARGET_UNIX
-#define ClrCaptureContext RtlCaptureContext
-#endif // HOST_X86 && !TARGET_UNIX
-
-
-#endif
diff --git a/src/inc/stdmacros.h b/src/inc/stdmacros.h
new file mode 100644 (file)
index 0000000..2d0a057
--- /dev/null
@@ -0,0 +1,347 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+
+//
+// common.h - precompiled headers include for the COM+ Execution Engine
+//
+
+//
+// Make sure _ASSERTE is defined before including this header file
+// Other than that, please keep this header self-contained so that it can be included in
+//  all dlls
+//
+
+
+#ifndef _stdmacros_h_
+#define _stdmacros_h_
+
+#include "specstrings.h"
+#include "contract.h"
+
+#ifndef _ASSERTE
+#error Please define _ASSERTE before including StdMacros.h
+#endif
+
+#ifdef _DEBUG
+#define     DEBUG_ARG(x)  , x
+#define     DEBUG_ARG1(x)  x
+#else
+#define     DEBUG_ARG(x)
+#define     DEBUG_ARG1(x)
+#endif
+
+#ifdef DACCESS_COMPILE
+#define     DAC_ARG(x)  , x
+#else
+#define     DAC_ARG(x)
+#endif
+
+
+/********************************************/
+/*         Portability macros               */
+/********************************************/
+
+#ifdef TARGET_AMD64
+#define AMD64_FIRST_ARG(x)  x ,
+#define AMD64_ARG(x)        , x
+#define AMD64_ONLY(x)       x
+#define NOT_AMD64(x)
+#define NOT_AMD64_ARG(x)
+#else
+#define AMD64_FIRST_ARG(x)
+#define AMD64_ARG(x)
+#define AMD64_ONLY(x)
+#define NOT_AMD64(x)        x
+#define NOT_AMD64_ARG(x)    , x
+#endif
+
+#ifdef TARGET_X86
+#define X86_FIRST_ARG(x)    x ,
+#define X86_ARG(x)          , x
+#define X86_ONLY(x)         x
+#define NOT_X86(x)
+#define NOT_X86_ARG(x)
+#else
+#define X86_FIRST_ARG(x)
+#define X86_ARG(x)
+#define X86_ONLY(x)
+#define NOT_X86(x)          x
+#define NOT_X86_ARG(x)      , x
+#endif
+
+#ifdef HOST_64BIT
+#define BIT64_ARG(x)  , x
+#define BIT64_ONLY(x) x
+#define NOT_BIT64(x)
+#define NOT_BIT64_ARG(x)
+#else
+#define BIT64_ARG(x)
+#define BIT64_ONLY(x)
+#define NOT_BIT64(x)    x
+#define NOT_BIT64_ARG(x)    , x
+#endif // HOST_64BIT
+
+#ifdef TARGET_ARM
+#define ARM_FIRST_ARG(x)  x ,
+#define ARM_ARG(x)        , x
+#define ARM_ONLY(x)       x
+#define NOT_ARM(x)
+#define NOT_ARM_ARG(x)
+#else
+#define ARM_FIRST_ARG(x)
+#define ARM_ARG(x)
+#define ARM_ONLY(x)
+#define NOT_ARM(x)        x
+#define NOT_ARM_ARG(x)    , x
+#endif
+
+#ifdef TARGET_ARM64
+#define ARM64_FIRST_ARG(x)  x ,
+#define ARM64_ARG(x)        , x
+#define ARM64_ONLY(x)       x
+#define NOT_ARM64(x)
+#define NOT_ARM64_ARG(x)
+#else
+#define ARM64_FIRST_ARG(x)
+#define ARM64_ARG(x)
+#define ARM64_ONLY(x)
+#define NOT_ARM64(x)        x
+#define NOT_ARM64_ARG(x)    , x
+#endif
+
+#ifdef TARGET_64BIT
+#define LOG2_PTRSIZE 3
+#else
+#define LOG2_PTRSIZE 2
+#endif
+
+#ifdef HOST_64BIT
+    #define INVALID_POINTER_CC 0xcccccccccccccccc
+    #define INVALID_POINTER_CD 0xcdcdcdcdcdcdcdcd
+    #define FMT_ADDR           " %08x`%08x "
+    #define LFMT_ADDR          W(" %08x`%08x ")
+    #define DBG_ADDR(ptr)      (DWORD)(((UINT_PTR) (ptr)) >> 32), (DWORD)(((UINT_PTR) (ptr)) & 0xffffffff)
+#else // HOST_64BIT
+    #define INVALID_POINTER_CC 0xcccccccc
+    #define INVALID_POINTER_CD 0xcdcdcdcd
+    #define FMT_ADDR           " %08x "
+    #define LFMT_ADDR          W(" %08x ")
+    #define DBG_ADDR(ptr)      (DWORD)((UINT_PTR)(ptr))
+#endif // HOST_64BIT
+
+#ifdef TARGET_ARM
+    #define ALIGN_ACCESS        ((1<<LOG2_PTRSIZE)-1)
+#endif
+
+
+#ifndef ALLOC_ALIGN_CONSTANT
+#define ALLOC_ALIGN_CONSTANT (sizeof(void*)-1)
+#endif
+
+
+inline void *GetTopMemoryAddress(void)
+{
+    WRAPPER_NO_CONTRACT;
+
+    static void *result; // = NULL;
+    if( NULL == result )
+    {
+        SYSTEM_INFO sysInfo;
+        GetSystemInfo( &sysInfo );
+        result = sysInfo.lpMaximumApplicationAddress;
+    }
+    return result;
+}
+inline void *GetBotMemoryAddress(void)
+{
+    WRAPPER_NO_CONTRACT;
+
+    static void *result; // = NULL;
+    if( NULL == result )
+    {
+        SYSTEM_INFO sysInfo;
+        GetSystemInfo( &sysInfo );
+        result = sysInfo.lpMinimumApplicationAddress;
+    }
+    return result;
+}
+
+#define TOP_MEMORY (GetTopMemoryAddress())
+#define BOT_MEMORY (GetBotMemoryAddress())
+
+
+//
+// This macro returns val rounded up as necessary to be a multiple of alignment; alignment must be a power of 2
+//
+inline size_t ALIGN_UP( size_t val, size_t alignment )
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    // alignment must be a power of 2 for this implementation to work (need modulo otherwise)
+    _ASSERTE( 0 == (alignment & (alignment - 1)) );
+    size_t result = (val + (alignment - 1)) & ~(alignment - 1);
+    _ASSERTE( result >= val );      // check for overflow
+    return result;
+}
+
+template <typename T> inline T ALIGN_UP(T val, size_t alignment)
+{
+    WRAPPER_NO_CONTRACT;
+    return (T)ALIGN_UP((size_t)val, alignment);
+}
+
+inline size_t ALIGN_DOWN( size_t val, size_t alignment )
+{
+    LIMITED_METHOD_CONTRACT;
+
+    // alignment must be a power of 2 for this implementation to work (need modulo otherwise)
+    _ASSERTE( 0 == (alignment & (alignment - 1)) );
+    size_t result = val & ~(alignment - 1);
+    return result;
+}
+inline void* ALIGN_DOWN( void* val, size_t alignment )
+{
+    WRAPPER_NO_CONTRACT;
+    return (void*) ALIGN_DOWN( (size_t)val, alignment );
+}
+inline uint8_t* ALIGN_DOWN( uint8_t* val, size_t alignment )
+{
+    WRAPPER_NO_CONTRACT;
+    return (uint8_t*) ALIGN_DOWN( (size_t)val, alignment );
+}
+
+inline BOOL IS_ALIGNED( size_t val, size_t alignment )
+{
+    LIMITED_METHOD_CONTRACT;
+    SUPPORTS_DAC;
+
+    // alignment must be a power of 2 for this implementation to work (need modulo otherwise)
+    _ASSERTE( 0 == (alignment & (alignment - 1)) );
+    return 0 == (val & (alignment - 1));
+}
+inline BOOL IS_ALIGNED( const void* val, size_t alignment )
+{
+    WRAPPER_NO_CONTRACT;
+    return IS_ALIGNED( (size_t) val, alignment );
+}
+
+// Rounds a ULONG up to the nearest power of two number.
+inline ULONG RoundUpToPower2(ULONG x)
+{
+    if (x == 0) return 1;
+
+    x = x - 1;
+    x = x | (x >> 1);
+    x = x | (x >> 2);
+    x = x | (x >> 4);
+    x = x | (x >> 8);
+    x = x | (x >> 16);
+    return x + 1;
+}
+
+#ifdef ALIGN_ACCESS
+
+// NOTE: pSrc is evaluated three times!!!
+#define MAYBE_UNALIGNED_READ(pSrc, bits)        (IS_ALIGNED((size_t)(pSrc), sizeof(UINT##bits)) ? \
+                                                    (*(UINT##bits*)      (pSrc)) : \
+                                                    (GET_UNALIGNED_##bits(pSrc)) )
+
+#define MAYBE_UNALIGNED_WRITE(pDst, bits, expr) do { if (IS_ALIGNED((size_t)(pDst), sizeof(UINT##bits))) \
+                                                    *(UINT##bits*)(pDst) = (UINT##bits)(expr); else \
+                                                    SET_UNALIGNED_##bits(pDst, (UINT##bits)(expr)); } while (0)
+
+// these are necessary for MAYBE_UNALIGNED_XXX to work with UINT_PTR
+#define GET_UNALIGNED__PTR(x) GET_UNALIGNED_PTR(x)
+#define SET_UNALIGNED__PTR(p,x) SET_UNALIGNED_PTR(p,x)
+
+#else // ALIGN_ACCESS
+#define MAYBE_UNALIGNED_READ(pSrc, bits)        (*(UINT##bits*)(pSrc))
+#define MAYBE_UNALIGNED_WRITE(pDst, bits, expr) do { *(UINT##bits*)(pDst) = (UINT##bits)(expr); } while(0)
+#endif // ALIGN_ACCESS
+
+//
+// define some useful macros for logging object
+//
+
+#define FMT_OBJECT  "object" FMT_ADDR
+#define FMT_HANDLE  "handle" FMT_ADDR
+#define FMT_CLASS   "%s"
+#define FMT_REG     "r%d "
+#define FMT_STK     "sp%s0x%02x "
+#define FMT_PIPTR   "%s%s pointer "
+
+
+#define DBG_GET_CLASS_NAME(pMT)        \
+        (((pMT) == NULL)  ? NULL : (pMT)->GetClass()->GetDebugClassName())
+
+#define DBG_CLASS_NAME_MT(pMT)         \
+        (DBG_GET_CLASS_NAME(pMT) == NULL) ? "<null-class>" : DBG_GET_CLASS_NAME(pMT)
+
+#define DBG_GET_MT_FROM_OBJ(obj)       \
+        (MethodTable*)((size_t)((Object*) (obj))->GetGCSafeMethodTable())
+
+#define DBG_CLASS_NAME_OBJ(obj)        \
+        ((obj) == NULL)  ? "null" : DBG_CLASS_NAME_MT(DBG_GET_MT_FROM_OBJ(obj))
+
+#define DBG_CLASS_NAME_IPTR2(obj,iptr) \
+        ((iptr) != 0)    ? ""     : DBG_CLASS_NAME_MT(DBG_GET_MT_FROM_OBJ(obj))
+
+#define DBG_CLASS_NAME_IPTR(obj,iptr)  \
+        ((obj)  == NULL) ? "null" : DBG_CLASS_NAME_IPTR2(obj,iptr)
+
+#define DBG_STK(off)                   \
+        (off >= 0) ? "+" : "-",        \
+        (off >= 0) ? off : -off
+
+#define DBG_PIN_NAME(pin)              \
+        (pin)  ? "pinned "  : ""
+
+#define DBG_IPTR_NAME(iptr)            \
+        (iptr) ? "interior" : "base"
+
+#define LOG_HANDLE_OBJECT_CLASS(str1, hnd, str2, obj)    \
+        str1 FMT_HANDLE str2 FMT_OBJECT FMT_CLASS "\n",  \
+        DBG_ADDR(hnd), DBG_ADDR(obj), DBG_CLASS_NAME_OBJ(obj)
+
+#define LOG_OBJECT_CLASS(obj)                            \
+        FMT_OBJECT FMT_CLASS "\n",                       \
+        DBG_ADDR(obj), DBG_CLASS_NAME_OBJ(obj)
+
+#define LOG_PIPTR_OBJECT_CLASS(obj, pin, iptr)           \
+        FMT_PIPTR FMT_ADDR FMT_CLASS "\n",               \
+        DBG_PIN_NAME(pin), DBG_IPTR_NAME(iptr),          \
+        DBG_ADDR(obj), DBG_CLASS_NAME_IPTR(obj,iptr)
+
+#define LOG_HANDLE_OBJECT(str1, hnd, str2, obj)          \
+        str1 FMT_HANDLE str2 FMT_OBJECT "\n",            \
+        DBG_ADDR(hnd), DBG_ADDR(obj)
+
+#define LOG_PIPTR_OBJECT(obj, pin, iptr)                 \
+        FMT_PIPTR FMT_ADDR "\n",                         \
+        DBG_PIN_NAME(pin), DBG_IPTR_NAME(iptr),          \
+        DBG_ADDR(obj)
+
+#define UNIQUE_LABEL_DEF(a,x)           a##x
+#define UNIQUE_LABEL_DEF_X(a,x)         UNIQUE_LABEL_DEF(a,x)
+#ifdef _MSC_VER
+#define UNIQUE_LABEL(a)                 UNIQUE_LABEL_DEF_X(_unique_label_##a##_, __COUNTER__)
+#else
+#define UNIQUE_LABEL(a)                 UNIQUE_LABEL_DEF_X(_unique_label_##a##_, __LINE__)
+#endif
+
+// This is temporary.  LKG should provide these macros and we should then
+// remove STRUNCATE and _TRUNCATE from here.
+
+/* error codes */
+#if !defined(STRUNCATE)
+#define STRUNCATE       80
+#endif
+
+/* _TRUNCATE */
+#if !defined(_TRUNCATE)
+#define _TRUNCATE ((size_t)-1)
+#endif
+
+#endif //_stdmacros_h_
index c9cb99bc74df8ffff3836581288a9537e0e3b628..cd6f10abb95e437d1a58cd4c778518488a855acb 100644 (file)
 #include "log.h"
 
 #if defined(STRESS_LOG) && !defined(FEATURE_NO_STRESSLOG)
-#include "releaseholder.h"
-#include "volatile.h"
 #include "staticcontract.h"
 #include "mscoree.h"
 #include "clrinternal.h"
+#include "volatile.h"
+#ifndef STRESS_LOG_ANALYZER
+#include "holder.h"
 #ifdef STRESS_LOG_READONLY
 #include <stddef.h> // offsetof
 #else //STRESS_LOG_READONLY
@@ -44,6 +45,9 @@
 #ifndef _ASSERTE
 #define _ASSERTE(expr)
 #endif
+#else
+#include <stddef.h> // offsetof
+#endif // STRESS_LOG_ANALYZER
 
 /* The STRESS_LOG* macros work like printf.  In fact the use printf in their implementation
    so all printf format specifications work.  In addition the Stress log dumper knows
@@ -508,6 +512,21 @@ typedef USHORT
     static StressLog theLog;    // We only have one log, and this is it
 };
 
+#ifndef STRESS_LOG_ANALYZER
+typedef Holder<CRITSEC_COOKIE, StressLog::Enter, StressLog::Leave, NULL, CompareDefault<CRITSEC_COOKIE>> StressLogLockHolder;
+#endif //!STRESS_LOG_ANALYZER
+
+#if defined(DACCESS_COMPILE)
+inline BOOL StressLog::LogOn(unsigned facility, unsigned level)
+{
+    STATIC_CONTRACT_LEAF;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+
+    // StressLog isn't dacized, and besides we don't want to log to it in DAC builds.
+    return FALSE;
+}
+#endif
+
 /*************************************************************************************/
 /* private classes */
 
index 65cda94ed9900b43bb15d5ea5d723c925d7da90c..01b5c0dffe6fa62e69419cdfad7b9f8ca56a5ba8 100644 (file)
 // define this to test data safety for the DAC. See code:DataTest::TestDataSafety.
 #define TEST_DATA_CONSISTENCY
 
-#if !defined(STRESS_LOG) && !defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
-#define STRESS_LOG
-#endif
-
 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
 #define USE_CHECKED_OBJECTREFS
 #endif
 
 #define FEATURE_SHARE_GENERIC_CODE
 
-#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
-    #define LOGGING
-#endif
-
-#if !defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
-// Failpoint support
-#if defined(_DEBUG) && !defined(DACCESS_COMPILE) && !defined(TARGET_UNIX)
-#define FAILPOINTS_ENABLED
-#endif
-#endif //!defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
-
-#if 0
-    // Enable to track details of EESuspension
-    #define TIME_SUSPEND
-#endif // 0
-
 #ifndef DACCESS_COMPILE
 // Enabled to track GC statistics
 #define GC_STATS
index 04addc4f9ba31676521496acf88fc46fa3b6e044..7c359ef9790750776e471922ebb851dffce4ca46 100644 (file)
@@ -1,8 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
-
 //*****************************************************************************
-// UtilCode.h (dummy/empty file)
+// UtilCode.h
 //
 // Utility functions implemented in UtilCode.lib.
 //
 #ifndef __UtilCode_h__
 #define __UtilCode_h__
 
+#include "crtwrap.h"
+#include "winwrap.h"
+#include <wchar.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ole2.h>
+#include <oleauto.h>
+#include <limits.h>
+#include "clrtypes.h"
+#include "safewrap.h"
+#include "volatile.h"
+#include <daccess.h>
+#include "clrhost.h"
+#include "debugmacros.h"
+#include "corhlprpriv.h"
+#include "winnls.h"
+#include "check.h"
+#include "safemath.h"
+#include "new.hpp"
+
+#ifdef PAL_STDCPP_COMPAT
+#include <type_traits>
+#else
+#include "clr_std/type_traits"
+#endif
+
+#include "contract.h"
+#include "entrypoints.h"
+
 #include<minipal/utils.h>
 
+#include "clrnt.h"
+
+#include "random.h"
+
+#define WINDOWS_KERNEL32_DLLNAME_A "kernel32"
+#define WINDOWS_KERNEL32_DLLNAME_W W("kernel32")
+
+#define CoreLibName_W W("System.Private.CoreLib")
+#define CoreLibName_IL_W W("System.Private.CoreLib.dll")
+#define CoreLibName_NI_W W("System.Private.CoreLib.ni.dll")
+#define CoreLibName_TLB_W W("System.Private.CoreLib.tlb")
+#define CoreLibName_A "System.Private.CoreLib"
+#define CoreLibName_IL_A "System.Private.CoreLib.dll"
+#define CoreLibName_NI_A "System.Private.CoreLib.ni.dll"
+#define CoreLibName_TLB_A "System.Private.CoreLib.tlb"
+#define CoreLibNameLen 22
+#define CoreLibSatelliteName_A "System.Private.CoreLib.resources"
+#define CoreLibSatelliteNameLen 32
+#define LegacyCoreLibName_A "mscorlib"
+
+class StringArrayList;
+
+#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
+#define _DEBUG_IMPL 1
+#endif
+
+#ifdef TARGET_ARM
+
+// Under ARM we generate code only with Thumb encoding. In order to ensure we execute such code in the correct
+// mode we must ensure the low-order bit is set in any code address we'll call as a sub-routine. In C++ this
+// is handled automatically for us by the compiler. When generating and working with code generated
+// dynamically we have to be careful to set or mask-out this bit as appropriate.
+#ifndef THUMB_CODE
+#define THUMB_CODE 1
+#endif
+
+// Given a WORD extract the bitfield [lowbit, highbit] (i.e. BitExtract(0xffff, 15, 0) == 0xffff).
+inline WORD BitExtract(WORD wValue, DWORD highbit, DWORD lowbit)
+{
+    _ASSERTE((highbit < 16) && (lowbit < 16) && (highbit >= lowbit));
+    return (wValue >> lowbit) & ((1 << ((highbit - lowbit) + 1)) - 1);
+}
+
+// Determine whether an ARM Thumb mode instruction is 32-bit or 16-bit based on the first WORD of the
+// instruction.
+inline bool Is32BitInstruction(WORD opcode)
+{
+    return BitExtract(opcode, 15, 11) >= 0x1d;
+}
+
+template <typename ResultType, typename SourceType>
+inline ResultType DataPointerToThumbCode(SourceType pCode)
+{
+    return (ResultType)(((UINT_PTR)pCode) | THUMB_CODE);
+}
+
+template <typename ResultType, typename SourceType>
+inline ResultType ThumbCodeToDataPointer(SourceType pCode)
+{
+    return (ResultType)(((UINT_PTR)pCode) & ~THUMB_CODE);
+}
+
+#endif // TARGET_ARM
+
+// Convert from a PCODE to the corresponding PINSTR.  On many architectures this will be the identity function;
+// on ARM, this will mask off the THUMB bit.
+inline TADDR PCODEToPINSTR(PCODE pc)
+{
+#ifdef TARGET_ARM
+    return ThumbCodeToDataPointer<TADDR,PCODE>(pc);
+#else
+    return dac_cast<PCODE>(pc);
+#endif
+}
+
+// Convert from a PINSTR to the corresponding PCODE.  On many architectures this will be the identity function;
+// on ARM, this will raise the THUMB bit.
+inline PCODE PINSTRToPCODE(TADDR addr)
+{
+#ifdef TARGET_ARM
+    return DataPointerToThumbCode<PCODE,TADDR>(addr);
+#else
+    return dac_cast<PCODE>(addr);
+#endif
+}
+
+typedef LPCSTR  LPCUTF8;
+typedef LPSTR   LPUTF8;
+
+#include "nsutilpriv.h"
+
+#include "stdmacros.h"
+
+//********** Macros. **********************************************************
+#ifndef FORCEINLINE
+ #if _MSC_VER < 1200
+   #define FORCEINLINE inline
+ #else
+   #define FORCEINLINE __forceinline
+ #endif
+#endif
+
+#ifndef DEBUG_NOINLINE
+#if defined(_DEBUG)
+#define DEBUG_NOINLINE NOINLINE
+#else
+#define DEBUG_NOINLINE
+#endif
+#endif
+
+#include <stddef.h> // for offsetof
+#include <minipal/utils.h>
+
+#define IS_DIGIT(ch) (((ch) >= W('0')) && ((ch) <= W('9')))
+#define DIGIT_TO_INT(ch) ((ch) - W('0'))
+#define INT_TO_DIGIT(i) ((WCHAR)(W('0') + (i)))
+
+#define IS_HEXDIGIT(ch) ((((ch) >= W('a')) && ((ch) <= W('f'))) || \
+                         (((ch) >= W('A')) && ((ch) <= W('F'))))
+#define HEXDIGIT_TO_INT(ch) ((towlower(ch) - W('a')) + 10)
+#define INT_TO_HEXDIGIT(i) ((WCHAR)(W('a') + ((i) - 10)))
+
+
+// Helper will 4 byte align a value, rounding up.
+#define ALIGN4BYTE(val) (((val) + 3) & ~0x3)
+
+#ifdef  _DEBUG
+#define DEBUGARG(x)         , x
+#else
+#define DEBUGARG(x)
+#endif
+
+#ifndef sizeofmember
+// Returns the size of a class or struct member.
+#define sizeofmember(c,m) (sizeof(((c*)0)->m))
+#endif
+
+//=--------------------------------------------------------------------------=
+// Prefast helpers.
+//
+
+#include "safemath.h"
+
+
+//=--------------------------------------------------------------------------=
+// string helpers.
+
+//
+// given and ANSI String, copy it into a wide buffer.
+// be careful about scoping when using this macro!
+//
+// how to use the below two macros:
+//
+//  ...
+//  LPSTR pszA;
+//  pszA = MyGetAnsiStringRoutine();
+//  MAKE_WIDEPTR_FROMANSI(pwsz, pszA);
+//  MyUseWideStringRoutine(pwsz);
+//  ...
+//
+// similarily for MAKE_ANSIPTR_FROMWIDE.  note that the first param does not
+// have to be declared, and no clean up must be done.
+//
+
+// We'll define an upper limit that allows multiplication by 4 (the max
+// bytes/char in UTF-8) but still remains positive, and allows some room for pad.
+// Under normal circumstances, we should never get anywhere near this limit.
+#define MAKE_MAX_LENGTH 0x1fffff00
+
+#ifndef MAKE_TOOLONGACTION
+#define MAKE_TOOLONGACTION ThrowHR(COR_E_OVERFLOW)
+#endif
+
+#ifndef MAKE_TRANSLATIONFAILED
+#define MAKE_TRANSLATIONFAILED ThrowWin32(ERROR_NO_UNICODE_TRANSLATION)
+#endif
+
+// This version throws on conversion errors (ie, no best fit character
+// mapping to characters that look similar, and no use of the default char
+// ('?') when printing out unrepresentable characters.  Use this method for
+// most development in the EE, especially anything like metadata or class
+// names.  See the BESTFIT version if you're printing out info to the console.
+#define MAKE_MULTIBYTE_FROMWIDE(ptrname, widestr, codepage) \
+    int __l##ptrname = (int)wcslen(widestr);        \
+    if (__l##ptrname > MAKE_MAX_LENGTH)         \
+        MAKE_TOOLONGACTION;                     \
+    __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
+    CQuickBytes __CQuickBytes##ptrname; \
+    __CQuickBytes##ptrname.AllocThrows(__l##ptrname); \
+    BOOL __b##ptrname; \
+    DWORD __cBytes##ptrname = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, &__b##ptrname); \
+    if (__b##ptrname || (__cBytes##ptrname == 0 && (widestr[0] != W('\0')))) { \
+        MAKE_TRANSLATIONFAILED; \
+    } \
+    LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
+
+// This version does best fit character mapping and also allows the use
+// of the default char ('?') for any Unicode character that isn't
+// representable.  This is reasonable for writing to the console, but
+// shouldn't be used for most string conversions.
+#define MAKE_MULTIBYTE_FROMWIDE_BESTFIT(ptrname, widestr, codepage) \
+    int __l##ptrname = (int)wcslen(widestr);        \
+    if (__l##ptrname > MAKE_MAX_LENGTH)         \
+        MAKE_TOOLONGACTION;                     \
+    __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
+    CQuickBytes __CQuickBytes##ptrname; \
+    __CQuickBytes##ptrname.AllocThrows(__l##ptrname); \
+    DWORD __cBytes##ptrname = WszWideCharToMultiByte(codepage, 0, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, NULL); \
+    if (__cBytes##ptrname == 0 && __l##ptrname != 0) { \
+        MAKE_TRANSLATIONFAILED; \
+    } \
+    LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
+
+// Use for anything critical other than output to console, where weird
+// character mappings are unacceptable.
+#define MAKE_ANSIPTR_FROMWIDE(ptrname, widestr) MAKE_MULTIBYTE_FROMWIDE(ptrname, widestr, CP_ACP)
+
+// Use for output to the console.
+#define MAKE_ANSIPTR_FROMWIDE_BESTFIT(ptrname, widestr) MAKE_MULTIBYTE_FROMWIDE_BESTFIT(ptrname, widestr, CP_ACP)
+
+#define MAKE_WIDEPTR_FROMANSI(ptrname, ansistr) \
+    CQuickBytes __qb##ptrname; \
+    int __l##ptrname; \
+    __l##ptrname = WszMultiByteToWideChar(CP_ACP, 0, ansistr, -1, 0, 0); \
+    if (__l##ptrname > MAKE_MAX_LENGTH) \
+        MAKE_TOOLONGACTION; \
+    LPWSTR ptrname = (LPWSTR) __qb##ptrname.AllocThrows((__l##ptrname+1)*sizeof(WCHAR));  \
+    if (WszMultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, ansistr, -1, ptrname, __l##ptrname) == 0) { \
+        MAKE_TRANSLATIONFAILED; \
+    }
+
+#define MAKE_WIDEPTR_FROMANSI_NOTHROW(ptrname, ansistr) \
+    CQuickBytes __qb##ptrname; \
+    LPWSTR ptrname = 0; \
+    int __l##ptrname; \
+    __l##ptrname = WszMultiByteToWideChar(CP_ACP, 0, ansistr, -1, 0, 0); \
+    if (__l##ptrname <= MAKE_MAX_LENGTH) { \
+        ptrname = (LPWSTR) __qb##ptrname.AllocNoThrow((__l##ptrname+1)*sizeof(WCHAR));  \
+        if (ptrname) { \
+            if (WszMultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, ansistr, -1, ptrname, __l##ptrname) != 0) { \
+                ptrname[__l##ptrname] = 0; \
+            } else { \
+                ptrname = 0; \
+            } \
+        } \
+    }
+
+#define MAKE_UTF8PTR_FROMWIDE(ptrname, widestr) CQuickBytes _##ptrname; _##ptrname.ConvertUnicode_Utf8(widestr); LPSTR ptrname = (LPSTR) _##ptrname.Ptr();
+
+#define MAKE_UTF8PTR_FROMWIDE_NOTHROW(ptrname, widestr) \
+    CQuickBytes __qb##ptrname; \
+    int __l##ptrname = (int)wcslen(widestr); \
+    LPUTF8 ptrname = 0; \
+    if (__l##ptrname <= MAKE_MAX_LENGTH) { \
+        __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
+        ptrname = (LPUTF8) __qb##ptrname.AllocNoThrow(__l##ptrname); \
+    } \
+    if (ptrname) { \
+        INT32 __lresult##ptrname=WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, ptrname, __l##ptrname-1, NULL, NULL); \
+        DWORD __dwCaptureLastError##ptrname = ::GetLastError(); \
+        if ((__lresult##ptrname==0) && (((LPCWSTR)widestr)[0] != W('\0'))) { \
+            if (__dwCaptureLastError##ptrname==ERROR_INSUFFICIENT_BUFFER) { \
+                INT32 __lsize##ptrname=WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, NULL, 0, NULL, NULL); \
+                ptrname = (LPSTR) __qb##ptrname .AllocNoThrow(__lsize##ptrname); \
+                if (ptrname) { \
+                    if (WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, ptrname, __lsize##ptrname, NULL, NULL) != 0) { \
+                        ptrname[__l##ptrname] = 0; \
+                    } else { \
+                        ptrname = 0; \
+                    } \
+                } \
+            } \
+            else { \
+                ptrname = 0; \
+            } \
+        } \
+    } \
+
+#define MAKE_WIDEPTR_FROMUTF8N(ptrname, utf8str, n8chrs) \
+    CQuickBytes __qb##ptrname; \
+    int __l##ptrname; \
+    __l##ptrname = WszMultiByteToWideChar(CP_UTF8, 0, utf8str, n8chrs, 0, 0); \
+    if (__l##ptrname > MAKE_MAX_LENGTH) \
+        MAKE_TOOLONGACTION; \
+    LPWSTR ptrname = (LPWSTR) __qb##ptrname .AllocThrows((__l##ptrname+1)*sizeof(WCHAR)); \
+    if (0==WszMultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8str, n8chrs, ptrname, __l##ptrname)) { \
+        MAKE_TRANSLATIONFAILED; \
+    } \
+    ptrname[__l##ptrname] = 0;
+
+
+#define MAKE_WIDEPTR_FROMUTF8(ptrname, utf8str) CQuickBytes _##ptrname;  _##ptrname.ConvertUtf8_Unicode(utf8str); LPCWSTR ptrname = (LPCWSTR) _##ptrname.Ptr();
+
+
+#define MAKE_WIDEPTR_FROMUTF8N_NOTHROW(ptrname, utf8str, n8chrs) \
+    CQuickBytes __qb##ptrname; \
+    int __l##ptrname; \
+    LPWSTR ptrname = 0; \
+    __l##ptrname = WszMultiByteToWideChar(CP_UTF8, 0, utf8str, n8chrs, 0, 0); \
+    if (__l##ptrname <= MAKE_MAX_LENGTH) { \
+        ptrname = (LPWSTR) __qb##ptrname.AllocNoThrow((__l##ptrname+1)*sizeof(WCHAR));  \
+        if (ptrname) { \
+            if (WszMultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8str, n8chrs, ptrname, __l##ptrname) != 0) { \
+                ptrname[__l##ptrname] = 0; \
+            } else { \
+                ptrname = 0; \
+            } \
+        } \
+    }
+
+#define MAKE_WIDEPTR_FROMUTF8_NOTHROW(ptrname, utf8str)   MAKE_WIDEPTR_FROMUTF8N_NOTHROW(ptrname, utf8str, -1)
+
+// This method takes the number of characters
+#define MAKE_MULTIBYTE_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt, codepage)        \
+    CQuickBytes __qb##ptrname; \
+    int __l##ptrname; \
+    __l##ptrname = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, _nCharacters, NULL, 0, NULL, NULL);           \
+    if (__l##ptrname > MAKE_MAX_LENGTH) \
+        MAKE_TOOLONGACTION; \
+    ptrname = (LPUTF8) __qb##ptrname .AllocThrows(__l##ptrname+1); \
+    BOOL __b##ptrname; \
+    DWORD _pCnt = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, _nCharacters, ptrname, __l##ptrname, NULL, &__b##ptrname);  \
+    if (__b##ptrname || (_pCnt == 0 && _nCharacters > 0)) { \
+        MAKE_TRANSLATIONFAILED; \
+    } \
+    ptrname[__l##ptrname] = 0;
+
+#define MAKE_MULTIBYTE_FROMWIDEN_BESTFIT(ptrname, widestr, _nCharacters, _pCnt, codepage)        \
+    CQuickBytes __qb##ptrname; \
+    int __l##ptrname; \
+    __l##ptrname = WszWideCharToMultiByte(codepage, 0, widestr, _nCharacters, NULL, 0, NULL, NULL);           \
+    if (__l##ptrname > MAKE_MAX_LENGTH) \
+        MAKE_TOOLONGACTION; \
+    ptrname = (LPUTF8) __qb##ptrname .AllocThrows(__l##ptrname+1); \
+    DWORD _pCnt = WszWideCharToMultiByte(codepage, 0, widestr, _nCharacters, ptrname, __l##ptrname, NULL, NULL);  \
+    if (_pCnt == 0 && _nCharacters > 0) { \
+        MAKE_TRANSLATIONFAILED; \
+    } \
+    ptrname[__l##ptrname] = 0;
+
+#define MAKE_ANSIPTR_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt)        \
+       MAKE_MULTIBYTE_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt, CP_ACP)
+
+
+inline
+LPWSTR DuplicateString(
+    LPCWSTR wszString,
+    size_t  cchString)
+{
+    STATIC_CONTRACT_NOTHROW;
+
+    LPWSTR wszDup = NULL;
+    if (wszString != NULL)
+    {
+        wszDup = new (nothrow) WCHAR[cchString + 1];
+        if (wszDup != NULL)
+        {
+            wcscpy_s(wszDup, cchString + 1, wszString);
+        }
+    }
+    return wszDup;
+}
+
+inline
+LPWSTR DuplicateString(
+    LPCWSTR wszString)
+{
+    STATIC_CONTRACT_NOTHROW;
+
+    if (wszString != NULL)
+    {
+        return DuplicateString(wszString, wcslen(wszString));
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+void DECLSPEC_NORETURN ThrowOutOfMemory();
+
+inline
+LPWSTR DuplicateStringThrowing(
+    LPCWSTR wszString,
+    size_t cchString)
+{
+    STATIC_CONTRACT_THROWS;
+
+    if (wszString == NULL)
+        return NULL;
+
+    LPWSTR wszDup = DuplicateString(wszString, cchString);
+    if (wszDup == NULL)
+        ThrowOutOfMemory();
+
+    return wszDup;
+}
+
+inline
+LPWSTR DuplicateStringThrowing(
+    LPCWSTR wszString)
+{
+    STATIC_CONTRACT_THROWS;
+
+    if (wszString == NULL)
+        return NULL;
+
+    LPWSTR wszDup = DuplicateString(wszString);
+    if (wszDup == NULL)
+        ThrowOutOfMemory();
+
+    return wszDup;
+}
+
+
+//*****************************************************************************
+// Placement new is used to new and object at an exact location.  The pointer
+// is simply returned to the caller without actually using the heap.  The
+// advantage here is that you cause the ctor() code for the object to be run.
+// This is ideal for heaps of C++ objects that need to get init'd multiple times.
+// Example:
+//      void        *pMem = GetMemFromSomePlace();
+//      Foo *p = new (pMem) Foo;
+//      DoSomething(p);
+//      p->~Foo();
+//*****************************************************************************
+#ifndef __PLACEMENT_NEW_INLINE
+#define __PLACEMENT_NEW_INLINE
+inline void *__cdecl operator new(size_t, void *_P)
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return (_P);
+}
+#endif // __PLACEMENT_NEW_INLINE
+
+
+/********************************************************************************/
+/* portability helpers */
+
+#ifdef TARGET_64BIT
+#define IN_TARGET_64BIT(x)     x
+#define IN_TARGET_32BIT(x)
+#else
+#define IN_TARGET_64BIT(x)
+#define IN_TARGET_32BIT(x)     x
+#endif
+
+void * __cdecl
+operator new(size_t n);
+
+_Ret_bytecap_(n) void * __cdecl
+operator new[](size_t n);
+
+void __cdecl
+operator delete(void *p) NOEXCEPT;
+
+void __cdecl
+operator delete[](void *p) NOEXCEPT;
+
+#ifdef _DEBUG_IMPL
+HRESULT _OutOfMemory(LPCSTR szFile, int iLine);
+#define OutOfMemory() _OutOfMemory(__FILE__, __LINE__)
+#else
+inline HRESULT OutOfMemory()
+{
+    LIMITED_METHOD_CONTRACT;
+    return (E_OUTOFMEMORY);
+}
+#endif
+
+//*****************************************************************************
+// Handle accessing localizable resource strings
+//*****************************************************************************
+typedef LPCWSTR LocaleID;
+typedef WCHAR LocaleIDValue[LOCALE_NAME_MAX_LENGTH];
+
+// Notes about the culture callbacks:
+// - The language we're operating in can change at *runtime*!
+// - A process may operate in *multiple* languages.
+//     (ex: Each thread may have it's own language)
+// - If we don't care what language we're in (or have no way of knowing),
+//     then return a 0-length name and UICULTUREID_DONTCARE for the culture ID.
+// - GetCultureName() and the GetCultureId() must be in sync (refer to the
+//     same language).
+// - We have two functions separate functions for better performance.
+//     - The name is used to resolve a directory for MsCorRC.dll.
+//     - The id is used as a key to map to a dll hinstance.
+
+// Callback to obtain both the culture name and the culture's parent culture name
+typedef HRESULT (*FPGETTHREADUICULTURENAMES)(__inout StringArrayList* pCultureNames);
+const LPCWSTR UICULTUREID_DONTCARE = NULL;
+
+typedef int (*FPGETTHREADUICULTUREID)(LocaleIDValue*);
+
+HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName);
+
+HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
+
+BOOL CLRFreeLibrary(HMODULE hModule);
+
+// Load a string using the resources for the current module.
+STDAPI UtilLoadStringRC(UINT iResouceID, _Out_writes_ (iMax) LPWSTR szBuffer, int iMax, int bQuiet=FALSE);
+
+// Specify callbacks so that UtilLoadStringRC can find out which language we're in.
+// If no callbacks specified (or both parameters are NULL), we default to the
+// resource dll in the root (which is probably english).
+void SetResourceCultureCallbacks(
+    FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
+    FPGETTHREADUICULTUREID fpGetThreadUICultureId
+);
+
+void GetResourceCultureCallbacks(
+        FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
+        FPGETTHREADUICULTUREID* fpGetThreadUICultureId
+);
+
+//*****************************************************************************
+// Use this class by privately deriving from noncopyable to disallow copying of
+// your class.
+//*****************************************************************************
+class noncopyable
+{
+protected:
+    noncopyable()
+    {}
+    ~noncopyable()
+    {}
+
+private:
+    noncopyable(const noncopyable&);
+    const noncopyable& operator=(const noncopyable&);
+};
+
+//*****************************************************************************
+// Must associate each handle to an instance of a resource dll with the int
+// that it represents
+//*****************************************************************************
+typedef HINSTANCE HRESOURCEDLL;
+
+
+class CCulturedHInstance
+{
+    LocaleIDValue   m_LangId;
+    HRESOURCEDLL    m_hInst;
+    BOOL            m_fMissing;
+
+public:
+    CCulturedHInstance()
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_hInst = NULL;
+        m_fMissing = FALSE;
+    }
+
+    BOOL HasID(LocaleID id)
+    {
+        _ASSERTE(m_hInst != NULL || m_fMissing);
+        if (id == UICULTUREID_DONTCARE)
+            return FALSE;
+
+        return wcscmp(id, m_LangId) == 0;
+    }
+
+    HRESOURCEDLL GetLibraryHandle()
+    {
+        return m_hInst;
+    }
+
+    BOOL IsSet()
+    {
+        return m_hInst != NULL;
+    }
+
+    BOOL IsMissing()
+    {
+        return m_fMissing;
+    }
+
+    void SetMissing(LocaleID id)
+    {
+        _ASSERTE(m_hInst == NULL);
+        SetId(id);
+        m_fMissing = TRUE;
+    }
+
+    void Set(LocaleID id, HRESOURCEDLL hInst)
+    {
+        _ASSERTE(m_hInst == NULL);
+        _ASSERTE(m_fMissing == FALSE);
+        SetId(id);
+        m_hInst = hInst;
+    }
+  private:
+    void SetId(LocaleID id)
+    {
+        if (id != UICULTUREID_DONTCARE)
+        {
+            wcsncpy_s(m_LangId, ARRAY_SIZE(m_LangId), id, ARRAY_SIZE(m_LangId));
+            m_LangId[STRING_LENGTH(m_LangId)] = W('\0');
+        }
+        else
+        {
+            m_LangId[0] = W('\0');
+        }
+    }
+ };
+
+#ifndef DACCESS_COMPILE
+void AddThreadPreferredUILanguages(StringArrayList* pArray);
+#endif
+//*****************************************************************************
+// CCompRC manages string Resource access for COM+. This includes loading
+// the MsCorRC.dll for resources as well allowing each thread to use a
+// a different localized version.
+//*****************************************************************************
+class CCompRC
+{
+public:
+
+    enum ResourceCategory
+    {
+        // must be present
+        Required,
+
+        // present in Desktop CLR and Core CLR + debug pack, an error
+        // If missing, get a generic error message instead
+        Error,
+
+        // present in Desktop CLR and Core CLR + debug pack, normal operation (e.g tracing)
+        // if missing, get a generic "resource not found" message instead
+        Debugging,
+
+        // present in Desktop CLR, optional for CoreCLR
+        DesktopCLR,
+
+        // might not be present, non essential
+        Optional
+    };
+
+    CCompRC()
+    {
+        // This constructor will be fired up on startup. Make sure it doesn't
+        // do anything besides zero-out out values.
+        m_fpGetThreadUICultureId = NULL;
+        m_fpGetThreadUICultureNames = NULL;
+
+        m_pHash = NULL;
+        m_nHashSize = 0;
+        m_csMap = NULL;
+        m_pResourceFile = NULL;
+    }// CCompRC
+
+    HRESULT Init(LPCWSTR pResourceFile);
+    void Destroy();
+
+    HRESULT LoadString(ResourceCategory eCategory, UINT iResourceID, _Out_writes_ (iMax) LPWSTR szBuffer, int iMax , int *pcwchUsed=NULL);
+    HRESULT LoadString(ResourceCategory eCategory, LocaleID langId, UINT iResourceID, _Out_writes_ (iMax) LPWSTR szBuffer, int iMax, int *pcwchUsed);
+
+    void SetResourceCultureCallbacks(
+        FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
+        FPGETTHREADUICULTUREID fpGetThreadUICultureId
+    );
+
+    void GetResourceCultureCallbacks(
+        FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
+        FPGETTHREADUICULTUREID* fpGetThreadUICultureId
+    );
+
+    // Get the default resource location (mscorrc.dll)
+    static CCompRC* GetDefaultResourceDll();
+
+    static void GetDefaultCallbacks(
+                    FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
+                    FPGETTHREADUICULTUREID* fpGetThreadUICultureId)
+    {
+        WRAPPER_NO_CONTRACT;
+        m_DefaultResourceDll.GetResourceCultureCallbacks(
+                    fpGetThreadUICultureNames,
+                    fpGetThreadUICultureId);
+    }
+
+    static void SetDefaultCallbacks(
+                FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
+                FPGETTHREADUICULTUREID fpGetThreadUICultureId)
+    {
+        WRAPPER_NO_CONTRACT;
+        // Either both are NULL or neither are NULL
+        _ASSERTE((fpGetThreadUICultureNames != NULL) ==
+                 (fpGetThreadUICultureId != NULL));
+
+        m_DefaultResourceDll.SetResourceCultureCallbacks(
+                fpGetThreadUICultureNames,
+                fpGetThreadUICultureId);
+    }
+
+private:
+// String resouces packaged as PE files only exist on Windows
+#ifdef HOST_WINDOWS
+    HRESULT GetLibrary(LocaleID langId, HRESOURCEDLL* phInst);
+#ifndef DACCESS_COMPILE
+    HRESULT LoadLibraryHelper(HRESOURCEDLL *pHInst,
+                              SString& rcPath);
+    HRESULT LoadLibraryThrows(HRESOURCEDLL * pHInst);
+    HRESULT LoadLibrary(HRESOURCEDLL * pHInst);
+    HRESULT LoadResourceFile(HRESOURCEDLL * pHInst, LPCWSTR lpFileName);
+#endif // DACCESS_COMPILE
+#endif // HOST_WINDOWS
+
+    // We do not have global constructors any more
+    static LONG     m_dwDefaultInitialized;
+    static CCompRC  m_DefaultResourceDll;
+    static LPCWSTR  m_pDefaultResource;
+
+    // We must map between a thread's int and a dll instance.
+    // Since we only expect 1 language almost all of the time, we'll special case
+    // that and then use a variable size map for everything else.
+    CCulturedHInstance m_Primary;
+    CCulturedHInstance * m_pHash;
+    int m_nHashSize;
+
+    CRITSEC_COOKIE m_csMap;
+
+    LPCWSTR m_pResourceFile;
+
+    // Main accessors for hash
+    HRESOURCEDLL LookupNode(LocaleID langId, BOOL &fMissing);
+    HRESULT AddMapNode(LocaleID langId, HRESOURCEDLL hInst, BOOL fMissing = FALSE);
+
+    FPGETTHREADUICULTUREID m_fpGetThreadUICultureId;
+    FPGETTHREADUICULTURENAMES m_fpGetThreadUICultureNames;
+};
+
+HRESULT UtilLoadResourceString(CCompRC::ResourceCategory eCategory, UINT iResouceID, _Out_writes_ (iMax) LPWSTR szBuffer, int iMax);
+
+
+int UtilMessageBox(
+                  HWND hWnd,        // Handle to Owner Window
+                  UINT uText,       // Resource Identifier for Text message
+                  UINT uCaption,    // Resource Identifier for Caption
+                  UINT uType,       // Style of MessageBox
+                  BOOL displayForNonInteractive,    // Display even if the process is running non interactive
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  ...);             // Additional Arguments
+
+int UtilMessageBoxNonLocalized(
+                  HWND hWnd,        // Handle to Owner Window
+                  LPCWSTR lpText,    // Resource Identifier for Text message
+                  LPCWSTR lpTitle,   // Resource Identifier for Caption
+                  UINT uType,       // Style of MessageBox
+                  BOOL displayForNonInteractive,    // Display even if the process is running non interactive
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  ...);             // Additional Arguments
+
+int UtilMessageBoxVA(
+                  HWND hWnd,        // Handle to Owner Window
+                  UINT uText,       // Resource Identifier for Text message
+                  UINT uCaption,    // Resource Identifier for Caption
+                  UINT uType,       // Style of MessageBox
+                  BOOL displayForNonInteractive,    // Display even if the process is running non interactive
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  va_list args);    // Additional Arguments
+
+int UtilMessageBoxNonLocalizedVA(
+                  HWND hWnd,        // Handle to Owner Window
+                  LPCWSTR lpText,    // Text message
+                  LPCWSTR lpCaption, // Caption
+                  UINT uType,       // Style of MessageBox
+                  BOOL displayForNonInteractive,    // Display even if the process is running non interactive
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  BOOL * pInputFromUser,            // To distinguish between user pressing abort vs. assuming abort.
+                  va_list args);    // Additional Arguments
+
+int UtilMessageBoxNonLocalizedVA(
+                  HWND hWnd,        // Handle to Owner Window
+                  LPCWSTR lpText,    // Text message
+                  LPCWSTR lpCaption, // Caption
+                  LPCWSTR lpDetails, // Details that may be shown in a collapsed extended area of the dialog (Vista or higher).
+                  UINT uType,       // Style of MessageBox
+                  BOOL displayForNonInteractive,    // Display even if the process is running non interactive
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  BOOL * pInputFromUser,            // To distinguish between user pressing abort vs. assuming abort.
+                  va_list args);    // Additional Arguments
+
+int UtilMessageBoxCatastrophic(
+                  UINT uText,       // Text for MessageBox
+                  UINT uTitle,      // Title for MessageBox
+                  UINT uType,       // Style of MessageBox
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  ...);
+
+int UtilMessageBoxCatastrophicNonLocalized(
+                  LPCWSTR lpText,    // Text for MessageBox
+                  LPCWSTR lpTitle,   // Title for MessageBox
+                  UINT uType,       // Style of MessageBox
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  ...);
+
+int UtilMessageBoxCatastrophicVA(
+                  UINT uText,       // Text for MessageBox
+                  UINT uTitle,      // Title for MessageBox
+                  UINT uType,       // Style of MessageBox
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  va_list args);    // Additional Arguments
+
+int UtilMessageBoxCatastrophicNonLocalizedVA(
+                  LPCWSTR lpText,    // Text for MessageBox
+                  LPCWSTR lpTitle,   // Title for MessageBox
+                  UINT uType,       // Style of MessageBox
+                  BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+                  va_list args);    // Additional Arguments
+
+
+// The HRESULT_FROM_WIN32 macro evaluates its arguments three times.
+// <TODO>TODO: All HRESULT_FROM_WIN32(GetLastError()) should be replaced by calls to
+//  this helper function avoid code bloat</TODO>
+inline HRESULT HRESULT_FROM_GetLastError()
+{
+    WRAPPER_NO_CONTRACT;
+    DWORD dw = GetLastError();
+    // Make sure we return a failure
+    if (dw == ERROR_SUCCESS)
+    {
+        _ASSERTE(!"We were expecting to get an error code, but a success code is being returned. Check this code path for Everett!");
+        return E_FAIL;
+    }
+    else
+        return HRESULT_FROM_WIN32(dw);
+}
+
+inline HRESULT HRESULT_FROM_GetLastErrorNA()
+{
+    WRAPPER_NO_CONTRACT;
+    DWORD dw = GetLastError();
+    // Make sure we return a failure
+    if (dw == ERROR_SUCCESS)
+        return E_FAIL;
+    else
+        return HRESULT_FROM_WIN32(dw);
+}
+
+inline HRESULT BadError(HRESULT hr)
+{
+    LIMITED_METHOD_CONTRACT;
+    _ASSERTE(!"Serious Error");
+    return (hr);
+}
+
+#define TESTANDRETURN(test, hrVal)              \
+{                                               \
+    int ___test = (int)(test);                  \
+    if (! ___test)                              \
+        return hrVal;                           \
+}
+
+#define TESTANDRETURNPOINTER(pointer)           \
+    TESTANDRETURN((pointer)!=NULL, E_POINTER)
+
+#define TESTANDRETURNMEMORY(pointer)            \
+    TESTANDRETURN((pointer)!=NULL, E_OUTOFMEMORY)
+
+#define TESTANDRETURNHR(hr)                     \
+    TESTANDRETURN(SUCCEEDED(hr), hr)
+
+#define TESTANDRETURNARG(argtest)               \
+    TESTANDRETURN(argtest, E_INVALIDARG)
+
+// Quick validity check for HANDLEs that are returned by Win32 APIs that
+// use INVALID_HANDLE_VALUE instead of NULL to indicate an error
+inline BOOL IsValidHandle(HANDLE h)
+{
+    LIMITED_METHOD_CONTRACT;
+    return ((h != NULL) && (h != INVALID_HANDLE_VALUE));
+}
+
+// Count the bits in a value in order iBits time.
+inline int CountBits(int iNum)
+{
+    LIMITED_METHOD_CONTRACT;
+    int iBits;
+    for (iBits=0;  iNum;  iBits++)
+        iNum = iNum & (iNum - 1);
+    return (iBits);
+}
+
+//*****************************************************************************
+//
+// Paths functions. Use these instead of the CRT.
+//
+//*****************************************************************************
+// secure version! Specify the size of the each buffer in count of elements
+void    SplitPath(const WCHAR *path,
+                  __inout_z __inout_ecount_opt(driveSizeInWords) WCHAR *drive, int driveSizeInWords,
+                  __inout_z __inout_ecount_opt(dirSizeInWords) WCHAR *dir, int dirSizeInWords,
+                  __inout_z __inout_ecount_opt(fnameSizeInWords) WCHAR *fname, size_t fnameSizeInWords,
+                  __inout_z __inout_ecount_opt(extSizeInWords) WCHAR *ext, size_t extSizeInWords);
+
+//*******************************************************************************
+// A much more sensible version that just points to each section of the string.
+//*******************************************************************************
+void    SplitPathInterior(
+    _In_      LPCWSTR wszPath,
+    _Out_opt_ LPCWSTR *pwszDrive,    _Out_opt_ size_t *pcchDrive,
+    _Out_opt_ LPCWSTR *pwszDir,      _Out_opt_ size_t *pcchDir,
+    _Out_opt_ LPCWSTR *pwszFileName, _Out_opt_ size_t *pcchFileName,
+    _Out_opt_ LPCWSTR *pwszExt,      _Out_opt_ size_t *pcchExt);
+
+
+void    MakePath(_Out_ CQuickWSTR &path,
+                 _In_ LPCWSTR drive,
+                 _In_ LPCWSTR dir,
+                 _In_ LPCWSTR fname,
+                 _In_ LPCWSTR ext);
+
+WCHAR * FullPath(_Out_writes_ (maxlen) WCHAR *UserBuf, const WCHAR *path, size_t maxlen);
+
+//*****************************************************************************
+//
+// SString version of the path functions.
+//
+//*****************************************************************************
+void    SplitPath(_In_ SString const &path,
+                  __inout_opt SString *drive,
+                  __inout_opt SString *dir,
+                  __inout_opt SString *fname,
+                  __inout_opt SString *ext);
+
+#include "ostype.h"
+
+#define CLRGetTickCount64() GetTickCount64()
+
+//
+// Allocate free memory within the range [pMinAddr..pMaxAddr] using
+// ClrVirtualQuery to find free memory and ClrVirtualAlloc to allocate it.
+//
+BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr,
+                                   const BYTE *pMaxAddr,
+                                   SIZE_T dwSize,
+                                   DWORD flAllocationType,
+                                   DWORD flProtect);
+
+//
+// Allocate free memory with specific alignment
+//
+LPVOID ClrVirtualAllocAligned(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, SIZE_T alignment);
+
+class NumaNodeInfo
+{
+private:
+    static BOOL m_enableGCNumaAware;
+    static uint16_t m_nNodes;
+    static BOOL InitNumaNodeInfoAPI();
+
+public:
+    static BOOL CanEnableGCNumaAware();
+    static void InitNumaNodeInfo();
+
+#if !defined(FEATURE_REDHAWK)
+public:        // functions
+
+    static LPVOID VirtualAllocExNuma(HANDLE hProc, LPVOID lpAddr, SIZE_T size,
+                                     DWORD allocType, DWORD prot, DWORD node);
+#ifdef HOST_WINDOWS
+    static BOOL GetNumaProcessorNodeEx(PPROCESSOR_NUMBER proc_no, PUSHORT node_no);
+    static bool GetNumaInfo(PUSHORT total_nodes, DWORD* max_procs_per_node);
+#else // HOST_WINDOWS
+    static BOOL GetNumaProcessorNodeEx(USHORT proc_no, PUSHORT node_no);
+#endif // HOST_WINDOWS
+#endif
+};
+
+#ifdef HOST_WINDOWS
+
+struct CPU_Group_Info
+{
+    WORD       nr_active;      // at most 64
+    WORD       reserved[1];
+    WORD       begin;
+    WORD       end;
+    DWORD_PTR  active_mask;
+    DWORD      groupWeight;
+    DWORD      activeThreadWeight;
+};
+
+class CPUGroupInfo
+{
+private:
+    static LONG m_initialization;
+    static WORD m_nGroups;
+    static WORD m_nProcessors;
+    static BOOL m_enableGCCPUGroups;
+    static BOOL m_threadUseAllCpuGroups;
+    static BOOL m_threadAssignCpuGroups;
+    static WORD m_initialGroup;
+    static CPU_Group_Info *m_CPUGroupInfoArray;
+
+    static BOOL InitCPUGroupInfoArray();
+    static BOOL InitCPUGroupInfoRange();
+    static void InitCPUGroupInfo();
+    static BOOL IsInitialized();
+
+public:
+    static void EnsureInitialized();
+    static BOOL CanEnableGCCPUGroups();
+    static BOOL CanEnableThreadUseAllCpuGroups();
+    static BOOL CanAssignCpuGroupsToThreads();
+    static WORD GetNumActiveProcessors();
+    static void GetGroupForProcessor(WORD processor_number,
+                   WORD *group_number, WORD *group_processor_number);
+    static DWORD CalculateCurrentProcessorNumber();
+    static bool GetCPUGroupInfo(PUSHORT total_groups, DWORD* max_procs_per_group);
+    //static void PopulateCPUUsageArray(void * infoBuffer, ULONG infoSize);
+
+#if !defined(FEATURE_REDHAWK)
+public:
+    static BOOL GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP relationship,
+                  SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *slpiex, PDWORD count);
+    static BOOL SetThreadGroupAffinity(HANDLE h,
+                   const GROUP_AFFINITY *groupAffinity, GROUP_AFFINITY *previousGroupAffinity);
+    static BOOL GetThreadGroupAffinity(HANDLE h, GROUP_AFFINITY *groupAffinity);
+    static BOOL GetSystemTimes(FILETIME *idleTime, FILETIME *kernelTime, FILETIME *userTime);
+    static void ChooseCPUGroupAffinity(GROUP_AFFINITY *gf);
+    static void ClearCPUGroupAffinity(GROUP_AFFINITY *gf);
+    static BOOL GetCPUGroupRange(WORD group_number, WORD* group_begin, WORD* group_size);
+#endif
+};
+
+DWORD_PTR GetCurrentProcessCpuMask();
+
+#endif // HOST_WINDOWS
+
+int GetTotalProcessorCount();
+
+//******************************************************************************
+// Returns the number of processors that a process has been configured to run on
+//******************************************************************************
+int GetCurrentProcessCpuCount();
+
+uint32_t GetOsPageSize();
+
+
+//*****************************************************************************
+// Return != 0 if the bit at the specified index in the array is on and 0 if
+// it is off.
+//*****************************************************************************
+inline int GetBit(PTR_BYTE pcBits,int iBit)
+{
+    LIMITED_METHOD_CONTRACT;
+    return (pcBits[iBit>>3] & (1 << (iBit & 0x7)));
+}
+
+#ifdef DACCESS_COMPILE
+inline int GetBit(BYTE const * pcBits,int iBit)
+{
+    WRAPPER_NO_CONTRACT;
+    return GetBit(dac_cast<PTR_BYTE>(pcBits), iBit);
+}
+#endif
+
+//*****************************************************************************
+// Set the state of the bit at the specified index based on the value of bOn.
+//*****************************************************************************
+inline void SetBit(PTR_BYTE pcBits,int iBit,int bOn)
+{
+    LIMITED_METHOD_CONTRACT;
+    if (bOn)
+        pcBits[iBit>>3] |= (1 << (iBit & 0x7));
+    else
+        pcBits[iBit>>3] &= ~(1 << (iBit & 0x7));
+}
+
+#ifdef DACCESS_COMPILE
+inline void SetBit(BYTE * pcBits,int iBit,int bOn)
+{
+    WRAPPER_NO_CONTRACT;
+    SetBit(dac_cast<PTR_BYTE>(pcBits), iBit, bOn);
+}
+#endif
+
+template<typename T>
+class SimpleListNode
+{
+public:
+    SimpleListNode<T>(const T& _t)
+    {
+        data = _t;
+        next = 0;
+    }
+
+    T                  data;
+    SimpleListNode<T>* next;
+};
+
+template<typename T>
+class SimpleList
+{
+public:
+    typedef SimpleListNode<T> NodeType;
+
+    SimpleList<T>()
+    {
+        head = NULL;
+    }
+
+    void LinkHead(NodeType* pNode)
+    {
+        pNode->next = head;
+                      head = pNode;
+    }
+
+    NodeType* UnlinkHead()
+    {
+        NodeType* ret = head;
+
+        if (head)
+        {
+            head = head->next;
+        }
+        return ret;
+    }
+
+    NodeType* Head()
+    {
+        return head;
+    }
+
+protected:
+
+    NodeType* head;
+};
+
+
+template < typename T, typename U >
+struct Pair
+{
+public:
+    typedef Pair< T, U > this_type;
+    typedef T first_type;
+    typedef U second_type;
+
+    Pair()
+    {}
+
+    Pair( T const & t, U const & u )
+        : m_first( t )
+        , m_second( u )
+    { SUPPORTS_DAC; }
+
+    Pair( this_type const & obj )
+        : m_first( obj.m_first )
+        , m_second( obj.m_second )
+    {}
+
+    this_type & operator=( this_type const & obj )
+    {
+        m_first = obj.m_first;
+        m_second = obj.m_second;
+        return *this;
+    }
+
+    T & First()
+    {
+        return m_first;
+    }
+
+    T const & First() const
+    {
+        return m_first;
+    }
+
+    U & Second()
+    {
+        return m_second;
+    }
+
+    U const & Second() const
+    {
+        return m_second;
+    }
+
+    bool operator==(const Pair& rhs) const
+    {
+        return ((this->First()  == rhs.First()) &&
+                (this->Second() == rhs.Second()));
+    }
+
+    bool operator!=(const Pair& rhs) const
+    {
+        return !(*this == rhs);
+    }
+
+private:
+    first_type  m_first;
+    second_type m_second;
+};
+
+
+template < typename T, typename U >
+Pair< T, U > MakePair( T const & t, U const & u )
+{
+    SUPPORTS_DAC;
+    return Pair< T, U >( t, u );
+}
+
+
+//*****************************************************************************
+// This class implements a dynamic array of structures for which the order of
+// the elements is unimportant.  This means that any item placed in the list
+// may be swapped to any other location in the list at any time.  If the order
+// of the items you place in the array is important, then use the CStructArray
+// class.
+//*****************************************************************************
+
+template <class T,
+          int iGrowInc,
+          class ALLOCATOR>
+class CUnorderedArrayWithAllocator
+{
+    int         m_iCount;               // # of elements used in the list.
+    int         m_iSize;                // # of elements allocated in the list.
+public:
+#ifndef DACCESS_COMPILE
+    T           *m_pTable;              // Pointer to the list of elements.
+#else
+    TADDR        m_pTable;              // Pointer to the list of elements.
+#endif
+
+public:
+
+#ifndef DACCESS_COMPILE
+
+    CUnorderedArrayWithAllocator() :
+        m_iCount(0),
+        m_iSize(0),
+        m_pTable(NULL)
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+    ~CUnorderedArrayWithAllocator()
+    {
+        LIMITED_METHOD_CONTRACT;
+        // Free the chunk of memory.
+        if (m_pTable != NULL)
+            ALLOCATOR::Free(this, m_pTable);
+    }
+
+    void Clear()
+    {
+        WRAPPER_NO_CONTRACT;
+        m_iCount = 0;
+        if (m_iSize > iGrowInc)
+        {
+            T* tmp = ALLOCATOR::AllocNoThrow(this, iGrowInc);
+            if (tmp) {
+                ALLOCATOR::Free(this, m_pTable);
+                m_pTable = tmp;
+                m_iSize = iGrowInc;
+            }
+        }
+    }
+
+    void Clear(int iFirst, int iCount)
+    {
+        WRAPPER_NO_CONTRACT;
+        int     iSize;
+
+        if (iFirst + iCount < m_iCount)
+            memmove(&m_pTable[iFirst], &m_pTable[iFirst + iCount], sizeof(T) * (m_iCount - (iFirst + iCount)));
+
+        m_iCount -= iCount;
+
+        iSize = ((m_iCount / iGrowInc) * iGrowInc) + ((m_iCount % iGrowInc != 0) ? iGrowInc : 0);
+        if (m_iSize > iGrowInc && iSize < m_iSize)
+        {
+            T *tmp = ALLOCATOR::AllocNoThrow(this, iSize);
+            if (tmp) {
+                memcpy (tmp, m_pTable, iSize * sizeof(T));
+                delete [] m_pTable;
+                m_pTable = tmp;
+                m_iSize = iSize;
+            }
+        }
+        _ASSERTE(m_iCount <= m_iSize);
+    }
+
+    T *Table()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_pTable);
+    }
+
+    T *Append()
+    {
+        CONTRACTL {
+            NOTHROW;
+        } CONTRACTL_END;
+
+        // The array should grow, if we can't fit one more element into the array.
+        if (m_iSize <= m_iCount && GrowNoThrow() == NULL)
+            return (NULL);
+        return (&m_pTable[m_iCount++]);
+    }
+
+    T *AppendThrowing()
+    {
+        CONTRACTL {
+            THROWS;
+        } CONTRACTL_END;
+
+        // The array should grow, if we can't fit one more element into the array.
+        if (m_iSize <= m_iCount)
+            Grow();
+        return (&m_pTable[m_iCount++]);
+    }
+
+    void Delete(const T &Entry)
+    {
+        LIMITED_METHOD_CONTRACT;
+        --m_iCount;
+        for (int i=0; i <= m_iCount; ++i)
+            if (m_pTable[i] == Entry)
+            {
+                m_pTable[i] = m_pTable[m_iCount];
+                return;
+            }
+
+        // Just in case we didn't find it.
+        ++m_iCount;
+    }
+
+    void DeleteByIndex(int i)
+    {
+        LIMITED_METHOD_CONTRACT;
+        --m_iCount;
+        m_pTable[i] = m_pTable[m_iCount];
+    }
+
+    void Swap(int i,int j)
+    {
+        LIMITED_METHOD_CONTRACT;
+        T       tmp;
+
+        if (i == j)
+            return;
+        tmp = m_pTable[i];
+        m_pTable[i] = m_pTable[j];
+        m_pTable[j] = tmp;
+    }
+
+#else
+
+    TADDR Table()
+    {
+        LIMITED_METHOD_CONTRACT;
+        SUPPORTS_DAC;
+        return (m_pTable);
+    }
+
+    void EnumMemoryRegions(void)
+    {
+        SUPPORTS_DAC;
+        DacEnumMemoryRegion(m_pTable, m_iCount * sizeof(T));
+    }
+
+#endif // #ifndef DACCESS_COMPILE
+
+    USHORT Count()
+    {
+        LIMITED_METHOD_CONTRACT;
+        SUPPORTS_DAC;
+        _ASSERTE(FitsIn<USHORT>(m_iCount));
+        return static_cast<USHORT>(m_iCount);
+    }
+
+private:
+    T *Grow();
+    T *GrowNoThrow();
+};
+
+
+#ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// Increase the size of the array.
+//*****************************************************************************
+template <class T,
+          int iGrowInc,
+          class ALLOCATOR>
+T *CUnorderedArrayWithAllocator<T,iGrowInc,ALLOCATOR>::GrowNoThrow()  // NULL if can't grow.
+{
+    WRAPPER_NO_CONTRACT;
+    T       *pTemp;
+
+    // try to allocate memory for reallocation.
+    if ((pTemp = ALLOCATOR::AllocNoThrow(this, m_iSize+iGrowInc)) == NULL)
+        return (NULL);
+    memcpy (pTemp, m_pTable, m_iSize*sizeof(T));
+    ALLOCATOR::Free(this, m_pTable);
+    m_pTable = pTemp;
+    m_iSize += iGrowInc;
+    _ASSERTE(m_iSize > 0);
+    return (pTemp);
+}
+
+template <class T,
+          int iGrowInc,
+          class ALLOCATOR>
+T *CUnorderedArrayWithAllocator<T,iGrowInc,ALLOCATOR>::Grow()  // exception if can't grow.
+{
+    WRAPPER_NO_CONTRACT;
+    T       *pTemp;
+
+    // try to allocate memory for reallocation.
+    pTemp = ALLOCATOR::AllocThrowing(this, m_iSize+iGrowInc);
+    memcpy (pTemp, m_pTable, m_iSize*sizeof(T));
+    ALLOCATOR::Free(this, m_pTable);
+    m_pTable = pTemp;
+    m_iSize += iGrowInc;
+    _ASSERTE(m_iSize > 0);
+    return (pTemp);
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+
+template <class T>
+class CUnorderedArray__Allocator
+{
+public:
+
+    static T *AllocThrowing (void*, int nElements)
+    {
+        return new T[nElements];
+    }
+
+    static T *AllocNoThrow (void*, int nElements)
+    {
+        return new (nothrow) T[nElements];
+    }
+
+    static void Free (void*, T *pTable)
+    {
+        delete [] pTable;
+    }
+};
+
+
+template <class T,int iGrowInc>
+class CUnorderedArray : public CUnorderedArrayWithAllocator<T, iGrowInc, CUnorderedArray__Allocator<T> >
+{
+public:
+
+    CUnorderedArray ()
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+};
+
+
+//Used by the debugger.  Included here in hopes somebody else might, too
+typedef CUnorderedArray<SIZE_T, 17> SIZE_T_UNORDERED_ARRAY;
+
+
+//*****************************************************************************
+// This class implements a dynamic array of structures for which the insert
+// order is important.  Inserts will slide all elements after the location
+// down, deletes slide all values over the deleted item.  If the order of the
+// items in the array is unimportant to you, then CUnorderedArray may provide
+// the same feature set at lower cost.
+//*****************************************************************************
+class CStructArray
+{
+    BYTE        *m_pList;               // Pointer to the list of elements.
+    int         m_iCount;               // # of elements used in the list.
+    int         m_iSize;                // # of elements allocated in the list.
+    int         m_iGrowInc;             // Growth increment.
+    short       m_iElemSize;            // Size of an array element.
+    bool        m_bFree;                // true if data is automatically maintained.
+
+public:
+    CStructArray(short iElemSize, short iGrowInc = 1) :
+        m_pList(NULL),
+        m_iCount(0),
+        m_iSize(0),
+        m_iGrowInc(iGrowInc),
+        m_iElemSize(iElemSize),
+        m_bFree(true)
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+    ~CStructArray()
+    {
+        WRAPPER_NO_CONTRACT;
+        Clear();
+    }
+
+    void *Insert(int iIndex);
+    void *InsertThrowing(int iIndex);
+    void *Append();
+    void *AppendThrowing();
+    int AllocateBlock(int iCount);
+    void AllocateBlockThrowing(int iCount);
+    void Delete(int iIndex);
+    void *Ptr()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_pList);
+    }
+    void *Get(int iIndex)
+    {
+        WRAPPER_NO_CONTRACT;
+        _ASSERTE(iIndex < m_iCount);
+        return (BYTE*) Ptr() + (iIndex * (size_t)m_iElemSize);
+    }
+    size_t Size()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_iCount * (size_t)m_iElemSize);
+    }
+    int Count()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_iCount);
+    }
+    void Clear();
+    void ClearCount()
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_iCount = 0;
+    }
+
+    void InitOnMem(short iElemSize, void *pList, int iCount, int iSize, int iGrowInc=1)
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_iElemSize = iElemSize;
+        m_iGrowInc = (short) iGrowInc;
+        m_pList = (BYTE*)pList;
+        m_iCount = iCount;
+        m_iSize = iSize;
+        m_bFree = false;
+    }
+
+private:
+    void Grow(int iCount);
+};
+
+
+//*****************************************************************************
+// This template simplifies access to a CStructArray by removing void * and
+// adding some operator overloads.
+//*****************************************************************************
+template <class T>
+class CDynArray : public CStructArray
+{
+public:
+    CDynArray(short iGrowInc=16) :
+        CStructArray(sizeof(T), iGrowInc)
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+
+    T *Insert(int iIndex)
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *)CStructArray::Insert((int)iIndex));
+    }
+
+    T *InsertThrowing(int iIndex)
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *)CStructArray::InsertThrowing((int)iIndex));
+    }
+
+    T *Append()
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *)CStructArray::Append());
+    }
+
+    T *AppendThrowing()
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *)CStructArray::AppendThrowing());
+    }
+
+    T *Ptr()
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *)CStructArray::Ptr());
+    }
+
+    T *Get(int iIndex)
+    {
+        WRAPPER_NO_CONTRACT;
+        return (Ptr() + iIndex);
+    }
+    T &operator[](int iIndex)
+    {
+        WRAPPER_NO_CONTRACT;
+        return (*(Ptr() + iIndex));
+    }
+    int ItemIndex(T *p)
+    {
+        WRAPPER_NO_CONTRACT;
+        return (((int)(LONG_PTR)p - (int)(LONG_PTR)Ptr()) / sizeof(T));
+    }
+    void Move(int iFrom, int iTo)
+    {
+        WRAPPER_NO_CONTRACT;
+        T       tmp;
+
+        _ASSERTE(iFrom >= 0 && iFrom < Count() &&
+                 iTo >= 0 && iTo < Count());
+
+        tmp = *(Ptr() + iFrom);
+        if (iTo > iFrom)
+            memmove(Ptr() + iFrom, Ptr() + iFrom + 1, (iTo - iFrom) * sizeof(T));
+        else
+            memmove(Ptr() + iTo + 1, Ptr() + iTo, (iFrom - iTo) * sizeof(T));
+        *(Ptr() + iTo) = tmp;
+    }
+};
+
+// Some common arrays.
+typedef CDynArray<int> INTARRAY;
+typedef CDynArray<short> SHORTARRAY;
+typedef CDynArray<int> LONGARRAY;
+typedef CDynArray<USHORT> USHORTARRAY;
+typedef CDynArray<ULONG> ULONGARRAY;
+typedef CDynArray<BYTE> BYTEARRAY;
+typedef CDynArray<mdToken> TOKENARRAY;
+
+template <class T> class CStackArray : public CStructArray
+{
+public:
+    CStackArray(short iGrowInc=4) :
+        CStructArray(sizeof(T), iGrowInc),
+        m_curPos(0)
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+
+    void Push(T p)
+    {
+        WRAPPER_NO_CONTRACT;
+        // We should only inc m_curPos after we grow the array.
+        T *pT = (T *)CStructArray::InsertThrowing(m_curPos);
+        m_curPos ++;
+        *pT = p;
+    }
+
+    T * Pop()
+    {
+        WRAPPER_NO_CONTRACT;
+        T * retPtr;
+
+        _ASSERTE(m_curPos > 0);
+
+        retPtr = (T *)CStructArray::Get(m_curPos-1);
+        CStructArray::Delete(m_curPos--);
+
+        return (retPtr);
+    }
+
+    int Count()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return(m_curPos);
+    }
+
+private:
+    int m_curPos;
+};
+
+
+//*****************************************************************************
+// This template manages a list of free entries by their 0 based offset.  By
+// making it a template, you can use whatever size free chain will match your
+// maximum count of items.  -1 is reserved.
+//*****************************************************************************
+template <class T> class TFreeList
+{
+public:
+    void Init(
+        T           *rgList,
+        int         iCount)
+    {
+        LIMITED_METHOD_CONTRACT;
+        // Save off values.
+        m_rgList = rgList;
+        m_iCount = iCount;
+        m_iNext = 0;
+
+        // Init free list.
+        int i;
+        for (i=0;  i<iCount - 1;  i++)
+            m_rgList[i] = i + 1;
+        m_rgList[i] = (T) -1;
+    }
+
+    T GetFreeEntry()                        // Index of free item, or -1.
+    {
+        LIMITED_METHOD_CONTRACT;
+        T           iNext;
+
+        if (m_iNext == (T) -1)
+            return (-1);
+
+        iNext = m_iNext;
+        m_iNext = m_rgList[m_iNext];
+        return (iNext);
+    }
+
+    void DelFreeEntry(T iEntry)
+    {
+        LIMITED_METHOD_CONTRACT;
+        _ASSERTE(iEntry < m_iCount);
+        m_rgList[iEntry] = m_iNext;
+        m_iNext = iEntry;
+    }
+
+    // This function can only be used when it is guaranteed that the free
+    // array is contigous, for example, right after creation to quickly
+    // get a range of items from the heap.
+    void ReserveRange(int iCount)
+    {
+        LIMITED_METHOD_CONTRACT;
+        _ASSERTE(iCount < m_iCount);
+        _ASSERTE(m_iNext == 0);
+        m_iNext = iCount;
+    }
+
+private:
+    T           *m_rgList;              // List of free info.
+    int         m_iCount;               // How many entries to manage.
+    T           m_iNext;                // Next item to get.
+};
+
+
+//*****************************************************************************
+//*****************************************************************************
+template <class T> class CQuickSort
+{
+protected:
+    T           *m_pBase;                   // Base of array to sort.
+private:
+    SSIZE_T     m_iCount;                   // How many items in array.
+    SSIZE_T     m_iElemSize;                // Size of one element.
+public:
+    CQuickSort(
+        T           *pBase,                 // Address of first element.
+        SSIZE_T     iCount) :               // How many there are.
+        m_pBase(pBase),
+        m_iCount(iCount),
+        m_iElemSize(sizeof(T))
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+    }
+
+//*****************************************************************************
+// Call to sort the array.
+//*****************************************************************************
+    inline void Sort()
+    {
+        WRAPPER_NO_CONTRACT;
+        SortRange(0, m_iCount - 1);
+    }
+
+protected:
+//*****************************************************************************
+// Override this function to do the comparison.
+//*****************************************************************************
+    virtual FORCEINLINE int Compare(        // -1, 0, or 1
+        T           *psFirst,               // First item to compare.
+        T           *psSecond)              // Second item to compare.
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+        return (memcmp(psFirst, psSecond, sizeof(T)));
+//      return (::Compare(*psFirst, *psSecond));
+    }
+
+    virtual FORCEINLINE void Swap(
+        SSIZE_T     iFirst,
+        SSIZE_T     iSecond)
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+        if (iFirst == iSecond) return;
+        T sTemp( m_pBase[iFirst] );
+        m_pBase[iFirst] = m_pBase[iSecond];
+        m_pBase[iSecond] = sTemp;
+    }
+
+private:
+    inline void SortRange(
+        SSIZE_T     iLeft,
+        SSIZE_T     iRight)
+    {
+        WRAPPER_NO_CONTRACT;
+        SSIZE_T     iLast;
+        SSIZE_T     i;                      // loop variable.
+
+        for (;;)
+        {
+            // if less than two elements you're done.
+            if (iLeft >= iRight)
+                return;
+
+            // ASSERT that we now have valid indicies.  This is statically provable
+            // since this private function is only called with valid indicies,
+            // and iLeft and iRight only converge towards eachother.  However,
+            // PreFast can't detect this because it doesn't know about our callers.
+            COMPILER_ASSUME(iLeft >= 0 && iLeft < m_iCount);
+            COMPILER_ASSUME(iRight >= 0 && iRight < m_iCount);
+
+            // The mid-element is the pivot, move it to the left.
+            Swap(iLeft, (iLeft + iRight) / 2);
+            iLast = iLeft;
+
+            // move everything that is smaller than the pivot to the left.
+            for (i = iLeft + 1; i <= iRight; i++)
+            {
+                if (Compare(&m_pBase[i], &m_pBase[iLeft]) < 0)
+                {
+                    Swap(i, ++iLast);
+                }
+            }
+
+            // Put the pivot to the point where it is in between smaller and larger elements.
+            Swap(iLeft, iLast);
+
+            // Sort each partition.
+            SSIZE_T iLeftLast = iLast - 1;
+            SSIZE_T iRightFirst = iLast + 1;
+            if (iLeftLast - iLeft < iRight - iRightFirst)
+            {   // Left partition is smaller, sort it recursively
+                SortRange(iLeft, iLeftLast);
+                // Tail call to sort the right (bigger) partition
+                iLeft = iRightFirst;
+                //iRight = iRight;
+                continue;
+            }
+            else
+            {   // Right partition is smaller, sort it recursively
+                SortRange(iRightFirst, iRight);
+                // Tail call to sort the left (bigger) partition
+                //iLeft = iLeft;
+                iRight = iLeftLast;
+                continue;
+            }
+        }
+    }
+};
+
+//*****************************************************************************
+// Faster and simpler version of the binary search below.
+//*****************************************************************************
+template <class T>
+const T * BinarySearch(const T * pBase, int iCount, const T & find)
+{
+    WRAPPER_NO_CONTRACT;
+
+    int iFirst = 0;
+    int iLast  = iCount - 1;
+
+    // It is faster to use linear search once we get down to a small number of elements.
+    while (iLast - iFirst > 10)
+    {
+        int iMid = (iLast + iFirst) / 2;
+
+        if (find < pBase[iMid])
+            iLast = iMid - 1;
+        else
+            iFirst = iMid;
+    }
+
+    for (int i = iFirst; i <= iLast; i++)
+    {
+        if (find == pBase[i])
+            return &pBase[i];
+
+        if (find < pBase[i])
+            break;
+    }
+
+    return NULL;
+}
+
+//*****************************************************************************
+// This template encapsulates a binary search algorithm on the given type
+// of data.
+//*****************************************************************************
+template <class T> class CBinarySearch
+{
+private:
+    const T     *m_pBase;                   // Base of array to sort.
+    int         m_iCount;                   // How many items in array.
+
+public:
+    CBinarySearch(
+        const T     *pBase,                 // Address of first element.
+        int         iCount) :               // Value to find.
+        m_pBase(pBase),
+        m_iCount(iCount)
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+
+//*****************************************************************************
+// Searches for the item passed to ctor.
+//*****************************************************************************
+    const T *Find(                          // Pointer to found item in array.
+        const T     *psFind,                // The key to find.
+        int         *piInsert = NULL)       // Index to insert at.
+    {
+        WRAPPER_NO_CONTRACT;
+        int         iMid, iFirst, iLast;    // Loop control.
+        int         iCmp;                   // Comparison.
+
+        iFirst = 0;
+        iLast = m_iCount - 1;
+        while (iFirst <= iLast)
+        {
+            iMid = (iLast + iFirst) / 2;
+            iCmp = Compare(psFind, &m_pBase[iMid]);
+            if (iCmp == 0)
+            {
+                if (piInsert != NULL)
+                    *piInsert = iMid;
+                return (&m_pBase[iMid]);
+            }
+            else if (iCmp < 0)
+                iLast = iMid - 1;
+            else
+                iFirst = iMid + 1;
+        }
+        if (piInsert != NULL)
+            *piInsert = iFirst;
+        return (NULL);
+    }
+
+//*****************************************************************************
+// Override this function to do the comparison if a comparison operator is
+// not valid for your data type (such as a struct).
+//*****************************************************************************
+    virtual int Compare(                    // -1, 0, or 1
+        const T     *psFirst,               // Key you are looking for.
+        const T     *psSecond)              // Item to compare to.
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (memcmp(psFirst, psSecond, sizeof(T)));
+//      return (::Compare(*psFirst, *psSecond));
+    }
+};
+
+//*****************************************************************************
+// The information that the hash table implementation stores at the beginning
+// of every record that can be but in the hash table.
+//*****************************************************************************
+typedef DPTR(struct HASHENTRY) PTR_HASHENTRY;
+struct HASHENTRY
+{
+    ULONG      iPrev;                  // Previous bucket in the chain.
+    ULONG      iNext;                  // Next bucket in the chain.
+};
+
+typedef DPTR(struct FREEHASHENTRY) PTR_FREEHASHENTRY;
+struct FREEHASHENTRY : HASHENTRY
+{
+    ULONG      iFree;
+};
+
+//*****************************************************************************
+// Used by the FindFirst/FindNextEntry functions.  These api's allow you to
+// do a sequential scan of all entries.
+//*****************************************************************************
+struct HASHFIND
+{
+    ULONG      iBucket;            // The next bucket to look in.
+    ULONG      iNext;
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// This is a class that implements a chain and bucket hash table.
+//
+// The data is actually supplied as an array of structures by the user of this class.
+// This allows the buckets to use small indices to point to the chain, instead of pointers.
+//
+// Each entry in the array contains a HASHENTRY structure immediately
+// followed by the key used to hash the structure.
+//
+// The HASHENTRY part of every structure is used to implement the chain of
+// entries in a single bucket.
+//
+// This implementation does not support rehashing the buckets if the table grows
+// to big.
+// @TODO: Fix this by adding an abstract function Hash() which must be implemented
+// by all clients.
+//
+//*****************************************************************************
+class CHashTable
+{
+    friend class DebuggerRCThread; //RCthread actually needs access to
+    //fields of derrived class DebuggerPatchTable
+
+protected:
+    TADDR       m_pcEntries;            // Pointer to the array of structs.
+    ULONG      m_iEntrySize;           // Size of the structs.
+
+    ULONG      m_iBuckets;             // # of chains we are hashing into.
+    PTR_ULONG  m_piBuckets;           // Ptr to the array of bucket chains.
+
+    INDEBUG(unsigned    m_maxSearch;)   // For evaluating perf characteristics
+
+    HASHENTRY *EntryPtr(ULONG iEntry)
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+        return (PTR_HASHENTRY(m_pcEntries + (iEntry * (size_t)m_iEntrySize)));
+    }
+
+    ULONG     ItemIndex(HASHENTRY *p)
+    {
+        SUPPORTS_DAC;
+        LIMITED_METHOD_CONTRACT;
+        return (ULONG)((dac_cast<TADDR>(p) - m_pcEntries) / m_iEntrySize);
+    }
+
+
+public:
+
+    CHashTable(
+        ULONG      iBuckets) :         // # of chains we are hashing into.
+        m_pcEntries((TADDR)NULL),
+        m_iBuckets(iBuckets)
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        m_piBuckets = NULL;
+
+        INDEBUG(m_maxSearch = 0;)
+    }
+
+    CHashTable() :         // # of chains we are hashing into.
+        m_pcEntries((TADDR)NULL),
+        m_iBuckets(5)
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        m_piBuckets = NULL;
+
+        INDEBUG(m_maxSearch = 0;)
+    }
+
+#ifndef DACCESS_COMPILE
+
+    ~CHashTable()
+    {
+        LIMITED_METHOD_CONTRACT;
+        if (m_piBuckets != NULL)
+        {
+            delete [] m_piBuckets;
+            m_piBuckets = NULL;
+        }
+    }
+
+//*****************************************************************************
+// This is the second part of construction where we do all of the work that
+// can fail.  We also take the array of structs here because the calling class
+// presumably needs to allocate it in its NewInit.
+//*****************************************************************************
+    HRESULT NewInit(                    // Return status.
+        BYTE        *pcEntries,         // Array of structs we are managing.
+        ULONG      iEntrySize);        // Size of the entries.
+
+//*****************************************************************************
+// This can be called to change the pointer to the table that the hash table
+// is managing.  You might call this if (for example) you realloc the size
+// of the table and its pointer is different.
+//*****************************************************************************
+    void SetTable(
+        BYTE        *pcEntries)         // Array of structs we are managing.
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_pcEntries = (TADDR)pcEntries;
+    }
+
+//*****************************************************************************
+// Clear the hash table as if there were nothing in it.
+//*****************************************************************************
+    void Clear()
+    {
+        LIMITED_METHOD_CONTRACT;
+        _ASSERTE(m_piBuckets != NULL);
+        memset(m_piBuckets, 0xff, m_iBuckets * sizeof(ULONG));
+    }
+
+//*****************************************************************************
+// Add the struct at the specified index in m_pcEntries to the hash chains.
+//*****************************************************************************
+    BYTE *Add(                          // New entry.
+        ULONG      iHash,              // Hash value of entry to add.
+        ULONG      iIndex);            // Index of struct in m_pcEntries.
+
+//*****************************************************************************
+// Delete the struct at the specified index in m_pcEntries from the hash chains.
+//*****************************************************************************
+    void Delete(
+        ULONG      iHash,              // Hash value of entry to delete.
+        ULONG      iIndex);            // Index of struct in m_pcEntries.
+
+    void Delete(
+        ULONG      iHash,              // Hash value of entry to delete.
+        HASHENTRY   *psEntry);          // The struct to delete.
+
+//*****************************************************************************
+// The item at the specified index has been moved, update the previous and
+// next item.
+//*****************************************************************************
+    void Move(
+        ULONG      iHash,              // Hash value for the item.
+        ULONG      iNew);              // New location.
+
+#endif // #ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// Return a boolean indicating whether or not this hash table has been inited.
+//*****************************************************************************
+    int IsInited()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_piBuckets != NULL);
+    }
+
+//*****************************************************************************
+// Search the hash table for an entry with the specified key value.
+//*****************************************************************************
+    BYTE *Find(                         // Index of struct in m_pcEntries.
+        ULONG      iHash,              // Hash value of the item.
+        SIZE_T     key);               // The key to match.
+
+//*****************************************************************************
+// Search the hash table for the next entry with the specified key value.
+//*****************************************************************************
+    ULONG FindNext(                    // Index of struct in m_pcEntries.
+        SIZE_T     key,                // The key to match.
+        ULONG      iIndex);            // Index of previous match.
+
+//*****************************************************************************
+// Returns the first entry in the first hash bucket and inits the search
+// struct.  Use the FindNextEntry function to continue walking the list.  The
+// return order is not gauranteed.
+//*****************************************************************************
+    BYTE *FindFirstEntry(               // First entry found, or 0.
+        HASHFIND    *psSrch)            // Search object.
+    {
+        WRAPPER_NO_CONTRACT;
+        if (m_piBuckets == 0)
+            return (0);
+        psSrch->iBucket = 1;
+        psSrch->iNext = m_piBuckets[0];
+        return (FindNextEntry(psSrch));
+    }
+
+//*****************************************************************************
+// Returns the next entry in the list.
+//*****************************************************************************
+    BYTE *FindNextEntry(                // The next entry, or0 for end of list.
+        HASHFIND    *psSrch);           // Search object.
+
+#ifdef DACCESS_COMPILE
+    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
+                           ULONG numEntries);
+#endif
+
+protected:
+    virtual BOOL Cmp(SIZE_T key1, const HASHENTRY * pc2) = 0;
+};
+
+
+class CNewData
+{
+public:
+    static BYTE *Alloc(int iSize, int iMaxSize)
+    {
+        WRAPPER_NO_CONTRACT;
+        return (new BYTE[iSize]);
+    }
+    static void Free(BYTE *pPtr, int iSize)
+    {
+        LIMITED_METHOD_CONTRACT;
+        delete [] pPtr;
+    }
+    static BYTE *Grow(BYTE *&pPtr, int iCurSize)
+    {
+        WRAPPER_NO_CONTRACT;
+        BYTE *p;
+        S_SIZE_T newSize = S_SIZE_T(iCurSize) + S_SIZE_T(GrowSize(iCurSize));
+        //check for overflow
+        if(newSize.IsOverflow())
+            p = NULL;
+        else
+            p = new (nothrow) BYTE[newSize.Value()];
+        if (p == 0) return (0);
+        memcpy (p, pPtr, iCurSize);
+        delete [] pPtr;
+        pPtr = p;
+        return pPtr;
+    }
+    static void Clean(BYTE * pData, int iSize)
+    {
+    }
+    static int RoundSize(int iSize)
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (iSize);
+    }
+    static int GrowSize(int iCurSize)
+    {
+        LIMITED_METHOD_CONTRACT;
+        int newSize = (3 * iCurSize) / 2;
+        return (newSize < 256) ? 256 : newSize;
+    }
+};
+
+class CNewDataNoThrow
+{
+public:
+    static BYTE *Alloc(int iSize, int iMaxSize)
+    {
+        WRAPPER_NO_CONTRACT;
+        return (new (nothrow) BYTE[iSize]);
+    }
+    static void Free(BYTE *pPtr, int iSize)
+    {
+        LIMITED_METHOD_CONTRACT;
+        delete [] pPtr;
+    }
+    static BYTE *Grow(BYTE *&pPtr, int iCurSize)
+    {
+        WRAPPER_NO_CONTRACT;
+        BYTE *p;
+        S_SIZE_T newSize = S_SIZE_T(iCurSize) + S_SIZE_T(GrowSize(iCurSize));
+        //check for overflow
+        if(newSize.IsOverflow())
+            p = NULL;
+        else
+            p = new (nothrow) BYTE[newSize.Value()];
+        if (p == 0) return (0);
+        memcpy (p, pPtr, iCurSize);
+        delete [] pPtr;
+        pPtr = p;
+        return pPtr;
+    }
+    static void Clean(BYTE * pData, int iSize)
+    {
+    }
+    static int RoundSize(int iSize)
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (iSize);
+    }
+    static int GrowSize(int iCurSize)
+    {
+        LIMITED_METHOD_CONTRACT;
+        int newSize = (3 * iCurSize) / 2;
+        return (newSize < 256) ? 256 : newSize;
+    }
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// CHashTable expects the data to be in a single array - this is provided by
+// CHashTableAndData.
+// The array is allocated using the MemMgr type. CNewData and
+// CNewDataNoThrow can be used for this.
+//*****************************************************************************
+template <class MemMgr>
+class CHashTableAndData : public CHashTable
+{
+public:
+    DAC_ALIGNAS(CHashTable)
+    ULONG      m_iFree;                // Index into m_pcEntries[] of next available slot
+    ULONG      m_iEntries;             // size of m_pcEntries[]
+
+public:
+
+    CHashTableAndData() :
+        CHashTable()
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+
+    CHashTableAndData(
+        ULONG      iBuckets) :         // # of chains we are hashing into.
+        CHashTable(iBuckets)
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+
+#ifndef DACCESS_COMPILE
+
+    ~CHashTableAndData()
+    {
+        WRAPPER_NO_CONTRACT;
+        if (m_pcEntries != NULL)
+            MemMgr::Free((BYTE*)m_pcEntries, MemMgr::RoundSize(m_iEntries * m_iEntrySize));
+    }
+
+//*****************************************************************************
+// This is the second part of construction where we do all of the work that
+// can fail.  We also take the array of structs here because the calling class
+// presumably needs to allocate it in its NewInit.
+//*****************************************************************************
+    HRESULT NewInit(                    // Return status.
+        ULONG      iEntries,           // # of entries.
+        ULONG      iEntrySize,         // Size of the entries.
+        int         iMaxSize);          // Max size of data.
+
+//*****************************************************************************
+// Clear the hash table as if there were nothing in it.
+//*****************************************************************************
+    void Clear()
+    {
+        WRAPPER_NO_CONTRACT;
+        m_iFree = 0;
+        InitFreeChain(0, m_iEntries);
+        CHashTable::Clear();
+    }
+
+//*****************************************************************************
+// Grabs a slot for the new entry to be added.
+// The caller should fill in the non-HASHENTRY part of the returned slot
+//*****************************************************************************
+    BYTE *Add(
+        ULONG      iHash)              // Hash value of entry to add.
+    {
+        WRAPPER_NO_CONTRACT;
+        FREEHASHENTRY *psEntry;
+
+        // Make the table bigger if necessary.
+        if (m_iFree == UINT32_MAX && !Grow())
+            return (NULL);
+
+        // Add the first entry from the free list to the hash chain.
+        psEntry = (FREEHASHENTRY *) CHashTable::Add(iHash, m_iFree);
+        m_iFree = psEntry->iFree;
+
+        // If we're recycling memory, give our memory-allocator a chance to re-init it.
+
+        // Each entry is prefixed with a header - we don't want to trash that.
+        SIZE_T cbHeader = sizeof(FREEHASHENTRY);
+        MemMgr::Clean((BYTE*) psEntry + cbHeader, (int) (m_iEntrySize - cbHeader));
+
+        return ((BYTE *) psEntry);
+    }
+
+//*****************************************************************************
+// Delete the struct at the specified index in m_pcEntries from the hash chains.
+//*****************************************************************************
+    void Delete(
+        ULONG      iHash,              // Hash value of entry to delete.
+        ULONG      iIndex)             // Index of struct in m_pcEntries.
+    {
+        WRAPPER_NO_CONTRACT;
+        CHashTable::Delete(iHash, iIndex);
+        ((FREEHASHENTRY *) EntryPtr(iIndex))->iFree = m_iFree;
+        m_iFree = iIndex;
+    }
+
+    void Delete(
+        ULONG      iHash,              // Hash value of entry to delete.
+        HASHENTRY   *psEntry)           // The struct to delete.
+    {
+        WRAPPER_NO_CONTRACT;
+        CHashTable::Delete(iHash, psEntry);
+        ((FREEHASHENTRY *) psEntry)->iFree = m_iFree;
+        m_iFree = ItemIndex(psEntry);
+    }
+
+#endif // #ifndef DACCESS_COMPILE
+
+    // This is a sad legacy workaround. The debugger's patch table (implemented as this
+    // class) is shared across process. We publish the runtime offsets of
+    // some key fields. Since those fields are private, we have to provide
+    // accessors here. So if you're not using these functions, don't start.
+    // We can hopefully remove them.
+    // Note that we can't just make RCThread a friend of this class (we tried
+    // originally) because the inheritence chain has a private modifier,
+    // so DebuggerPatchTable::m_pcEntries is illegal.
+    static SIZE_T helper_GetOffsetOfEntries()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return offsetof(CHashTableAndData, m_pcEntries);
+    }
+
+    static SIZE_T helper_GetOffsetOfCount()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return offsetof(CHashTableAndData, m_iEntries);
+    }
+
+#ifdef DACCESS_COMPILE
+    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+    {
+        SUPPORTS_DAC;
+        CHashTable::EnumMemoryRegions(flags, m_iEntries);
+    }
+#endif
+
+private:
+    void InitFreeChain(ULONG iStart,ULONG iEnd);
+    int Grow();
+};
+
+#ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// This is the second part of construction where we do all of the work that
+// can fail.  We also take the array of structs here because the calling class
+// presumably needs to allocate it in its NewInit.
+//*****************************************************************************
+template<class MemMgr>
+HRESULT CHashTableAndData<MemMgr>::NewInit(// Return status.
+    ULONG      iEntries,               // # of entries.
+    ULONG      iEntrySize,             // Size of the entries.
+    int         iMaxSize)               // Max size of data.
+{
+    WRAPPER_NO_CONTRACT;
+    BYTE        *pcEntries;
+    HRESULT     hr;
+
+
+    // note that this function can throw because it depends on the <M>::Alloc
+
+    // Allocate the memory for the entries.
+    if ((pcEntries = MemMgr::Alloc(MemMgr::RoundSize(iEntries * iEntrySize),
+                                   MemMgr::RoundSize(iMaxSize))) == 0)
+        return (E_OUTOFMEMORY);
+    m_iEntries = iEntries;
+
+    // Init the base table.
+    if (FAILED(hr = CHashTable::NewInit(pcEntries, iEntrySize)))
+        MemMgr::Free(pcEntries, MemMgr::RoundSize(iEntries * iEntrySize));
+    else
+    {
+        // Init the free chain.
+        m_iFree = 0;
+        InitFreeChain(0, iEntries);
+    }
+    return (hr);
+}
+
+//*****************************************************************************
+// Initialize a range of records such that they are linked together to be put
+// on the free chain.
+//*****************************************************************************
+template<class MemMgr>
+void CHashTableAndData<MemMgr>::InitFreeChain(
+    ULONG      iStart,                 // Index to start initializing.
+    ULONG      iEnd)                   // Index to stop initializing
+{
+    LIMITED_METHOD_CONTRACT;
+    BYTE* pcPtr;
+    _ASSERTE(iEnd > iStart);
+
+    pcPtr = (BYTE*)m_pcEntries + iStart * (size_t)m_iEntrySize;
+    for (++iStart; iStart < iEnd; ++iStart)
+    {
+        ((FREEHASHENTRY *) pcPtr)->iFree = iStart;
+        pcPtr += m_iEntrySize;
+    }
+    ((FREEHASHENTRY *) pcPtr)->iFree = UINT32_MAX;
+}
+
+//*****************************************************************************
+// Attempt to increase the amount of space available for the record heap.
+//*****************************************************************************
+template<class MemMgr>
+int CHashTableAndData<MemMgr>::Grow()   // 1 if successful, 0 if not.
+{
+    WRAPPER_NO_CONTRACT;
+    int         iCurSize;               // Current size in bytes.
+    int         iEntries;               // New # of entries.
+
+    _ASSERTE(m_pcEntries != NULL);
+    _ASSERTE(m_iFree == UINT32_MAX);
+
+    // Compute the current size and new # of entries.
+    S_UINT32 iTotEntrySize = S_UINT32(m_iEntries) * S_UINT32(m_iEntrySize);
+    if( iTotEntrySize.IsOverflow() )
+    {
+        _ASSERTE( !"CHashTableAndData overflow!" );
+        return (0);
+    }
+    iCurSize = MemMgr::RoundSize( iTotEntrySize.Value() );
+    iEntries = (iCurSize + MemMgr::GrowSize(iCurSize)) / m_iEntrySize;
+
+    if ( (iEntries < 0) || ((ULONG)iEntries <= m_iEntries) )
+    {
+        _ASSERTE( !"CHashTableAndData overflow!" );
+        return (0);
+    }
+
+    // Try to expand the array.
+    if (MemMgr::Grow(*(BYTE**)&m_pcEntries, iCurSize) == 0)
+        return (0);
+
+    // Init the newly allocated space.
+    InitFreeChain(m_iEntries, iEntries);
+    m_iFree = m_iEntries;
+    m_iEntries = iEntries;
+    return (1);
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+//*****************************************************************************
+
+inline COUNT_T HashCOUNT_T(COUNT_T currentHash, COUNT_T data)
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+    return ((currentHash << 5) + currentHash) ^ data;
+}
+
+inline COUNT_T HashPtr(COUNT_T currentHash, PTR_VOID ptr)
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+    return HashCOUNT_T(currentHash, COUNT_T(SIZE_T(dac_cast<TADDR>(ptr))));
+}
+
+inline DWORD HashThreeToOne(DWORD a, DWORD b, DWORD c)
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    /*
+    lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+    These are functions for producing 32-bit hashes for hash table lookup.
+    hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+    are externally useful functions.  Routines to test the hash are included
+    if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+    the public domain.  It has no warranty.
+    */
+
+    #define rot32(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+    c ^= b; c -= rot32(b,14);
+    a ^= c; a -= rot32(c,11);
+    b ^= a; b -= rot32(a,25);
+    c ^= b; c -= rot32(b,16);
+    a ^= c; a -= rot32(c,4);
+    b ^= a; b -= rot32(a,14);
+    c ^= b; c -= rot32(b,24);
+
+    return c;
+}
+
+inline ULONG HashBytes(BYTE const *pbData, size_t iSize)
+{
+    LIMITED_METHOD_CONTRACT;
+    ULONG   hash = 5381;
+
+    BYTE const *pbDataEnd = pbData + iSize;
+
+    for (/**/ ; pbData < pbDataEnd; pbData++)
+    {
+        hash = ((hash << 5) + hash) ^ *pbData;
+    }
+    return hash;
+}
+
+// Helper function for hashing a string char by char.
+inline ULONG HashStringA(LPCSTR szStr)
+{
+    LIMITED_METHOD_CONTRACT;
+    ULONG   hash = 5381;
+    int     c;
+
+    while ((c = *szStr) != 0)
+    {
+        hash = ((hash << 5) + hash) ^ c;
+        ++szStr;
+    }
+    return hash;
+}
+
+inline ULONG HashString(LPCWSTR szStr)
+{
+    LIMITED_METHOD_CONTRACT;
+    ULONG   hash = 5381;
+    int     c;
+
+    while ((c = *szStr) != 0)
+    {
+        hash = ((hash << 5) + hash) ^ c;
+        ++szStr;
+    }
+    return hash;
+}
+
+inline ULONG HashStringN(LPCWSTR szStr, SIZE_T cchStr)
+{
+    LIMITED_METHOD_CONTRACT;
+    ULONG   hash = 5381;
+
+    // hash the string two characters at a time
+    ULONG *ptr = (ULONG *)szStr;
+
+    // we assume that szStr is null-terminated
+    _ASSERTE(cchStr <= wcslen(szStr));
+    SIZE_T cDwordCount = (cchStr + 1) / 2;
+
+    for (SIZE_T i = 0; i < cDwordCount; i++)
+    {
+        hash = ((hash << 5) + hash) ^ ptr[i];
+    }
+
+    return hash;
+}
+
+// Case-insensitive string hash function.
+inline ULONG HashiStringA(LPCSTR szStr)
+{
+    LIMITED_METHOD_CONTRACT;
+    ULONG   hash = 5381;
+    while (*szStr != 0)
+    {
+        hash = ((hash << 5) + hash) ^ toupper(*szStr);
+        szStr++;
+    }
+    return hash;
+}
+
+// Case-insensitive string hash function.
+inline ULONG HashiString(LPCWSTR szStr)
+{
+    LIMITED_METHOD_CONTRACT;
+    ULONG   hash = 5381;
+    while (*szStr != 0)
+    {
+        hash = ((hash << 5) + hash) ^ towupper(*szStr);
+        szStr++;
+    }
+    return hash;
+}
+
+// Case-insensitive string hash function.
+inline ULONG HashiStringN(LPCWSTR szStr, DWORD count)
+{
+    LIMITED_METHOD_CONTRACT;
+    ULONG   hash = 5381;
+    while (*szStr != 0 && count--)
+    {
+        hash = ((hash << 5) + hash) ^ towupper(*szStr);
+        szStr++;
+    }
+    return hash;
+}
+
+// Case-insensitive string hash function when all of the
+// characters in the string are known to be below 0x80.
+// Knowing this is much more efficient than calling
+// towupper above.
+inline ULONG HashiStringKnownLower80(LPCWSTR szStr) {
+    LIMITED_METHOD_CONTRACT;
+    ULONG hash = 5381;
+    int c;
+    int mask = ~0x20;
+    while ((c = *szStr)!=0) {
+        //If we have a lowercase character, ANDing off 0x20
+        //(mask) will make it an uppercase character.
+        if (c>='a' && c<='z') {
+            c&=mask;
+        }
+        hash = ((hash << 5) + hash) ^ c;
+        ++szStr;
+    }
+    return hash;
+}
+
+inline ULONG HashiStringNKnownLower80(LPCWSTR szStr, DWORD count) {
+    LIMITED_METHOD_CONTRACT;
+    ULONG hash = 5381;
+    int c;
+    int mask = ~0x20;
+    while ((c = *szStr) !=0 && count--) {
+        //If we have a lowercase character, ANDing off 0x20
+        //(mask) will make it an uppercase character.
+        if (c>='a' && c<='z') {
+            c&=mask;
+        }
+        hash = ((hash << 5) + hash) ^ c;
+        ++szStr;
+    }
+    return hash;
+}
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// This class implements a closed hashing table.  Values are hashed to a bucket,
+// and if that bucket is full already, then the value is placed in the next
+// free bucket starting after the desired target (with wrap around).  If the
+// table becomes 75% full, it is grown and rehashed to reduce lookups.  This
+// class is best used in a reltively small lookup table where hashing is
+// not going to cause many collisions.  By not having the collision chain
+// logic, a lot of memory is saved.
+//
+// The user of the template is required to supply several methods which decide
+// how each element can be marked as free, deleted, or used.  It would have
+// been possible to write this with more internal logic, but that would require
+// either (a) more overhead to add status on top of elements, or (b) hard
+// coded types like one for strings, one for ints, etc... This gives you the
+// flexibility of adding logic to your type.
+//*****************************************************************************
+class CClosedHashBase
+{
+    BYTE *EntryPtr(int iEntry)
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_rgData + (iEntry * (size_t)m_iEntrySize));
+    }
+
+    BYTE *EntryPtr(int iEntry, BYTE *rgData)
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (rgData + (iEntry * (size_t)m_iEntrySize));
+    }
+
+public:
+    enum ELEMENTSTATUS
+    {
+        FREE,                               // Item is not in use right now.
+        DELETED,                            // Item is deleted.
+        USED                                // Item is in use.
+    };
+
+    CClosedHashBase(
+        int         iBuckets,               // How many buckets should we start with.
+        int         iEntrySize,             // Size of an entry.
+        bool        bPerfect) :             // true if bucket size will hash with no collisions.
+        m_bPerfect(bPerfect),
+        m_iBuckets(iBuckets),
+        m_iEntrySize(iEntrySize),
+        m_iCount(0),
+        m_iCollisions(0),
+        m_rgData(0)
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_iSize = iBuckets + 7;
+    }
+
+    virtual ~CClosedHashBase()
+    {
+        WRAPPER_NO_CONTRACT;
+        Clear();
+    }
+
+    virtual void Clear()
+    {
+        LIMITED_METHOD_CONTRACT;
+        delete [] m_rgData;
+        m_iCount = 0;
+        m_iCollisions = 0;
+        m_rgData = 0;
+    }
+
+//*****************************************************************************
+// Accessors for getting at the underlying data.  Be careful to use Count()
+// only when you want the number of buckets actually used.
+//*****************************************************************************
+
+    int Count()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_iCount);
+    }
+
+    int Collisions()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_iCollisions);
+    }
+
+    int Buckets()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_iBuckets);
+    }
+
+    void SetBuckets(int iBuckets, bool bPerfect=false)
+    {
+        LIMITED_METHOD_CONTRACT;
+        _ASSERTE(m_rgData == 0);
+        m_iBuckets = iBuckets;
+        m_iSize = m_iBuckets + 7;
+        m_bPerfect = bPerfect;
+    }
+
+    BYTE *Data()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_rgData);
+    }
+
+//*****************************************************************************
+// Add a new item to hash table given the key value.  If this new entry
+// exceeds maximum size, then the table will grow and be re-hashed, which
+// may cause a memory error.
+//*****************************************************************************
+    BYTE *Add(                              // New item to fill out on success.
+        void        *pData)                 // The value to hash on.
+    {
+        WRAPPER_NO_CONTRACT;
+        // If we haven't allocated any memory, or it is too small, fix it.
+        if (!m_rgData || ((m_iCount + 1) > (m_iSize * 3 / 4) && !m_bPerfect))
+        {
+            if (!ReHash())
+                return (0);
+        }
+
+        return (DoAdd(pData, m_rgData, m_iBuckets, m_iSize, m_iCollisions, m_iCount));
+    }
+
+//*****************************************************************************
+// Delete the given value.  This will simply mark the entry as deleted (in
+// order to keep the collision chain intact).  There is an optimization that
+// consecutive deleted entries leading up to a free entry are themselves freed
+// to reduce collisions later on.
+//*****************************************************************************
+    void Delete(
+        void        *pData);                // Key value to delete.
+
+
+//*****************************************************************************
+//  Callback function passed to DeleteLoop.
+//*****************************************************************************
+    typedef BOOL (* DELETELOOPFUNC)(        // Delete current item?
+         BYTE *pEntry,                      // Bucket entry to evaluate
+         void *pCustomizer);                // User-defined value
+
+//*****************************************************************************
+// Iterates over all active values, passing each one to pDeleteLoopFunc.
+// If pDeleteLoopFunc returns TRUE, the entry is deleted. This is safer
+// and faster than using FindNext() and Delete().
+//*****************************************************************************
+    void DeleteLoop(
+        DELETELOOPFUNC pDeleteLoopFunc,     // Decides whether to delete item
+        void *pCustomizer);                 // Extra value passed to deletefunc.
+
+
+//*****************************************************************************
+// Lookup a key value and return a pointer to the element if found.
+//*****************************************************************************
+    BYTE *Find(                             // The item if found, 0 if not.
+        void        *pData);                // The key to lookup.
+
+//*****************************************************************************
+// Look for an item in the table.  If it isn't found, then create a new one and
+// return that.
+//*****************************************************************************
+    BYTE *FindOrAdd(                        // The item if found, 0 if not.
+        void        *pData,                 // The key to lookup.
+        bool        &bNew);                 // true if created.
+
+//*****************************************************************************
+// The following functions are used to traverse each used entry.  This code
+// will skip over deleted and free entries freeing the caller up from such
+// logic.
+//*****************************************************************************
+    BYTE *GetFirst()                        // The first entry, 0 if none.
+    {
+        WRAPPER_NO_CONTRACT;
+        int         i;                      // Loop control.
+
+        // If we've never allocated the table there can't be any to get.
+        if (m_rgData == 0)
+            return (0);
+
+        // Find the first one.
+        for (i=0;  i<m_iSize;  i++)
+        {
+            if (Status(EntryPtr(i)) != FREE && Status(EntryPtr(i)) != DELETED)
+                return (EntryPtr(i));
+        }
+        return (0);
+    }
+
+    BYTE *GetNext(BYTE *Prev)               // The next entry, 0 if done.
+    {
+        WRAPPER_NO_CONTRACT;
+        int         i;                      // Loop control.
+
+        for (i = (int)(((size_t) Prev - (size_t) &m_rgData[0]) / m_iEntrySize) + 1; i<m_iSize;  i++)
+        {
+            if (Status(EntryPtr(i)) != FREE && Status(EntryPtr(i)) != DELETED)
+                return (EntryPtr(i));
+        }
+        return (0);
+    }
+
+private:
+//*****************************************************************************
+// Hash is called with a pointer to an element in the table.  You must override
+// this method and provide a hash algorithm for your element type.
+//*****************************************************************************
+    virtual unsigned int Hash(             // The key value.
+        void const  *pData)=0;              // Raw data to hash.
+
+//*****************************************************************************
+// Compare is used in the typical memcmp way, 0 is eqaulity, -1/1 indicate
+// direction of miscompare.  In this system everything is always equal or not.
+//*****************************************************************************
+    virtual unsigned int Compare(          // 0, -1, or 1.
+        void const  *pData,                 // Raw key data on lookup.
+        BYTE        *pElement)=0;           // The element to compare data against.
+
+//*****************************************************************************
+// Return true if the element is free to be used.
+//*****************************************************************************
+    virtual ELEMENTSTATUS Status(           // The status of the entry.
+        BYTE        *pElement)=0;           // The element to check.
+
+//*****************************************************************************
+// Sets the status of the given element.
+//*****************************************************************************
+    virtual void SetStatus(
+        BYTE        *pElement,              // The element to set status for.
+        ELEMENTSTATUS eStatus)=0;           // New status.
+
+//*****************************************************************************
+// Returns the internal key value for an element.
+//*****************************************************************************
+    virtual void *GetKey(                   // The data to hash on.
+        BYTE        *pElement)=0;           // The element to return data ptr for.
+
+//*****************************************************************************
+// This helper actually does the add for you.
+//*****************************************************************************
+    BYTE *DoAdd(void *pData, BYTE *rgData, int &iBuckets, int iSize,
+                int &iCollisions, int &iCount);
+
+//*****************************************************************************
+// This function is called either to init the table in the first place, or
+// to rehash the table if we ran out of room.
+//*****************************************************************************
+    bool ReHash();                          // true if successful.
+
+//*****************************************************************************
+// Walk each item in the table and mark it free.
+//*****************************************************************************
+    void InitFree(BYTE *ptr, int iSize)
+    {
+        WRAPPER_NO_CONTRACT;
+        int         i;
+        for (i=0;  i<iSize;  i++, ptr += m_iEntrySize)
+            SetStatus(ptr, FREE);
+    }
+
+private:
+    bool        m_bPerfect;                 // true if the table size guarantees
+                                            //  no collisions.
+    int         m_iBuckets;                 // How many buckets do we have.
+    int         m_iEntrySize;               // Size of an entry.
+    int         m_iSize;                    // How many elements can we have.
+    int         m_iCount;                   // How many items cannot be used (NON free, i.e. USED+DELETED).
+    int         m_iCollisions;              // How many have we had.
+    BYTE        *m_rgData;                  // Data element list.
+};
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+template <class T> class CClosedHash : public CClosedHashBase
+{
+public:
+    CClosedHash(
+        int         iBuckets,               // How many buckets should we start with.
+        bool        bPerfect=false) :       // true if bucket size will hash with no collisions.
+        CClosedHashBase(iBuckets, sizeof(T), bPerfect)
+    {
+        WRAPPER_NO_CONTRACT;
+    }
+
+    T &operator[](int iIndex)
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T &) *(Data() + (iIndex * sizeof(T))));
+    }
+
+
+//*****************************************************************************
+// Add a new item to hash table given the key value.  If this new entry
+// exceeds maximum size, then the table will grow and be re-hashed, which
+// may cause a memory error.
+//*****************************************************************************
+    T *Add(                                 // New item to fill out on success.
+        void        *pData)                 // The value to hash on.
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *) CClosedHashBase::Add(pData));
+    }
+
+//*****************************************************************************
+// Lookup a key value and return a pointer to the element if found.
+//*****************************************************************************
+    T *Find(                                // The item if found, 0 if not.
+        void        *pData)                 // The key to lookup.
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *) CClosedHashBase::Find(pData));
+    }
+
+//*****************************************************************************
+// Look for an item in the table.  If it isn't found, then create a new one and
+// return that.
+//*****************************************************************************
+    T *FindOrAdd(                           // The item if found, 0 if not.
+        void        *pData,                 // The key to lookup.
+        bool        &bNew)                  // true if created.
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *) CClosedHashBase::FindOrAdd(pData, bNew));
+    }
+
+
+//*****************************************************************************
+// The following functions are used to traverse each used entry.  This code
+// will skip over deleted and free entries freeing the caller up from such
+// logic.
+//*****************************************************************************
+    T *GetFirst()                           // The first entry, 0 if none.
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *) CClosedHashBase::GetFirst());
+    }
+
+    T *GetNext(T *Prev)                     // The next entry, 0 if done.
+    {
+        WRAPPER_NO_CONTRACT;
+        return ((T *) CClosedHashBase::GetNext((BYTE *) Prev));
+    }
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// Closed hash with typed parameters.  The derived class is the second
+//  parameter to the template.  The derived class must implement:
+//    unsigned long Hash(const T *pData);
+//    unsigned long Compare(const T *p1, T *p2);
+//    ELEMENTSTATUS Status(T *pEntry);
+//    void SetStatus(T *pEntry, ELEMENTSTATUS s);
+//    void* GetKey(T *pEntry);
+//*****************************************************************************
+template<class T, class H>class CClosedHashEx : public CClosedHash<T>
+{
+public:
+    CClosedHashEx(
+        int         iBuckets,               // How many buckets should we start with.
+        bool        bPerfect=false) :       // true if bucket size will hash with no collisions.
+        CClosedHash<T> (iBuckets, bPerfect)
+    {
+        WRAPPER_NO_CONTRACT;
+    }
+
+    unsigned int Hash(const void *pData)
+    {
+        WRAPPER_NO_CONTRACT;
+        return static_cast<H*>(this)->Hash((const T*)pData);
+    }
+
+    unsigned int Compare(const void *p1, BYTE *p2)
+    {
+        WRAPPER_NO_CONTRACT;
+        return static_cast<H*>(this)->Compare((const T*)p1, (T*)p2);
+    }
+
+    typename CClosedHash<T>::ELEMENTSTATUS Status(BYTE *p)
+    {
+        WRAPPER_NO_CONTRACT;
+        return static_cast<H*>(this)->Status((T*)p);
+    }
+
+    void SetStatus(BYTE *p, typename CClosedHash<T>::ELEMENTSTATUS s)
+    {
+        WRAPPER_NO_CONTRACT;
+        static_cast<H*>(this)->SetStatus((T*)p, s);
+    }
+
+    void* GetKey(BYTE *p)
+    {
+        WRAPPER_NO_CONTRACT;
+        return static_cast<H*>(this)->GetKey((T*)p);
+    }
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// This template is another form of a closed hash table.  It handles collisions
+// through a linked chain.  To use it, derive your hashed item from HASHLINK
+// and implement the virtual functions required.  1.5 * ibuckets will be
+// allocated, with the extra .5 used for collisions.  If you add to the point
+// where no free nodes are available, the entire table is grown to make room.
+// The advantage to this system is that collisions are always directly known,
+// there either is one or there isn't.
+//*****************************************************************************
+struct HASHLINK
+{
+    ULONG       iNext;                  // Offset for next entry.
+};
+
+template <class T> class CChainedHash
+{
+    friend class VerifyLayoutsMD;
+public:
+    CChainedHash(int iBuckets=32) :
+        m_rgData(0),
+        m_iBuckets(iBuckets),
+        m_iCount(0),
+        m_iMaxChain(0),
+        m_iFree(0)
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_iSize = iBuckets + (iBuckets / 2);
+    }
+
+    ~CChainedHash()
+    {
+        LIMITED_METHOD_CONTRACT;
+        if (m_rgData)
+            delete [] m_rgData;
+    }
+
+    void SetBuckets(int iBuckets)
+    {
+        LIMITED_METHOD_CONTRACT;
+        _ASSERTE(m_rgData == 0);
+        // if iBuckets==0, then we'll allocate a zero size array and AV on dereference.
+        _ASSERTE(iBuckets > 0);
+        m_iBuckets = iBuckets;
+        m_iSize = iBuckets + (iBuckets / 2);
+    }
+
+    T *Add(void const *pData)
+    {
+        WRAPPER_NO_CONTRACT;
+        ULONG       iHash;
+        int         iBucket;
+        T           *pItem;
+
+        // Build the list if required.
+        if (m_rgData == 0 || m_iFree == 0xffffffff)
+        {
+            if (!ReHash())
+                return (0);
+        }
+
+        // Hash the item and pick a bucket.
+        iHash = Hash(pData);
+        iBucket = iHash % m_iBuckets;
+
+        // Use the bucket if it is free.
+        if (InUse(&m_rgData[iBucket]) == false)
+        {
+            pItem = &m_rgData[iBucket];
+            pItem->iNext = 0xffffffff;
+        }
+        // Else take one off of the free list for use.
+        else
+        {
+            ULONG       iEntry;
+
+            // Pull an item from the free list.
+            iEntry = m_iFree;
+            pItem = &m_rgData[m_iFree];
+            m_iFree = pItem->iNext;
+
+            // Link the new node in after the bucket.
+            pItem->iNext = m_rgData[iBucket].iNext;
+            m_rgData[iBucket].iNext = iEntry;
+        }
+        ++m_iCount;
+        return (pItem);
+    }
+
+    T *Find(void const *pData, bool bAddIfNew=false)
+    {
+        WRAPPER_NO_CONTRACT;
+        ULONG       iHash;
+        int         iBucket;
+        T           *pItem;
+
+        // Check states for lookup.
+        if (m_rgData == 0)
+        {
+            // If we won't be adding, then we are through.
+            if (bAddIfNew == false)
+                return (0);
+
+            // Otherwise, create the table.
+            if (!ReHash())
+                return (0);
+        }
+
+        // Hash the item and pick a bucket.
+        iHash = Hash(pData);
+        iBucket = iHash % m_iBuckets;
+
+        // If it isn't in use, then there it wasn't found.
+        if (!InUse(&m_rgData[iBucket]))
+        {
+            if (bAddIfNew == false)
+                pItem = 0;
+            else
+            {
+                pItem = &m_rgData[iBucket];
+                pItem->iNext = 0xffffffff;
+                ++m_iCount;
+            }
+        }
+        // Scan the list for the one we want.
+        else
+        {
+            ULONG iChain = 0;
+            for (pItem=(T *) &m_rgData[iBucket];  pItem;  pItem=GetNext(pItem))
+            {
+                if (Cmp(pData, pItem) == 0)
+                    break;
+                ++iChain;
+            }
+
+            if (!pItem && bAddIfNew)
+            {
+                ULONG       iEntry;
+
+                // Record maximum chain length.
+                if (iChain > m_iMaxChain)
+                    m_iMaxChain = iChain;
+
+                // Now need more room.
+                if (m_iFree == 0xffffffff)
+                {
+                    if (!ReHash())
+                        return (0);
+                }
+
+                // Pull an item from the free list.
+                iEntry = m_iFree;
+                pItem = &m_rgData[m_iFree];
+                m_iFree = pItem->iNext;
+
+                // Link the new node in after the bucket.
+                pItem->iNext = m_rgData[iBucket].iNext;
+                m_rgData[iBucket].iNext = iEntry;
+                ++m_iCount;
+            }
+        }
+        return (pItem);
+    }
+
+    int Count()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_iCount);
+    }
+
+    int Buckets()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_iBuckets);
+    }
+
+    ULONG MaxChainLength()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_iMaxChain);
+    }
+
+    virtual void Clear()
+    {
+        LIMITED_METHOD_CONTRACT;
+        // Free up the memory.
+        if (m_rgData)
+        {
+            delete [] m_rgData;
+            m_rgData = 0;
+        }
+
+        m_rgData = 0;
+        m_iFree = 0;
+        m_iCount = 0;
+        m_iMaxChain = 0;
+    }
+
+    virtual bool InUse(T *pItem)=0;
+    virtual void SetFree(T *pItem)=0;
+    virtual ULONG Hash(void const *pData)=0;
+    virtual int Cmp(void const *pData, void *pItem)=0;
+private:
+    inline T *GetNext(T *pItem)
+    {
+        LIMITED_METHOD_CONTRACT;
+        if (pItem->iNext != 0xffffffff)
+            return ((T *) &m_rgData[pItem->iNext]);
+        return (0);
+    }
+
+    bool ReHash()
+    {
+        WRAPPER_NO_CONTRACT;
+        T           *rgTemp;
+        int         iNewSize;
+
+        // If this is a first time allocation, then just malloc it.
+        if (!m_rgData)
+        {
+            if ((m_rgData = new (nothrow) T[m_iSize]) == 0)
+                return (false);
+
+            int i;
+            for (i=0;  i<m_iSize;  i++)
+                SetFree(&m_rgData[i]);
+
+            m_iFree = m_iBuckets;
+            for (i=m_iBuckets;  i<m_iSize;  i++)
+                ((T *) &m_rgData[i])->iNext = i + 1;
+            ((T *) &m_rgData[m_iSize - 1])->iNext = 0xffffffff;
+            return (true);
+        }
+
+        // Otherwise we need more room on the free chain, so allocate some.
+        iNewSize = m_iSize + (m_iSize / 2);
+
+        // Allocate/realloc memory.
+        if ((rgTemp = new (nothrow) T[iNewSize]) == 0)
+            return (false);
+
+        memcpy (rgTemp,m_rgData,m_iSize*sizeof(T));
+        delete [] m_rgData;
+
+        // Init new entries, save the new free chain, and reset internals.
+        m_iFree = m_iSize;
+        for (int i=m_iFree;  i<iNewSize;  i++)
+        {
+            SetFree(&rgTemp[i]);
+            ((T *) &rgTemp[i])->iNext = i + 1;
+        }
+        ((T *) &rgTemp[iNewSize - 1])->iNext = 0xffffffff;
+
+        m_rgData = rgTemp;
+        m_iSize = iNewSize;
+        return (true);
+    }
+
+private:
+    T           *m_rgData;              // Data to store items in.
+    int         m_iBuckets;             // How many buckets we want.
+    int         m_iSize;                // How many are allocated.
+    int         m_iCount;               // How many are we using.
+    ULONG       m_iMaxChain;            // Max chain length.
+    ULONG       m_iFree;                // Free chain.
+};
+
+
+//*****************************************************************************
+//
+//********** String helper functions.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+// Checks if string length exceeds the specified limit
+//*****************************************************************************
+inline BOOL IsStrLongerThan(_In_ _In_z_ char* pstr, unsigned N)
+{
+    LIMITED_METHOD_CONTRACT;
+    unsigned i = 0;
+    if(pstr)
+    {
+        for(i=0; (i < N)&&(pstr[i]); i++);
+    }
+    return (i >= N);
+}
+
+
+//*****************************************************************************
+// Class to parse a list of simple assembly names and then find a match
+//*****************************************************************************
+
+class AssemblyNamesList
+{
+    struct AssemblyName
+    {
+        LPUTF8          m_assemblyName;
+        AssemblyName   *m_next;         // Next name
+    };
+
+    AssemblyName       *m_pNames;       // List of names
+
+public:
+
+    bool IsInList(LPCUTF8 assemblyName);
+
+    bool IsEmpty()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return m_pNames == 0;
+    }
+
+    AssemblyNamesList(_In_ LPWSTR list);
+    ~AssemblyNamesList();
+};
+
+//*****************************************************************************
+// Class to parse a list of method names and then find a match
+//*****************************************************************************
+
+struct CORINFO_SIG_INFO;
+
+class MethodNamesListBase
+{
+    struct MethodName
+    {
+        LPUTF8      methodName;     // NULL means wildcard
+        LPUTF8      className;      // NULL means wildcard
+        int         numArgs;        // number of args for the method, -1 is wildcard
+        MethodName *next;           // Next name
+    };
+
+    MethodName     *pNames;         // List of names
+
+    bool IsInList(LPCUTF8 methodName, LPCUTF8 className, int numArgs);
+
+public:
+    void Init()
+    {
+        LIMITED_METHOD_CONTRACT;
+        pNames = 0;
+    }
+
+    void Init(_In_ _In_z_ LPWSTR list)
+    {
+        WRAPPER_NO_CONTRACT;
+        pNames = 0;
+        Insert(list);
+    }
+
+    void Destroy();
+
+    void Insert(_In_ _In_z_ LPWSTR list);
+
+    bool IsInList(LPCUTF8 methodName, LPCUTF8 className, PCCOR_SIGNATURE sig = NULL);
+    bool IsInList(LPCUTF8 methodName, LPCUTF8 className, CORINFO_SIG_INFO* pSigInfo);
+    bool IsEmpty()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return pNames == 0;
+    }
+};
+
+class MethodNamesList : public MethodNamesListBase
+{
+public:
+    MethodNamesList()
+    {
+        WRAPPER_NO_CONTRACT;
+        Init();
+    }
+
+    MethodNamesList(_In_ LPWSTR list)
+    {
+        WRAPPER_NO_CONTRACT;
+        Init(list);
+    }
+
+    ~MethodNamesList()
+    {
+        WRAPPER_NO_CONTRACT;
+        Destroy();
+    }
+};
+
+//*****************************************************************************
+// Convert a pointer to a string into a GUID.
+//*****************************************************************************
+HRESULT LPCSTRToGuid(                   // Return status.
+    LPCSTR      szGuid,                 // String to convert.
+    GUID        *psGuid);               // Buffer for converted GUID.
+
+//*****************************************************************************
+// Convert a GUID into a pointer to a string
+//*****************************************************************************
+int GuidToLPWSTR(                  // Return status.
+    GUID        Guid,                  // [IN] The GUID to convert.
+    _Out_writes_ (cchGuid) LPWSTR szGuid, // [OUT] String into which the GUID is stored
+    DWORD       cchGuid);              // [IN] Size in wide chars of szGuid
+
+//*****************************************************************************
+// Parse a Wide char string into a GUID
+//*****************************************************************************
+BOOL LPWSTRToGuid(
+    GUID      * Guid,                         // [OUT] The GUID to fill in
+    _In_reads_(cchGuid)   LPCWSTR szGuid,    // [IN] String to parse
+    DWORD       cchGuid);                     // [IN] Count in wchars in string
+
+typedef VPTR(class RangeList) PTR_RangeList;
+
+class RangeList
+{
+  public:
+    VPTR_BASE_CONCRETE_VTABLE_CLASS(RangeList)
+
+#ifndef DACCESS_COMPILE
+    RangeList();
+    ~RangeList();
+#else
+    RangeList()
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+#endif
+
+    // Wrappers to make the virtual calls DAC-safe.
+    BOOL AddRange(const BYTE *start, const BYTE *end, void *id)
+    {
+        return this->AddRangeWorker(start, end, id);
+    }
+
+    void RemoveRanges(void *id, const BYTE *start = NULL, const BYTE *end = NULL)
+    {
+        return this->RemoveRangesWorker(id, start, end);
+    }
+
+    BOOL IsInRange(TADDR address, TADDR *pID = NULL)
+    {
+        SUPPORTS_DAC;
+
+        return this->IsInRangeWorker(address, pID);
+    }
+
+#ifndef DACCESS_COMPILE
+
+    // You can overload these two for synchronization (as LockedRangeList does)
+    virtual BOOL AddRangeWorker(const BYTE *start, const BYTE *end, void *id);
+    // If both "start" and "end" are NULL, then this method deletes all ranges with
+    // the given id (i.e. the original behaviour).  Otherwise, it ignores the given
+    // id and deletes all ranges falling in the region [start, end).
+    virtual void RemoveRangesWorker(void *id, const BYTE *start = NULL, const BYTE *end = NULL);
+#else
+    virtual BOOL AddRangeWorker(const BYTE *start, const BYTE *end, void *id)
+    {
+        return TRUE;
+    }
+    virtual void RemoveRangesWorker(void *id, const BYTE *start = NULL, const BYTE *end = NULL) { }
+#endif // !DACCESS_COMPILE
+
+    virtual BOOL IsInRangeWorker(TADDR address, TADDR *pID = NULL);
+
+#ifdef DACCESS_COMPILE
+    void EnumMemoryRegions(enum CLRDataEnumMemoryFlags flags);
+#endif
+
+    enum
+    {
+        RANGE_COUNT = 10
+    };
+
+
+  private:
+    struct Range
+    {
+        TADDR start;
+        TADDR end;
+        TADDR id;
+    };
+
+    struct RangeListBlock
+    {
+        Range                ranges[RANGE_COUNT];
+        DPTR(RangeListBlock) next;
+
+#ifdef DACCESS_COMPILE
+        void EnumMemoryRegions(enum CLRDataEnumMemoryFlags flags);
+#endif
+
+    };
+
+    void InitBlock(RangeListBlock *block);
+
+    RangeListBlock       m_starterBlock;
+    DPTR(RangeListBlock) m_firstEmptyBlock;
+    TADDR                m_firstEmptyRange;
+};
+
+
+//
+// A private function to do the equavilent of a CoCreateInstance in
+// cases where we can't make the real call. Use this when, for
+// instance, you need to create a symbol reader in the Runtime but
+// we're not CoInitialized. Obviously, this is only good for COM
+// objects for which CoCreateInstance is just a glorified
+// find-and-load-me operation.
+//
+
+HRESULT FakeCoCreateInstanceEx(REFCLSID       rclsid,
+                               LPCWSTR        wszDllPath,
+                               REFIID         riid,
+                               void **        ppv,
+                               HMODULE *      phmodDll);
+
+// Provided for backward compatibility and for code that doesn't need the HMODULE of the
+// DLL that was loaded to create the COM object.  See comment at implementation of
+// code:FakeCoCreateInstanceEx for more details.
+inline HRESULT FakeCoCreateInstance(REFCLSID   rclsid,
+                                    REFIID     riid,
+                                    void **    ppv)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    return FakeCoCreateInstanceEx(rclsid, NULL, riid, ppv, NULL);
+};
+
+//*****************************************************************************
+// Gets the directory based on the location of the module. This routine
+// is called at COR setup time. Set is called during EEStartup and by the
+// MetaData dispenser.
+//*****************************************************************************
+HRESULT GetInternalSystemDirectory(_Out_writes_to_opt_(*pdwLength,*pdwLength) LPWSTR buffer, __inout DWORD* pdwLength);
+LPCWSTR GetInternalSystemDirectory(_Out_opt_ DWORD * pdwLength = NULL);
+
+//*****************************************************************************
+// This function validates the given Method/Field/Standalone signature. (util.cpp)
+//*****************************************************************************
+struct IMDInternalImport;
+HRESULT validateTokenSig(
+    mdToken             tk,                     // [IN] Token whose signature needs to be validated.
+    PCCOR_SIGNATURE     pbSig,                  // [IN] Signature.
+    ULONG               cbSig,                  // [IN] Size in bytes of the signature.
+    DWORD               dwFlags,                // [IN] Method flags.
+    IMDInternalImport*  pImport);               // [IN] Internal MD Import interface ptr
+
+//*****************************************************************************
+// Determine the version number of the runtime that was used to build the
+// specified image. The pMetadata pointer passed in is the pointer to the
+// metadata contained in the image.
+//*****************************************************************************
+HRESULT GetImageRuntimeVersionString(PVOID pMetaData, LPCSTR* pString);
+
+//*****************************************************************************
+// The registry keys and values that contain the information regarding
+// the default registered unmanaged debugger.
+//*****************************************************************************
+
+#define kDebugApplicationsPoliciesKey W("SOFTWARE\\Policies\\Microsoft\\Windows\\Windows Error Reporting\\DebugApplications")
+#define kDebugApplicationsKey  W("SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\DebugApplications")
+
+#define kUnmanagedDebuggerKey W("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug")
+#define kUnmanagedDebuggerValue W("Debugger")
+#define kUnmanagedDebuggerAutoValue W("Auto")
+#define kUnmanagedDebuggerAutoExclusionListKey W("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList")
+
+BOOL GetRegistryLongValue(HKEY    hKeyParent,              // Parent key.
+                          LPCWSTR szKey,                   // Key name to look at.
+                          LPCWSTR szName,                  // Name of value to get.
+                          long    *pValue,                 // Put value here, if found.
+                          BOOL    fReadNonVirtualizedKey); // Whether to read 64-bit hive on WOW64
+
+HRESULT GetCurrentModuleFileName(SString& pBuffer);
+
+//*****************************************************************************
+// Retrieve information regarding what registered default debugger
+//*****************************************************************************
+void GetDebuggerSettingInfo(SString &debuggerKeyValue, BOOL *pfAuto);
+HRESULT GetDebuggerSettingInfoWorker(_Out_writes_to_opt_(*pcchDebuggerString, *pcchDebuggerString) LPWSTR wszDebuggerString, DWORD * pcchDebuggerString, BOOL * pfAuto);
+
+void TrimWhiteSpace(__inout_ecount(*pcch)  LPCWSTR *pwsz, __inout LPDWORD pcch);
+
+
+//*****************************************************************************
+// Convert a UTF8 string to Unicode, into a CQuickArray<WCHAR>.
+//*****************************************************************************
+HRESULT Utf2Quick(
+    LPCUTF8     pStr,                   // The string to convert.
+    CQuickArray<WCHAR> &rStr,           // The QuickArray<WCHAR> to convert it into.
+    int         iCurLen = 0);           // Initial characters in the array to leave (default 0).
+
+//*****************************************************************************
+//  Extract the movl 64-bit unsigned immediate from an IA64 bundle
+//  (Format X2)
+//*****************************************************************************
+UINT64 GetIA64Imm64(UINT64 * pBundle);
+UINT64 GetIA64Imm64(UINT64 qword0, UINT64 qword1);
+
+//*****************************************************************************
+//  Deposit the movl 64-bit unsigned immediate into an IA64 bundle
+//  (Format X2)
+//*****************************************************************************
+void PutIA64Imm64(UINT64 * pBundle, UINT64 imm64);
+
+//*****************************************************************************
+//  Extract the IP-Relative signed 25-bit immediate from an IA64 bundle
+//  (Formats B1, B2 or B3)
+//  Note that due to branch target alignment requirements
+//       the lowest four bits in the result will always be zero.
+//*****************************************************************************
+INT32 GetIA64Rel25(UINT64 * pBundle, UINT32 slot);
+INT32 GetIA64Rel25(UINT64 qword0, UINT64 qword1, UINT32 slot);
+
+//*****************************************************************************
+//  Deposit the IP-Relative signed 25-bit immediate into an IA64 bundle
+//  (Formats B1, B2 or B3)
+//  Note that due to branch target alignment requirements
+//       the lowest four bits are required to be zero.
+//*****************************************************************************
+void PutIA64Rel25(UINT64 * pBundle, UINT32 slot, INT32 imm25);
+
+//*****************************************************************************
+//  Extract the IP-Relative signed 64-bit immediate from an IA64 bundle
+//  (Formats X3 or X4)
+//*****************************************************************************
+INT64 GetIA64Rel64(UINT64 * pBundle);
+INT64 GetIA64Rel64(UINT64 qword0, UINT64 qword1);
+
+//*****************************************************************************
+//  Deposit the IP-Relative signed 64-bit immediate into a IA64 bundle
+//  (Formats X3 or X4)
+//*****************************************************************************
+void PutIA64Rel64(UINT64 * pBundle, INT64 imm64);
+
+//*****************************************************************************
+//  Extract the 32-bit immediate from movw/movt Thumb2 sequence
+//*****************************************************************************
+UINT32 GetThumb2Mov32(UINT16 * p);
+
+//*****************************************************************************
+//  Deposit the 32-bit immediate into movw/movt Thumb2 sequence
+//*****************************************************************************
+void PutThumb2Mov32(UINT16 * p, UINT32 imm32);
+
+//*****************************************************************************
+//  Extract the 24-bit rel offset from bl instruction
+//*****************************************************************************
+INT32 GetThumb2BlRel24(UINT16 * p);
+
+//*****************************************************************************
+//  Extract the 24-bit rel offset from bl instruction
+//*****************************************************************************
+void PutThumb2BlRel24(UINT16 * p, INT32 imm24);
+
+//*****************************************************************************
+//  Extract the PC-Relative offset from a b or bl instruction
+//*****************************************************************************
+INT32 GetArm64Rel28(UINT32 * pCode);
+
+//*****************************************************************************
+//  Extract the PC-Relative page address from an adrp instruction
+//*****************************************************************************
+INT32 GetArm64Rel21(UINT32 * pCode);
+
+//*****************************************************************************
+//  Extract the page offset from an add instruction
+//*****************************************************************************
+INT32 GetArm64Rel12(UINT32 * pCode);
+
+//*****************************************************************************
+//  Deposit the PC-Relative offset 'imm28' into a b or bl instruction
+//*****************************************************************************
+void PutArm64Rel28(UINT32 * pCode, INT32 imm28);
+
+//*****************************************************************************
+//  Deposit the PC-Relative page address 'imm21' into an adrp instruction
+//*****************************************************************************
+void PutArm64Rel21(UINT32 * pCode, INT32 imm21);
+
+//*****************************************************************************
+//  Deposit the page offset 'imm12' into an add instruction
+//*****************************************************************************
+void PutArm64Rel12(UINT32 * pCode, INT32 imm12);
+
+//*****************************************************************************
+// Returns whether the offset fits into bl instruction
+//*****************************************************************************
+inline bool FitsInThumb2BlRel24(INT32 imm24)
+{
+    return ((imm24 << 7) >> 7) == imm24;
+}
+
+//*****************************************************************************
+// Returns whether the offset fits into an Arm64 b or bl instruction
+//*****************************************************************************
+inline bool FitsInRel28(INT32 val32)
+{
+    return (val32 >= -0x08000000) && (val32 < 0x08000000);
+}
+
+//*****************************************************************************
+// Returns whether the offset fits into an Arm64 adrp instruction
+//*****************************************************************************
+inline bool FitsInRel21(INT32 val32)
+{
+    return (val32 >= 0) && (val32 <= 0x001FFFFF);
+}
+
+//*****************************************************************************
+// Returns whether the offset fits into an Arm64 add instruction
+//*****************************************************************************
+inline bool FitsInRel12(INT32 val32)
+{
+    return (val32 >= 0) && (val32 <= 0x00000FFF);
+}
+
+//*****************************************************************************
+// Returns whether the offset fits into an Arm64 b or bl instruction
+//*****************************************************************************
+inline bool FitsInRel28(INT64 val64)
+{
+    return (val64 >= -0x08000000LL) && (val64 < 0x08000000LL);
+}
+
+#if !defined(DACCESS_COMPILE)
+
+extern thread_local size_t t_ThreadType;
+
+// check if current thread is a GC thread (concurrent or server)
+inline BOOL IsGCSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+
+    return !!(t_ThreadType & ThreadType_GC);
+}
+
+// check if current thread is a Gate thread
+inline BOOL IsGateSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_Gate);
+}
+
+// check if current thread is a Timer thread
+inline BOOL IsTimerSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_Timer);
+}
+
+// check if current thread is a debugger helper thread
+inline BOOL IsDbgHelperSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_DbgHelper);
+}
+
+// check if current thread is a debugger helper thread
+inline BOOL IsETWRundownSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_ETWRundownThread);
+}
+
+// check if current thread is a generic instantiation lookup compare thread
+inline BOOL IsGenericInstantiationLookupCompareThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_GenericInstantiationCompare);
+}
+
+// check if current thread is a thread which is performing shutdown
+inline BOOL IsShutdownSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_Shutdown);
+}
+
+inline BOOL IsThreadPoolIOCompletionSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_Threadpool_IOCompletion);
+}
+
+inline BOOL IsThreadPoolWorkerSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_Threadpool_Worker);
+}
+
+inline BOOL IsWaitSpecialThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_Wait);
+}
+
+// check if current thread is a thread which is performing shutdown
+inline BOOL IsSuspendEEThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_DynamicSuspendEE);
+}
+
+inline BOOL IsFinalizerThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_Finalizer);
+}
+
+inline BOOL IsShutdownHelperThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_ShutdownHelper);
+}
+
+inline BOOL IsProfilerAttachThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+
+    return !!(t_ThreadType & ThreadType_ProfAPI_Attach);
+}
+
+// set special type for current thread
+void ClrFlsSetThreadType(TlsThreadTypeFlag flag);
+void ClrFlsClearThreadType(TlsThreadTypeFlag flag);
+
+#endif //!DACCESS_COMPILE
+
+HRESULT SetThreadName(HANDLE hThread, PCWSTR lpThreadDescription);
+
+inline BOOL IsGCThread ()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_MODE_ANY;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+
+#if !defined(DACCESS_COMPILE)
+    return IsGCSpecialThread () || IsSuspendEEThread ();
+#else
+    return FALSE;
+#endif
+}
+
+class ClrFlsThreadTypeSwitch
+{
+public:
+    ClrFlsThreadTypeSwitch (TlsThreadTypeFlag flag)
+    {
+        STATIC_CONTRACT_NOTHROW;
+        STATIC_CONTRACT_GC_NOTRIGGER;
+        STATIC_CONTRACT_MODE_ANY;
+
+#ifndef DACCESS_COMPILE
+        m_flag = flag;
+        m_fPreviouslySet = (t_ThreadType & flag);
+
+        // In debug builds, remember the full group of flags that were set at the time
+        // the constructor was called.  This will be used in ASSERTs in the destructor
+        INDEBUG(m_nPreviousFlagGroup = t_ThreadType);
+
+        if (!m_fPreviouslySet)
+        {
+            ClrFlsSetThreadType(flag);
+        }
+#endif // DACCESS_COMPILE
+    }
+
+    ~ClrFlsThreadTypeSwitch ()
+    {
+        STATIC_CONTRACT_NOTHROW;
+        STATIC_CONTRACT_GC_NOTRIGGER;
+        STATIC_CONTRACT_MODE_ANY;
+
+#ifndef DACCESS_COMPILE
+        // This holder should only be used to set (and thus restore) ONE thread type flag
+        // at a time. If more than that one flag was modified since this holder was
+        // instantiated, then this holder still restores only the flag it knows about. To
+        // prevent confusion, assert if some other flag was modified, so the user doesn't
+        // expect the holder to restore the entire original set of flags.
+        //
+        // The expression below says that the only difference between the previous flag
+        // group and the current flag group should be m_flag (or no difference at all, if
+        // m_flag's state didn't actually change).
+        _ASSERTE(((m_nPreviousFlagGroup ^ t_ThreadType) | (size_t) m_flag) == (size_t) m_flag);
+
+        if (m_fPreviouslySet)
+        {
+            ClrFlsSetThreadType(m_flag);
+        }
+        else
+        {
+            ClrFlsClearThreadType(m_flag);
+        }
+#endif // DACCESS_COMPILE
+    }
+
+private:
+    TlsThreadTypeFlag m_flag;
+    BOOL m_fPreviouslySet;
+    INDEBUG(size_t m_nPreviousFlagGroup);
+};
+
+//*********************************************************************************
+
+#include "contract.inl"
+
+namespace util
+{
+    //  compare adapters
+    //
+
+    template < typename T >
+    struct less
+    {
+        bool operator()( T const & first, T const & second ) const
+        {
+            return first < second;
+        }
+    };
+
+    template < typename T >
+    struct greater
+    {
+        bool operator()( T const & first, T const & second ) const
+        {
+            return first > second;
+        }
+    };
+
+
+    //  sort adapters
+    //
+
+    template< typename Iter, typename Pred >
+    void sort( Iter begin, Iter end, Pred pred );
+
+    template< typename T, typename Pred >
+    void sort( T * begin, T * end, Pred pred )
+    {
+        struct sort_helper : CQuickSort< T >
+        {
+            sort_helper( T * begin, T * end, Pred pred )
+                : CQuickSort< T >( begin, end - begin )
+                , m_pred( pred )
+            {}
+
+            virtual int Compare( T * first, T * second )
+            {
+                return m_pred( *first, *second ) ? -1
+                            : ( m_pred( *second, *first ) ? 1 : 0 );
+            }
+
+            Pred m_pred;
+        };
+
+        sort_helper sort_obj( begin, end, pred );
+        sort_obj.Sort();
+    }
+
+
+    template < typename Iter >
+    void sort( Iter begin, Iter end );
+
+    template < typename T >
+    void sort( T * begin, T * end )
+    {
+        util::sort( begin, end, util::less< T >() );
+    }
+
+
+    // binary search adapters
+    //
+
+    template < typename Iter, typename T, typename Pred >
+    Iter lower_bound( Iter begin, Iter end, T const & val, Pred pred );
+
+    template < typename T, typename Pred >
+    T * lower_bound( T * begin, T * end, T const & val, Pred pred )
+    {
+        for (; begin != end; )
+        {
+            T * mid = begin + ( end - begin ) / 2;
+            if ( pred( *mid, val ) )
+                begin = ++mid;
+            else
+                end = mid;
+        }
+
+        return begin;
+    }
+
+
+    template < typename Iter, typename T >
+    Iter lower_bound( Iter begin, Iter end, T const & val );
+
+    template < typename T >
+    T * lower_bound( T * begin, T * end, T const & val )
+    {
+        return util::lower_bound( begin, end, val, util::less< T >() );
+    }
+}
+
+
+/* ------------------------------------------------------------------------ *
+ * Overloaded operators for the executable heap
+ * ------------------------------------------------------------------------ */
+
+#ifdef HOST_WINDOWS
+
+struct CExecutable { int x; };
+extern const CExecutable executable;
+
+void * __cdecl operator new(size_t n, const CExecutable&);
+void * __cdecl operator new[](size_t n, const CExecutable&);
+void * __cdecl operator new(size_t n, const CExecutable&, const NoThrow&);
+void * __cdecl operator new[](size_t n, const CExecutable&, const NoThrow&);
+
+
+//
+// Executable heap delete to match the executable heap new above.
+//
+template<class T> void DeleteExecutable(T *p)
+{
+    if (p != NULL)
+    {
+        p->T::~T();
+
+        HeapFree(ClrGetProcessExecutableHeap(), 0, p);
+    }
+}
+
+#endif // HOST_WINDOWS
+
+BOOL NoGuiOnAssert();
+#ifdef _DEBUG
+VOID TerminateOnAssert();
+#endif // _DEBUG
+
+
+BOOL ThreadWillCreateGuardPage(SIZE_T sizeReservedStack, SIZE_T sizeCommitedStack);
+
+FORCEINLINE void HolderSysFreeString(BSTR str) { CONTRACT_VIOLATION(ThrowsViolation); SysFreeString(str); }
+
+typedef Wrapper<BSTR, DoNothing, HolderSysFreeString> BSTRHolder;
+
+BOOL IsIPInModule(PTR_VOID pModuleBaseAddress, PCODE ip);
+
+namespace UtilCode
+{
+    // These are type-safe versions of Interlocked[Compare]Exchange
+    // They avoid invoking struct cast operations via reinterpreting
+    // the struct's address as a LONG* or LONGLONG* and dereferencing it.
+    //
+    // If we had a global ::operator & (unary), we would love to use that
+    // to ensure we were not also accidentally getting a structs's provided
+    // operator &. TODO: probe with a static_assert?
+
+    template <typename T, int SIZE = sizeof(T)>
+    struct InterlockedCompareExchangeHelper;
+
+    template <typename T>
+    struct InterlockedCompareExchangeHelper<T, sizeof(LONG)>
+    {
+        static inline T InterlockedExchange(
+            T volatile * target,
+            T            value)
+        {
+            static_assert_no_msg(sizeof(T) == sizeof(LONG));
+            LONG res = ::InterlockedExchange(
+                reinterpret_cast<LONG volatile *>(target),
+                *reinterpret_cast<LONG *>(/*::operator*/&(value)));
+            return *reinterpret_cast<T*>(&res);
+        }
+
+        static inline T InterlockedCompareExchange(
+            T volatile * destination,
+            T            exchange,
+            T            comparand)
+        {
+            static_assert_no_msg(sizeof(T) == sizeof(LONG));
+            LONG res = ::InterlockedCompareExchange(
+                reinterpret_cast<LONG volatile *>(destination),
+                *reinterpret_cast<LONG*>(/*::operator*/&(exchange)),
+                *reinterpret_cast<LONG*>(/*::operator*/&(comparand)));
+            return *reinterpret_cast<T*>(&res);
+        }
+    };
+
+    template <typename T>
+    struct InterlockedCompareExchangeHelper<T, sizeof(LONGLONG)>
+    {
+        static inline T InterlockedExchange(
+            T volatile * target,
+            T            value)
+        {
+            static_assert_no_msg(sizeof(T) == sizeof(LONGLONG));
+            LONGLONG res = ::InterlockedExchange64(
+                reinterpret_cast<LONGLONG volatile *>(target),
+                *reinterpret_cast<LONGLONG *>(/*::operator*/&(value)));
+            return *reinterpret_cast<T*>(&res);
+        }
+
+        static inline T InterlockedCompareExchange(
+            T volatile * destination,
+            T            exchange,
+            T            comparand)
+        {
+            static_assert_no_msg(sizeof(T) == sizeof(LONGLONG));
+            LONGLONG res = ::InterlockedCompareExchange64(
+                reinterpret_cast<LONGLONG volatile *>(destination),
+                *reinterpret_cast<LONGLONG*>(/*::operator*/&(exchange)),
+                *reinterpret_cast<LONGLONG*>(/*::operator*/&(comparand)));
+            return *reinterpret_cast<T*>(&res);
+        }
+    };
+}
+
+template <typename T>
+inline T InterlockedExchangeT(
+    T volatile * target,
+    T            value)
+{
+    return ::UtilCode::InterlockedCompareExchangeHelper<T>::InterlockedExchange(
+        target, value);
+}
+
+template <typename T>
+inline T InterlockedCompareExchangeT(
+    T volatile * destination,
+    T            exchange,
+    T            comparand)
+{
+    return ::UtilCode::InterlockedCompareExchangeHelper<T>::InterlockedCompareExchange(
+        destination, exchange, comparand);
+}
+
+// Pointer variants for Interlocked[Compare]ExchangePointer
+// If the underlying type is a const type, we have to remove its constness
+// since Interlocked[Compare]ExchangePointer doesn't take const void * arguments.
+template <typename T>
+inline T* InterlockedExchangeT(
+    T* volatile * target,
+    T*            value)
+{
+    //STATIC_ASSERT(value == 0);
+    typedef typename std::remove_const<T>::type * non_const_ptr_t;
+    return reinterpret_cast<T*>(InterlockedExchangePointer(
+        reinterpret_cast<PVOID volatile *>(const_cast<non_const_ptr_t volatile *>(target)),
+        reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(value))));
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+    T* volatile * destination,
+    T*            exchange,
+    T*            comparand)
+{
+    //STATIC_ASSERT(exchange == 0);
+    typedef typename std::remove_const<T>::type * non_const_ptr_t;
+    return reinterpret_cast<T*>(InterlockedCompareExchangePointer(
+        reinterpret_cast<PVOID volatile *>(const_cast<non_const_ptr_t volatile *>(destination)),
+        reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(exchange)),
+        reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(comparand))));
+}
+
+// NULL pointer variants of the above to avoid having to cast NULL
+// to the appropriate pointer type.
+template <typename T>
+inline T* InterlockedExchangeT(
+    T* volatile *  target,
+    std::nullptr_t value) // When nullptr is provided as argument.
+{
+    //STATIC_ASSERT(value == 0);
+    return InterlockedExchangeT(target, static_cast<T*>(value));
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+    T* volatile *  destination,
+    std::nullptr_t exchange,  // When nullptr is provided as argument.
+    T*             comparand)
+{
+    //STATIC_ASSERT(exchange == 0);
+    return InterlockedCompareExchangeT(destination, static_cast<T*>(exchange), comparand);
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+    T* volatile *  destination,
+    T*             exchange,
+    std::nullptr_t comparand) // When nullptr is provided as argument.
+{
+    //STATIC_ASSERT(comparand == 0);
+    return InterlockedCompareExchangeT(destination, exchange, static_cast<T*>(comparand));
+}
+
+// NULL pointer variants of the above to avoid having to cast NULL
+// to the appropriate pointer type.
+template <typename T>
+inline T* InterlockedExchangeT(
+    T* volatile *   target,
+    int             value) // When NULL is provided as argument.
+{
+    //STATIC_ASSERT(value == 0);
+    return InterlockedExchangeT(target, nullptr);
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+    T* volatile *   destination,
+    int             exchange,  // When NULL is provided as argument.
+    T*              comparand)
+{
+    //STATIC_ASSERT(exchange == 0);
+    return InterlockedCompareExchangeT(destination, nullptr, comparand);
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+    T* volatile *   destination,
+    T*              exchange,
+    int             comparand) // When NULL is provided as argument.
+{
+    //STATIC_ASSERT(comparand == 0);
+    return InterlockedCompareExchangeT(destination, exchange, nullptr);
+}
+
+#undef InterlockedExchangePointer
+#define InterlockedExchangePointer Use_InterlockedExchangeT
+#undef InterlockedCompareExchangePointer
+#define InterlockedCompareExchangePointer Use_InterlockedCompareExchangeT
+
+// Returns the directory for clr module. So, if path was for "C:\Dir1\Dir2\Filename.DLL",
+// then this would return "C:\Dir1\Dir2\" (note the trailing backslash).
+HRESULT GetClrModuleDirectory(SString& wszPath);
+HRESULT CopySystemDirectory(const SString& pPathString, SString& pbuffer);
+
+HMODULE LoadLocalizedResourceDLLForSDK(_In_z_ LPCWSTR wzResourceDllName, _In_opt_z_ LPCWSTR modulePath=NULL, bool trySelf=true);
+// This is a slight variation that can be used for anything else
+typedef void* (__cdecl *LocalizedFileHandler)(LPCWSTR);
+void* FindLocalizedFile(_In_z_ LPCWSTR wzResourceDllName, LocalizedFileHandler lfh, _In_opt_z_ LPCWSTR modulePath=NULL);
+
+
+namespace Clr { namespace Util
+{
+
+#ifdef HOST_WINDOWS
+namespace Com
+{
+    HRESULT FindInprocServer32UsingCLSID(REFCLSID rclsid, SString & ssInprocServer32Name);
+}
+#endif // HOST_WINDOWS
+
+}}
+
+inline DWORD GetLoadWithAlteredSearchPathFlag()
+{
+    LIMITED_METHOD_CONTRACT;
+    #ifdef LOAD_WITH_ALTERED_SEARCH_PATH
+        return LOAD_WITH_ALTERED_SEARCH_PATH;
+    #else
+        return 0;
+    #endif
+}
+
+// clr::SafeAddRef and clr::SafeRelease helpers.
+namespace clr
+{
+    //=================================================================================================================
+    template <typename ItfT>
+    static inline
+    typename std::enable_if< std::is_pointer<ItfT>::value, ItfT >::type
+    SafeAddRef(ItfT pItf)
+    {
+        STATIC_CONTRACT_LIMITED_METHOD;
+        if (pItf != nullptr)
+        {
+            pItf->AddRef();
+        }
+        return pItf;
+    }
+
+    //=================================================================================================================
+    template <typename ItfT>
+    typename std::enable_if< std::is_pointer<ItfT>::value && std::is_reference<ItfT>::value, ULONG >::type
+    SafeRelease(ItfT pItf)
+    {
+        STATIC_CONTRACT_LIMITED_METHOD;
+        ULONG res = 0;
+        if (pItf != nullptr)
+        {
+            res = pItf->Release();
+            pItf = nullptr;
+        }
+        return res;
+    }
+
+    //=================================================================================================================
+    template <typename ItfT>
+    typename std::enable_if< std::is_pointer<ItfT>::value && !std::is_reference<ItfT>::value, ULONG >::type
+    SafeRelease(ItfT pItf)
+    {
+        STATIC_CONTRACT_LIMITED_METHOD;
+        ULONG res = 0;
+        if (pItf != nullptr)
+        {
+            res = pItf->Release();
+        }
+        return res;
+    }
+}
+
+// clr::SafeDelete
+namespace clr
+{
+    //=================================================================================================================
+    template <typename PtrT>
+    static inline
+    typename std::enable_if< std::is_pointer<PtrT>::value, PtrT >::type
+    SafeDelete(PtrT & ptr)
+    {
+        STATIC_CONTRACT_LIMITED_METHOD;
+        if (ptr != nullptr)
+        {
+            delete ptr;
+            ptr = nullptr;
+        }
+    }
+}
+
+// ======================================================================================
+// Spinning support (used by VM and by MetaData via file:..\Utilcode\UTSem.cpp)
+
+struct SpinConstants
+{
+    DWORD dwInitialDuration;
+    DWORD dwMaximumDuration;
+    DWORD dwBackoffFactor;
+    DWORD dwRepetitions;
+    DWORD dwMonitorSpinCount;
+};
+
+extern SpinConstants g_SpinConstants;
+
 #endif // __UtilCode_h__
index 610a408f39fb6e3660be53f9fd5e11f1803b3737..e127fe25f99b1f6eff6e6bf8da0b8f4699d033c1 100644 (file)
 #endif
 
 #if defined(__GNUC__)
-#if defined(HOST_ARM) || defined(HOST_ARM64)
+#if defined(HOST_ARMV6)
+// DMB ISH not valid on ARMv6
+#define VOLATILE_MEMORY_BARRIER() asm volatile ("mcr p15, 0, r0, c7, c10, 5" : : : "memory")
+#elif defined(HOST_ARM) || defined(HOST_ARM64)
 // This is functionally equivalent to the MemoryBarrier() macro used on ARM on Windows.
 #define VOLATILE_MEMORY_BARRIER() asm volatile ("dmb ish" : : : "memory")
 #else
diff --git a/src/inc/win64unwind.h b/src/inc/win64unwind.h
new file mode 100644 (file)
index 0000000..d9990a3
--- /dev/null
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef _WIN64UNWIND_H_
+#define _WIN64UNWIND_H_
+
+//
+// Define AMD64 exception handling structures and function prototypes.
+//
+// Define unwind operation codes.
+//
+
+typedef enum _UNWIND_OP_CODES {
+    UWOP_PUSH_NONVOL = 0,
+    UWOP_ALLOC_LARGE,
+    UWOP_ALLOC_SMALL,
+    UWOP_SET_FPREG,
+    UWOP_SAVE_NONVOL,
+    UWOP_SAVE_NONVOL_FAR,
+    UWOP_EPILOG,
+    UWOP_SPARE_CODE,
+    UWOP_SAVE_XMM128,
+    UWOP_SAVE_XMM128_FAR,
+    UWOP_PUSH_MACHFRAME,
+
+#ifdef TARGET_UNIX
+    // UWOP_SET_FPREG_LARGE is a CLR Unix-only extension to the Windows AMD64 unwind codes.
+    // It is not part of the standard Windows AMD64 unwind codes specification.
+    // UWOP_SET_FPREG allows for a maximum of a 240 byte offset between RSP and the
+    // frame pointer, when the frame pointer is established. UWOP_SET_FPREG_LARGE
+    // has a 32-bit range scaled by 16. When UWOP_SET_FPREG_LARGE is used,
+    // UNWIND_INFO.FrameRegister must be set to the frame pointer register, and
+    // UNWIND_INFO.FrameOffset must be set to 15 (its maximum value). UWOP_SET_FPREG_LARGE
+    // is followed by two UNWIND_CODEs that are combined to form a 32-bit offset (the same
+    // as UWOP_SAVE_NONVOL_FAR). This offset is then scaled by 16. The result must be less
+    // than 2^32 (that is, the top 4 bits of the unscaled 32-bit number must be zero). This
+    // result is used as the frame pointer register offset from RSP at the time the frame pointer
+    // is established. Either UWOP_SET_FPREG or UWOP_SET_FPREG_LARGE can be used, but not both.
+
+    UWOP_SET_FPREG_LARGE,
+#endif // TARGET_UNIX
+} UNWIND_OP_CODES, *PUNWIND_OP_CODES;
+
+static const UCHAR UnwindOpExtraSlotTable[] = {
+    0,          // UWOP_PUSH_NONVOL
+    1,          // UWOP_ALLOC_LARGE (or 3, special cased in lookup code)
+    0,          // UWOP_ALLOC_SMALL
+    0,          // UWOP_SET_FPREG
+    1,          // UWOP_SAVE_NONVOL
+    2,          // UWOP_SAVE_NONVOL_FAR
+    1,          // UWOP_EPILOG
+    2,          // UWOP_SPARE_CODE      // previously 64-bit UWOP_SAVE_XMM_FAR
+    1,          // UWOP_SAVE_XMM128
+    2,          // UWOP_SAVE_XMM128_FAR
+    0,          // UWOP_PUSH_MACHFRAME
+
+#ifdef TARGET_UNIX
+    2,          // UWOP_SET_FPREG_LARGE
+#endif // TARGET_UNIX
+};
+
+//
+// Define unwind code structure.
+//
+
+typedef union _UNWIND_CODE {
+    struct {
+        UCHAR CodeOffset;
+        UCHAR UnwindOp : 4;
+        UCHAR OpInfo : 4;
+    };
+
+    struct {
+        UCHAR OffsetLow;
+        UCHAR UnwindOp : 4;
+        UCHAR OffsetHigh : 4;
+    } EpilogueCode;
+
+    USHORT FrameOffset;
+} UNWIND_CODE, *PUNWIND_CODE;
+
+//
+// Define unwind information flags.
+//
+
+#define UNW_FLAG_NHANDLER 0x0
+#define UNW_FLAG_EHANDLER 0x1
+#define UNW_FLAG_UHANDLER 0x2
+#define UNW_FLAG_CHAININFO 0x4
+
+#ifdef TARGET_X86
+
+typedef struct _UNWIND_INFO {
+    ULONG FunctionLength;
+} UNWIND_INFO, *PUNWIND_INFO;
+
+#else // TARGET_X86
+
+typedef struct _UNWIND_INFO {
+    UCHAR Version : 3;
+    UCHAR Flags : 5;
+    UCHAR SizeOfProlog;
+    UCHAR CountOfUnwindCodes;
+    UCHAR FrameRegister : 4;
+    UCHAR FrameOffset : 4;
+    UNWIND_CODE UnwindCode[1];
+
+//
+// The unwind codes are followed by an optional DWORD aligned field that
+// contains the exception handler address or the address of chained unwind
+// information. If an exception handler address is specified, then it is
+// followed by the language specified exception handler data.
+//
+//  union {
+//      ULONG ExceptionHandler;
+//      ULONG FunctionEntry;
+//  };
+//
+//  ULONG ExceptionData[];
+//
+
+} UNWIND_INFO, *PUNWIND_INFO;
+
+#endif // TARGET_X86
+#endif // _WIN64UNWIND_H_
diff --git a/src/inc/winwrap.h b/src/inc/winwrap.h
new file mode 100644 (file)
index 0000000..3bf11ba
--- /dev/null
@@ -0,0 +1,491 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// WinWrap.h
+//
+// This file contains wrapper functions for Win32 API's that take strings.
+//
+// The Common Language Runtime internally uses UNICODE as the internal state
+// and string format.  This file will undef the mapping macros so that one
+// cannot mistakingly call a method that isn't going to work.  Instead, you
+// have to call the correct wrapper API.
+//
+//*****************************************************************************
+
+#ifndef __WIN_WRAP_H__
+#define __WIN_WRAP_H__
+
+//********** Macros. **********************************************************
+#if !defined(WIN32_LEAN_AND_MEAN)
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+//
+// WinCE uniformly uses cdecl calling convention on x86. __stdcall is defined as __cdecl in SDK.
+// STDCALL macro is meant to be used where we have hard dependency on __stdcall calling convention
+// - the unification with __cdecl does not apply to STDCALL.
+//
+#define STDCALL _stdcall
+
+//********** Includes. ********************************************************
+
+#include <crtwrap.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <specstrings.h>
+
+#include "registrywrapper.h"
+#include "longfilepathwrappers.h"
+
+#if defined(_PREFAST_) || defined(SOURCE_FORMATTING)
+//
+// For PREFAST we don't want the C_ASSERT to be expanded since it always
+// involves the comparison of two constants which causes PREfast warning 326
+//
+#undef C_ASSERT
+#define C_ASSERT(expr)
+#endif
+
+#include "palclr.h"
+
+#if !defined(__TODO_PORT_TO_WRAPPERS__)
+//*****************************************************************************
+// Undefine all of the windows wrappers so you can't use them.
+//*****************************************************************************
+
+// winbase.h
+#undef GetBinaryType
+#undef GetShortPathName
+#undef GetEnvironmentStrings
+#undef FreeEnvironmentStrings
+#undef FormatMessage
+#undef lstrcmp
+#undef lstrcmpi
+#undef lstrcpyn
+#undef lstrlen
+#undef CreateMutex
+#undef OpenMutex
+#undef CreateEvent
+#undef OpenEvent
+#undef CreateSemaphore
+#undef OpenSemaphore
+#undef CreateWaitableTimer
+#undef CreateFileMapping
+#undef OpenFileMapping
+#undef LoadLibrary
+#undef LoadLibraryEx
+#undef GetModuleFileName
+#undef GetModuleHandle
+#undef GetModuleHandleEx
+#undef CreateProcess
+#undef GetCommandLine
+#undef GetEnvironmentVariable
+#undef SetEnvironmentVariable
+#undef ExpandEnvironmentStrings
+#undef OutputDebugString
+#undef FindResource
+#undef FindResourceEx
+#undef BeginUpdateResource
+#undef UpdateResource
+#undef EndUpdateResource
+#undef GetPrivateProfileInt
+#undef GetSystemDirectory
+#undef GetTempPath
+#undef GetTempFileName
+#undef GetCurrentDirectory
+#undef GetFullPathName
+#undef CreateFile
+#undef GetFileAttributes
+#undef GetFileAttributesEx
+#undef DeleteFile
+#undef FindFirstFileEx
+#undef FindFirstFile
+#undef FindNextFile
+#undef CopyFile
+#undef CopyFileEx
+#undef MoveFile
+#undef MoveFileEx
+#undef CreateHardLink
+#undef CreateNamedPipe
+#undef WaitNamedPipe
+#undef LookupPrivilegeValue
+#undef GetVersionEx
+
+// winuser.h
+#undef MAKEINTRESOURCE
+#undef GetUserObjectInformation
+#undef GetMessage
+
+#undef SendMessage
+#undef CharLower
+#undef MessageBox
+#undef GetClassName
+#undef LoadString
+#undef GetCalendarInfo
+#undef GetDateFormat
+#undef GetTimeFormat
+#undef LCMapString
+
+#endif // !defined(__TODO_PORT_TO_WRAPPERS__)
+
+//
+// NT supports the wide entry points.  So we redefine the wrappers right back
+// to the *W entry points as macros.  This way no client code needs a wrapper on NT.
+//
+
+// winbase.h
+#define WszFormatMessage   FormatMessageW
+#define Wszlstrcmp   lstrcmpW
+#define Wszlstrcmpi   lstrcmpiW
+#define WszCreateMutex CreateMutexW
+#define WszOpenMutex OpenMutexW
+#define WszCreateEvent CreateEventW
+#define WszOpenEvent OpenEventW
+#define WszCreateWaitableTimer CreateWaitableTimerW
+#define WszCreateFileMapping CreateFileMappingW
+#define WszOpenFileMapping OpenFileMappingW
+#define WszGetModuleHandle GetModuleHandleW
+#define WszGetModuleHandleEx GetModuleHandleExW
+#define WszGetCommandLine GetCommandLineW
+#define WszSetEnvironmentVariable SetEnvironmentVariableW
+#define WszExpandEnvironmentStrings ExpandEnvironmentStringsW
+#define WszOutputDebugString OutputDebugStringW
+#define WszFindResource FindResourceW
+#define WszFindResourceEx FindResourceExW
+#define WszBeginUpdateResource BeginUpdateResourceW
+#define WszUpdateResource UpdateResourceW
+#define WszEndUpdateResource EndUpdateResourceW
+#define WszGetPrivateProfileInt GetPrivateProfileIntW
+#define WszGetSystemDirectory GetSystemDirectoryW
+#define WszCreateNamedPipe CreateNamedPipeW
+#define WszWaitNamedPipe WaitNamedPipeW
+#define WszLookupPrivilegeValue LookupPrivilegeValueW
+
+// winuser.h
+#define WszMAKEINTRESOURCE MAKEINTRESOURCEW
+#define WszGetUserObjectInformation GetUserObjectInformationW
+#define WszGetMessage GetMessageW
+#define WszSendMessage SendMessageW
+#define WszCharLower CharLowerW
+#define WszMessageBox LateboundMessageBoxW
+#define WszGetClassName GetClassNameW
+#define WszLoadString LoadStringW
+#define WszRegOpenKeyEx ClrRegOpenKeyEx
+#define WszRegOpenKey(hKey, wszSubKey, phkRes) ClrRegOpenKeyEx(hKey, wszSubKey, 0, KEY_ALL_ACCESS, phkRes)
+#define WszRegQueryValue RegQueryValueW
+#define WszRegQueryValueEx RegQueryValueExW
+#define WszRegQueryValueExTrue RegQueryValueExW
+#define WszRegQueryStringValueEx RegQueryValueExW
+
+#define WszRegQueryInfoKey RegQueryInfoKeyW
+#define WszRegEnumValue RegEnumValueW
+#define WszRegEnumKeyEx RegEnumKeyExW
+#define WszGetCalendarInfo GetCalendarInfoW
+#define WszGetDateFormat GetDateFormatW
+#define WszGetTimeFormat GetTimeFormatW
+#define WszLCMapString LCMapStringW
+#define WszMultiByteToWideChar MultiByteToWideChar
+#define WszWideCharToMultiByte WideCharToMultiByte
+#define WszCreateSemaphore(_secattr, _count, _maxcount, _name) CreateSemaphoreExW((_secattr), (_count), (_maxcount), (_name), 0, MAXIMUM_ALLOWED | SYNCHRONIZE | SEMAPHORE_MODIFY_STATE)
+
+#ifdef FEATURE_CORESYSTEM
+
+// CoreSystem has GetFileVersionInfo{Size}Ex but not GetFileVersionInfoSize{Size}
+#undef GetFileVersionInfo
+#define GetFileVersionInfo(_filename, _handle, _len, _data) GetFileVersionInfoEx(0, (_filename), (_handle), (_len), (_data))
+#undef GetFileVersionInfoSize
+#define GetFileVersionInfoSize(_filename, _handle) GetFileVersionInfoSizeEx(0, (_filename), (_handle))
+
+#endif // FEATURE_CORESYSTEM
+
+#ifndef _T
+#define _T(str) W(str)
+#endif
+
+//File and Directory Functions which need special handling for LongFile Names
+//Note only the functions which are currently used are defined
+#define WszLoadLibrary         LoadLibraryExWrapper
+#define WszLoadLibraryEx       LoadLibraryExWrapper
+#define WszCreateFile          CreateFileWrapper
+#define WszGetFileAttributes   GetFileAttributesWrapper
+#define WszGetFileAttributesEx GetFileAttributesExWrapper
+#define WszDeleteFile          DeleteFileWrapper
+#define WszFindFirstFileEx     FindFirstFileExWrapper
+#define WszFindNextFile        FindNextFileW
+#define WszMoveFileEx          MoveFileExWrapper
+
+//Can not use extended syntax
+#define WszGetFullPathName     GetFullPathNameW
+
+//Long Files will not work on these till redstone
+#define WszGetCurrentDirectory GetCurrentDirectoryWrapper
+#define WszGetTempFileName     GetTempFileNameWrapper
+#define WszGetTempPath         GetTempPathWrapper
+
+//APIS which have a buffer as an out parameter
+#define WszGetEnvironmentVariable GetEnvironmentVariableWrapper
+#define WszSearchPath          SearchPathWrapper
+#define WszGetModuleFileName   GetModuleFileNameWrapper
+
+//NOTE: IF the following API's are enabled ensure that they can work with LongFile Names
+//See the usage and implementation of above API's
+//
+//#define WszGetBinaryType       GetBinaryTypeWrapper     //Coresys does not seem to have this API
+
+#if HOST_UNIX
+#define WszFindFirstFile     FindFirstFileW
+#else
+#define WszFindFirstFile(_lpFileName_, _lpFindData_)       FindFirstFileExWrapper(_lpFileName_, FindExInfoStandard, _lpFindData_, FindExSearchNameMatch, NULL, 0)
+#endif // HOST_UNIX
+//*****************************************************************************
+// Prototypes for API's.
+//*****************************************************************************
+
+extern DWORD g_dwMaxDBCSCharByteSize;
+
+void EnsureCharSetInfoInitialized();
+
+inline DWORD GetMaxDBCSCharByteSize()
+{
+    // contract.h not visible here
+    __annotation(W("WRAPPER ") W("GetMaxDBCSCharByteSize"));
+#ifndef HOST_UNIX
+    EnsureCharSetInfoInitialized();
+
+    _ASSERTE(g_dwMaxDBCSCharByteSize != 0);
+    return (g_dwMaxDBCSCharByteSize);
+#else // HOST_UNIX
+    return 3;
+#endif // HOST_UNIX
+}
+
+#ifndef HOST_UNIX
+BOOL RunningInteractive();
+#else // !HOST_UNIX
+#define RunningInteractive() FALSE
+#endif // !HOST_UNIX
+
+#ifndef Wsz_mbstowcs
+#define Wsz_mbstowcs(szOut, szIn, iSize) WszMultiByteToWideChar(CP_ACP, 0, szIn, -1, szOut, iSize)
+#endif
+
+#ifndef Wsz_wcstombs
+#define Wsz_wcstombs(szOut, szIn, iSize) WszWideCharToMultiByte(CP_ACP, 0, szIn, -1, szOut, iSize, 0, 0)
+#endif
+
+// For all platforms:
+
+BOOL
+WszCreateProcess(
+    LPCWSTR lpApplicationName,
+    LPCWSTR lpCommandLine,
+    LPSECURITY_ATTRIBUTES lpProcessAttributes,
+    LPSECURITY_ATTRIBUTES lpThreadAttributes,
+    BOOL bInheritHandles,
+    DWORD dwCreationFlags,
+    LPVOID lpEnvironment,
+    LPCWSTR lpCurrentDirectory,
+    LPSTARTUPINFOW lpStartupInfo,
+    LPPROCESS_INFORMATION lpProcessInformation
+    );
+
+#if defined(HOST_X86) && defined(_MSC_VER)
+
+//
+// Windows SDK does not use intrinsics on x86. Redefine the interlocked operations to use intrinsics.
+//
+
+#include "intrin.h"
+
+#define InterlockedIncrement            _InterlockedIncrement
+#define InterlockedDecrement            _InterlockedDecrement
+#define InterlockedExchange             _InterlockedExchange
+#define InterlockedCompareExchange      _InterlockedCompareExchange
+#define InterlockedExchangeAdd          _InterlockedExchangeAdd
+#define InterlockedCompareExchange64    _InterlockedCompareExchange64
+#define InterlockedAnd                  _InterlockedAnd
+#define InterlockedOr                   _InterlockedOr
+
+//
+// There is no _InterlockedCompareExchangePointer intrinsic in VC++ for x86.
+// winbase.h #defines InterlockedCompareExchangePointer as __InlineInterlockedCompareExchangePointer,
+// which calls the Win32 InterlockedCompareExchange, not the intrinsic _InterlockedCompareExchange.
+// We want the intrinsic, so we #undef the Windows version of this API, and define our own.
+//
+#ifdef InterlockedCompareExchangePointer
+#undef InterlockedCompareExchangePointer
+#endif
+
+FORCEINLINE
+PVOID
+InterlockedCompareExchangePointer (
+    __inout  PVOID volatile *Destination,
+    _In_opt_ PVOID ExChange,
+    _In_opt_ PVOID Comperand
+    )
+{
+    return((PVOID)(LONG_PTR)_InterlockedCompareExchange((LONG volatile *)Destination, (LONG)(LONG_PTR)ExChange, (LONG)(LONG_PTR)Comperand));
+}
+
+#endif // HOST_X86 && _MSC_VER
+
+#if defined(HOST_X86) & !defined(InterlockedIncrement64)
+
+// Interlockedxxx64 that do not have intrinsics are only supported on Windows Server 2003
+// or higher for X86 so define our own portable implementation
+
+#undef InterlockedIncrement64
+#define InterlockedIncrement64          __InterlockedIncrement64
+#undef InterlockedDecrement64
+#define InterlockedDecrement64          __InterlockedDecrement64
+#undef InterlockedExchange64
+#define InterlockedExchange64           __InterlockedExchange64
+#undef InterlockedExchangeAdd64
+#define InterlockedExchangeAdd64        __InterlockedExchangeAdd64
+
+__forceinline LONGLONG __InterlockedIncrement64(LONGLONG volatile *Addend)
+{
+    LONGLONG Old;
+
+    do {
+        Old = *Addend;
+    } while (InterlockedCompareExchange64(Addend,
+                                          Old + 1,
+                                          Old) != Old);
+
+    return Old + 1;
+}
+
+__forceinline LONGLONG __InterlockedDecrement64(LONGLONG volatile *Addend)
+{
+    LONGLONG Old;
+
+    do {
+        Old = *Addend;
+    } while (InterlockedCompareExchange64(Addend,
+                                          Old - 1,
+                                          Old) != Old);
+
+    return Old - 1;
+}
+
+__forceinline LONGLONG __InterlockedExchange64(LONGLONG volatile * Target, LONGLONG Value)
+{
+    LONGLONG Old;
+
+    do {
+        Old = *Target;
+    } while (InterlockedCompareExchange64(Target,
+                                          Value,
+                                          Old) != Old);
+
+    return Old;
+}
+
+__forceinline LONGLONG __InterlockedExchangeAdd64(LONGLONG volatile * Addend, LONGLONG Value)
+{
+    LONGLONG Old;
+
+    do {
+        Old = *Addend;
+    } while (InterlockedCompareExchange64(Addend,
+                                          Old + Value,
+                                          Old) != Old);
+
+    return Old;
+}
+
+#endif // HOST_X86
+
+// Output printf-style formatted text to the debugger if it's present or stdout otherwise.
+inline void DbgWPrintf(const LPCWSTR wszFormat, ...)
+{
+    WCHAR wszBuffer[4096];
+
+    va_list args;
+    va_start(args, wszFormat);
+
+    _vsnwprintf_s(wszBuffer, sizeof(wszBuffer) / sizeof(WCHAR), _TRUNCATE, wszFormat, args);
+
+    va_end(args);
+
+    if (IsDebuggerPresent())
+    {
+        OutputDebugStringW(wszBuffer);
+    }
+    else
+    {
+        fwprintf(stdout, W("%s"), wszBuffer);
+        fflush(stdout);
+    }
+}
+
+typedef int (*MessageBoxWFnPtr)(HWND hWnd,
+                                LPCWSTR lpText,
+                                LPCWSTR lpCaption,
+                                UINT uType);
+
+inline int LateboundMessageBoxW(HWND hWnd,
+                                LPCWSTR lpText,
+                                LPCWSTR lpCaption,
+                                UINT uType)
+{
+#ifndef HOST_UNIX
+    // User32 should exist on all systems where displaying a message box makes sense.
+    HMODULE hGuiExtModule = WszLoadLibrary(W("user32"));
+    if (hGuiExtModule)
+    {
+        int result = IDCANCEL;
+        MessageBoxWFnPtr fnptr = (MessageBoxWFnPtr)GetProcAddress(hGuiExtModule, "MessageBoxW");
+        if (fnptr)
+            result = fnptr(hWnd, lpText, lpCaption, uType);
+
+        FreeLibrary(hGuiExtModule);
+        return result;
+    }
+#endif // !HOST_UNIX
+
+    // No luck. Output the caption and text to the debugger if present or stdout otherwise.
+    if (lpText == NULL)
+        lpText = W("<null>");
+    if (lpCaption == NULL)
+        lpCaption = W("<null>");
+    DbgWPrintf(W("**** MessageBox invoked, title '%s' ****\n"), lpCaption);
+    DbgWPrintf(W("  %s\n"), lpText);
+    DbgWPrintf(W("********\n"));
+    DbgWPrintf(W("\n"));
+
+    // Indicate to the caller that message box was not actually displayed
+    SetLastError(ERROR_NOT_SUPPORTED);
+    return 0;
+}
+
+inline int LateboundMessageBoxA(HWND hWnd,
+                                LPCSTR lpText,
+                                LPCSTR lpCaption,
+                                UINT uType)
+{
+    if (lpText == NULL)
+        lpText = "<null>";
+    if (lpCaption == NULL)
+        lpCaption = "<null>";
+
+    SIZE_T cchText = strlen(lpText) + 1;
+    LPWSTR wszText = (LPWSTR)_alloca(cchText * sizeof(WCHAR));
+    swprintf_s(wszText, cchText, W("%S"), lpText);
+
+    SIZE_T cchCaption = strlen(lpCaption) + 1;
+    LPWSTR wszCaption = (LPWSTR)_alloca(cchCaption * sizeof(WCHAR));
+    swprintf_s(wszCaption, cchCaption, W("%S"), lpCaption);
+
+    return LateboundMessageBoxW(hWnd, wszText, wszCaption, uType);
+}
+
+#if defined(FEATURE_CORESYSTEM)
+
+#define MessageBoxW LateboundMessageBoxW
+#define MessageBoxA LateboundMessageBoxA
+
+#endif // FEATURE_CORESYSTEM
+
+#endif  // __WIN_WRAP_H__
diff --git a/src/inc/yieldprocessornormalized.h b/src/inc/yieldprocessornormalized.h
new file mode 100644 (file)
index 0000000..121e60b
--- /dev/null
@@ -0,0 +1,295 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#pragma once
+
+// Undefine YieldProcessor to encourage using the normalized versions below instead. System_YieldProcessor() can be used where
+// the intention is to use the system-default implementation of YieldProcessor().
+#define HAS_SYSTEM_YIELDPROCESSOR
+FORCEINLINE void System_YieldProcessor() { YieldProcessor(); }
+#ifdef YieldProcessor
+#undef YieldProcessor
+#endif
+#define YieldProcessor Dont_Use_YieldProcessor
+
+#define DISABLE_COPY(T) \
+    T(const T &) = delete; \
+    T &operator =(const T &) = delete
+
+#define DISABLE_CONSTRUCT_COPY(T) \
+    T() = delete; \
+    DISABLE_COPY(T)
+
+class YieldProcessorNormalization
+{
+public:
+    static const unsigned int TargetNsPerNormalizedYield = 37;
+    static const unsigned int TargetMaxNsPerSpinIteration = 272;
+
+    // These are maximums for the computed values for normalization based their calculation
+    static const unsigned int MaxYieldsPerNormalizedYield = TargetNsPerNormalizedYield * 10;
+    static const unsigned int MaxOptimalMaxNormalizedYieldsPerSpinIteration =
+        TargetMaxNsPerSpinIteration * 3 / (TargetNsPerNormalizedYield * 2) + 1;
+
+private:
+    static bool s_isMeasurementScheduled;
+
+    static unsigned int s_yieldsPerNormalizedYield;
+    static unsigned int s_optimalMaxNormalizedYieldsPerSpinIteration;
+
+public:
+    static bool IsMeasurementScheduled()
+    {
+        return s_isMeasurementScheduled;
+    }
+
+    static void PerformMeasurement();
+
+private:
+    static void ScheduleMeasurementIfNecessary();
+
+public:
+    static unsigned int GetOptimalMaxNormalizedYieldsPerSpinIteration()
+    {
+        return s_optimalMaxNormalizedYieldsPerSpinIteration;
+    }
+
+    static void FireMeasurementEvents();
+
+private:
+    static double AtomicLoad(double *valueRef);
+    static void AtomicStore(double *valueRef, double value);
+
+    DISABLE_CONSTRUCT_COPY(YieldProcessorNormalization);
+
+    friend class YieldProcessorNormalizationInfo;
+    friend void YieldProcessorNormalizedForPreSkylakeCount(unsigned int);
+};
+
+class YieldProcessorNormalizationInfo
+{
+private:
+    unsigned int yieldsPerNormalizedYield;
+    unsigned int optimalMaxNormalizedYieldsPerSpinIteration;
+    unsigned int optimalMaxYieldsPerSpinIteration;
+
+public:
+    YieldProcessorNormalizationInfo()
+        : yieldsPerNormalizedYield(YieldProcessorNormalization::s_yieldsPerNormalizedYield),
+        optimalMaxNormalizedYieldsPerSpinIteration(YieldProcessorNormalization::s_optimalMaxNormalizedYieldsPerSpinIteration),
+        optimalMaxYieldsPerSpinIteration(yieldsPerNormalizedYield * optimalMaxNormalizedYieldsPerSpinIteration)
+    {
+        YieldProcessorNormalization::ScheduleMeasurementIfNecessary();
+    }
+
+    DISABLE_COPY(YieldProcessorNormalizationInfo);
+
+    friend void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &);
+    friend void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &, unsigned int);
+    friend void YieldProcessorNormalizedForPreSkylakeCount(const YieldProcessorNormalizationInfo &, unsigned int);
+    friend void YieldProcessorWithBackOffNormalized(const YieldProcessorNormalizationInfo &, unsigned int);
+};
+
+// See YieldProcessorNormalized() for preliminary info. Typical usage:
+//     if (!condition)
+//     {
+//         YieldProcessorNormalizationInfo normalizationInfo;
+//         do
+//         {
+//             YieldProcessorNormalized(normalizationInfo);
+//         } while (!condition);
+//     }
+FORCEINLINE void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &normalizationInfo)
+{
+    unsigned int n = normalizationInfo.yieldsPerNormalizedYield;
+    _ASSERTE(n != 0);
+    do
+    {
+        System_YieldProcessor();
+    } while (--n != 0);
+}
+
+// Delays execution of the current thread for a short duration. Unlike YieldProcessor(), an effort is made to normalize the
+// delay across processors. The actual delay may be meaningful in several ways, including but not limited to the following:
+//   - The delay should be long enough that a tiny spin-wait like the following has a decent likelihood of observing a new value
+//     for the condition (when changed by a different thread) on each iteration, otherwise it may unnecessary increase CPU usage
+//     and decrease scalability of the operation.
+//         while(!condition)
+//         {
+//             YieldProcessorNormalized();
+//         }
+//   - The delay should be short enough that a tiny spin-wait like above would not miss multiple cross-thread changes to the
+//     condition, otherwise it may unnecessarily increase latency of the operation
+//   - In reasonably short spin-waits, the actual delay may not matter much. In unreasonably long spin-waits that progress in
+//     yield count per iteration for each failed check of the condition, the progression can significantly magnify the second
+//     issue above on later iterations.
+//   - This function and variants are intended to provide a decent balance between the above issues, as ideal solutions to each
+//     issue have trade-offs between them. If latency of the operation is far more important in the scenario, consider using
+//     System_YieldProcessor() instead, which would issue a delay that is typically <= the delay issued by this method.
+FORCEINLINE void YieldProcessorNormalized()
+{
+    YieldProcessorNormalized(YieldProcessorNormalizationInfo());
+}
+
+// See YieldProcessorNormalized(count) for preliminary info. Typical usage:
+//     if (!moreExpensiveCondition)
+//     {
+//         YieldProcessorNormalizationInfo normalizationInfo;
+//         do
+//         {
+//             YieldProcessorNormalized(normalizationInfo, 2);
+//         } while (!moreExpensiveCondition);
+//     }
+FORCEINLINE void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &normalizationInfo, unsigned int count)
+{
+    _ASSERTE(count != 0);
+
+    if (sizeof(SIZE_T) <= sizeof(unsigned int))
+    {
+        // On platforms with a small SIZE_T, prevent overflow on the multiply below
+        const unsigned int MaxCount = UINT_MAX / YieldProcessorNormalization::MaxYieldsPerNormalizedYield;
+        if (count > MaxCount)
+        {
+            count = MaxCount;
+        }
+    }
+
+    SIZE_T n = (SIZE_T)count * normalizationInfo.yieldsPerNormalizedYield;
+    _ASSERTE(n != 0);
+    do
+    {
+        System_YieldProcessor();
+    } while (--n != 0);
+}
+
+// See YieldProcessorNormalized() for preliminary info. This function repeats the delay 'count' times. This overload is
+// preferred over the single-count overload when multiple yields are desired per spin-wait iteration. Typical usage:
+//     while(!moreExpensiveCondition)
+//     {
+//         YieldProcessorNormalized(2);
+//     }
+FORCEINLINE void YieldProcessorNormalized(unsigned int count)
+{
+    YieldProcessorNormalized(YieldProcessorNormalizationInfo(), count);
+}
+
+// Please DO NOT use this function in new code! See YieldProcessorNormalizedForPreSkylakeCount(preSkylakeCount) for preliminary
+// info. Typical usage:
+//     if (!condition)
+//     {
+//         YieldProcessorNormalizationInfo normalizationInfo;
+//         do
+//         {
+//             YieldProcessorNormalizedForPreSkylakeCount(normalizationInfo, 100);
+//         } while (!condition);
+//     }
+FORCEINLINE void YieldProcessorNormalizedForPreSkylakeCount(
+    const YieldProcessorNormalizationInfo &normalizationInfo,
+    unsigned int preSkylakeCount)
+{
+    _ASSERTE(preSkylakeCount != 0);
+
+    if (sizeof(SIZE_T) <= sizeof(unsigned int))
+    {
+        // On platforms with a small SIZE_T, prevent overflow on the multiply below
+        const unsigned int MaxCount = UINT_MAX / YieldProcessorNormalization::MaxYieldsPerNormalizedYield;
+        if (preSkylakeCount > MaxCount)
+        {
+            preSkylakeCount = MaxCount;
+        }
+    }
+
+    const unsigned int PreSkylakeCountToSkylakeCountDivisor = 8;
+    SIZE_T n = (SIZE_T)preSkylakeCount * normalizationInfo.yieldsPerNormalizedYield / PreSkylakeCountToSkylakeCountDivisor;
+    if (n == 0)
+    {
+        n = 1;
+    }
+    do
+    {
+        System_YieldProcessor();
+    } while (--n != 0);
+}
+
+// Please DO NOT use this function in new code! This function is to be used for old spin-wait loops that have not been retuned
+// for recent processors, and especially where the yield count may be unreasonably high. The function scales the yield count in
+// an attempt to normalize the total delay across processors, to approximately the total delay that would be issued on a
+// pre-Skylake processor. New code should be tuned with YieldProcessorNormalized() or variants instead. Typical usage:
+//     while(!condition)
+//     {
+//         YieldProcessorNormalizedForPreSkylakeCount(100);
+//     }
+FORCEINLINE void YieldProcessorNormalizedForPreSkylakeCount(unsigned int preSkylakeCount)
+{
+    // This function does not forward to the one above because it is used by some code under utilcode, where
+    // YieldProcessorNormalizationInfo cannot be used since normalization does not happen in some of its consumers. So this
+    // version uses the fields in YieldProcessorNormalization directly.
+
+    _ASSERTE(preSkylakeCount != 0);
+
+    if (sizeof(SIZE_T) <= sizeof(unsigned int))
+    {
+        // On platforms with a small SIZE_T, prevent overflow on the multiply below
+        const unsigned int MaxCount = UINT_MAX / YieldProcessorNormalization::MaxYieldsPerNormalizedYield;
+        if (preSkylakeCount > MaxCount)
+        {
+            preSkylakeCount = MaxCount;
+        }
+    }
+
+    const unsigned int PreSkylakeCountToSkylakeCountDivisor = 8;
+    SIZE_T n =
+        (SIZE_T)preSkylakeCount *
+        YieldProcessorNormalization::s_yieldsPerNormalizedYield /
+        PreSkylakeCountToSkylakeCountDivisor;
+    if (n == 0)
+    {
+        n = 1;
+    }
+    do
+    {
+        System_YieldProcessor();
+    } while (--n != 0);
+}
+
+// See YieldProcessorNormalized() for preliminary info. This function is to be used when there is a decent possibility that the
+// condition would not be satisfied within a short duration. The current implementation increases the delay per spin-wait
+// iteration exponentially up to a limit. Typical usage:
+//     if (!conditionThatMayNotBeSatisfiedSoon)
+//     {
+//         YieldProcessorNormalizationInfo normalizationInfo;
+//         do
+//         {
+//             YieldProcessorWithBackOffNormalized(normalizationInfo); // maybe Sleep(0) occasionally
+//         } while (!conditionThatMayNotBeSatisfiedSoon);
+//     }
+FORCEINLINE void YieldProcessorWithBackOffNormalized(
+    const YieldProcessorNormalizationInfo &normalizationInfo,
+    unsigned int spinIteration)
+{
+    // This shift value should be adjusted based on the asserted conditions below
+    const UINT8 MaxShift = 3;
+    static_assert_no_msg(
+        ((unsigned int)1 << MaxShift) <= YieldProcessorNormalization::MaxOptimalMaxNormalizedYieldsPerSpinIteration);
+    static_assert_no_msg(
+        ((unsigned int)1 << (MaxShift + 1)) > YieldProcessorNormalization::MaxOptimalMaxNormalizedYieldsPerSpinIteration);
+
+    unsigned int n;
+    if (spinIteration <= MaxShift &&
+        ((unsigned int)1 << spinIteration) < normalizationInfo.optimalMaxNormalizedYieldsPerSpinIteration)
+    {
+        n = ((unsigned int)1 << spinIteration) * normalizationInfo.yieldsPerNormalizedYield;
+    }
+    else
+    {
+        n = normalizationInfo.optimalMaxYieldsPerSpinIteration;
+    }
+    _ASSERTE(n != 0);
+    do
+    {
+        System_YieldProcessor();
+    } while (--n != 0);
+}
+
+#undef DISABLE_CONSTRUCT_COPY
+#undef DISABLE_COPY
index ef4ff06d5a53123a67c1ed2427065cd2cd29c74a..59f43049ad38647e036d9c66fad55d91ce4f7ab2 100644 (file)
@@ -6,4 +6,7 @@ include_directories(${COREPAL_SOURCE_DIR}/src)
 add_compile_options(-fexceptions)
 add_definitions(-DUSE_STL)
 
+remove_definitions(-DUNICODE)
+remove_definitions(-D_UNICODE)
+
 add_subdirectory(src)
index 6c5fa110123433164684615dd952da3aea5bbda1..43dfd6a2a5a7377e22f14bb8b7ab68555924b330 100644 (file)
@@ -343,28 +343,70 @@ typedef __int64 time_t;
 #define PAL_INITIALIZE_SYNC_THREAD                  0x01
 #define PAL_INITIALIZE_EXEC_ALLOCATOR               0x02
 #define PAL_INITIALIZE_STD_HANDLES                  0x04
-#define PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER     0x08
-#define PAL_INITIALIZE_DEBUGGER_EXCEPTIONS          0x10
-#define PAL_INITIALIZE_ENSURE_STACK_SIZE            0x20
 
 // PAL_Initialize() flags
-#define PAL_INITIALIZE                 (PAL_INITIALIZE_SYNC_THREAD | PAL_INITIALIZE_STD_HANDLES)
+#define PAL_INITIALIZE                 (PAL_INITIALIZE_SYNC_THREAD | \
+                                        PAL_INITIALIZE_STD_HANDLES)
 
-// PAL_InitializeDLL() flags - don't start any of the helper threads
-#define PAL_INITIALIZE_DLL             PAL_INITIALIZE_NONE       
-
-// PAL_InitializeCoreCLR() flags
-#define PAL_INITIALIZE_CORECLR         (PAL_INITIALIZE | PAL_INITIALIZE_EXEC_ALLOCATOR | PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER | PAL_INITIALIZE_DEBUGGER_EXCEPTIONS | PAL_INITIALIZE_ENSURE_STACK_SIZE)
+// PAL_InitializeDLL() flags - don't start any of the helper threads or register any exceptions
+#define PAL_INITIALIZE_DLL              PAL_INITIALIZE_NONE
 
 typedef DWORD (PALAPI_NOEXPORT *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter);
 typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
 
 /******************* PAL-Specific Entrypoints *****************************/
 
+PALIMPORT
+void
+PALAPI
+PAL_InitializeWithFlags(
+    DWORD flags);
+
 PALIMPORT
 int
 PALAPI
 PAL_InitializeDLL();
+typedef VOID (*PPAL_STARTUP_CALLBACK)(
+    char *modulePath,
+    HMODULE hModule,
+    PVOID parameter);
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_RegisterForRuntimeStartup(
+    IN DWORD dwProcessId,
+    IN LPCWSTR lpApplicationGroupId,
+    IN PPAL_STARTUP_CALLBACK pfnCallback,
+    IN PVOID parameter,
+    OUT PVOID *ppUnregisterToken);
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_UnregisterForRuntimeStartup(
+    IN PVOID pUnregisterToken);
+
+static const unsigned int MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH = MAX_PATH;
+PALIMPORT
+VOID
+PALAPI
+PAL_GetTransportName(
+    const unsigned int MAX_TRANSPORT_NAME_LENGTH,
+    OUT char *name,
+    IN const char *prefix,
+    IN DWORD id,
+    IN const char *applicationGroupId,
+    IN const char *suffix);
+PALIMPORT
+VOID
+PALAPI
+PAL_GetTransportPipeName(
+    OUT char *name,
+    IN DWORD id,
+    IN const char *applicationGroupId,
+    IN const char *suffix);
+
 
 PALIMPORT
 HINSTANCE
@@ -882,6 +924,10 @@ DWORD
 PALAPI
 GetCurrentSessionId();
 
+PALIMPORT
+HANDLE
+PALAPI
+GetCurrentProcess();
 
 PALIMPORT
 DWORD
@@ -925,6 +971,55 @@ typedef struct _PROCESS_INFORMATION {
     DWORD dwProcessId;
     DWORD dwThreadId_PAL_Undefined;
 } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
+PALIMPORT
+BOOL
+PALAPI
+CreateProcessW(
+           IN LPCWSTR lpApplicationName,
+           IN LPWSTR lpCommandLine,
+           IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
+           IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+           IN BOOL bInheritHandles,
+           IN DWORD dwCreationFlags,
+           IN LPVOID lpEnvironment,
+           IN LPCWSTR lpCurrentDirectory,
+           IN LPSTARTUPINFOW lpStartupInfo,
+           OUT LPPROCESS_INFORMATION lpProcessInformation);
+
+#define CreateProcess CreateProcessW
+PALIMPORT
+BOOL
+PALAPI
+TerminateProcess(
+         IN HANDLE hProcess,
+         IN UINT uExitCode);
+
+#define MAXIMUM_WAIT_OBJECTS  64
+#define WAIT_OBJECT_0 0
+#define WAIT_ABANDONED   0x00000080
+#define WAIT_ABANDONED_0 0x00000080
+#define WAIT_TIMEOUT 258
+#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
+
+#define INFINITE 0xFFFFFFFF // Infinite timeout
+
+PALIMPORT
+DWORD
+PALAPI
+WaitForSingleObject(
+            IN HANDLE hHandle,
+            IN DWORD dwMilliseconds);
+
+#define DEBUG_PROCESS                     0x00000001
+#define DEBUG_ONLY_THIS_PROCESS           0x00000002
+#define CREATE_SUSPENDED                  0x00000004
+#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
+PALIMPORT
+DWORD
+PALAPI
+ResumeThread(
+         IN HANDLE hThread);
+
 
 #ifdef HOST_X86
 
@@ -2256,6 +2351,15 @@ typedef struct _RUNTIME_FUNCTION {
 #define PROCESS_ALL_ACCESS        (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
                                    0xFFF)
 
+PALIMPORT
+HANDLE
+PALAPI
+OpenProcess(
+    IN DWORD dwDesiredAccess, /* PROCESS_DUP_HANDLE or PROCESS_ALL_ACCESS */
+    IN BOOL bInheritHandle,
+    IN DWORD dwProcessId
+    );
+
 PALIMPORT
 BOOL
 PALAPI
@@ -2989,7 +3093,6 @@ GetSystemInfo(
 #define wcspbrk       PAL_wcspbrk
 #define wcscmp        PAL_wcscmp
 #define wcsncpy       PAL_wcsncpy
-#define wcstok        PAL_wcstok
 #define wcscspn       PAL_wcscspn
 #define iswprint      PAL_iswprint
 #define realloc       PAL_realloc
@@ -3182,7 +3285,6 @@ PALIMPORT DLLEXPORT const WCHAR * __cdecl PAL_wcschr(const WCHAR *, WCHAR);
 PALIMPORT DLLEXPORT const WCHAR * __cdecl PAL_wcsrchr(const WCHAR *, WCHAR);
 PALIMPORT WCHAR _WConst_return * __cdecl PAL_wcspbrk(const WCHAR *, const WCHAR *);
 PALIMPORT DLLEXPORT WCHAR _WConst_return * __cdecl PAL_wcsstr(const WCHAR *, const WCHAR *);
-PALIMPORT WCHAR * __cdecl PAL_wcstok(WCHAR *, const WCHAR *);
 PALIMPORT DLLEXPORT size_t __cdecl PAL_wcscspn(const WCHAR *, const WCHAR *);
 PALIMPORT int __cdecl PAL_swprintf(WCHAR *, const WCHAR *, ...);
 PALIMPORT int __cdecl PAL_vswprintf(WCHAR *, const WCHAR *, va_list);
index 1fe285eef162d227ac7856b766e76b9320c043cf..a1bad6300f3cff567bca5437a2e9b6676ef43cea 100644 (file)
@@ -39,6 +39,8 @@
 #include "unixasmmacrosamd64.inc"
 #elif defined(HOST_ARM)
 #include "unixasmmacrosarm.inc"
+#elif defined(HOST_ARMV6)
+#include "unixasmmacrosarm.inc"
 #elif defined(HOST_ARM64)
 #include "unixasmmacrosarm64.inc"
 #elif defined(HOST_S390X)
index e0c0016cc26ab2c1e967bcc6d21a1a11b56bb637..d323ccc49fbd2da8fd8f48794f265e107dec802d 100644 (file)
@@ -197,7 +197,11 @@ C_FUNC(\Name\()_End):
 .endm
 
 .macro EMIT_BREAKPOINT
+#ifdef __armv6__
+        .inst 0xe7f001f0
+#else
         .inst.w 0xde01
+#endif
 .endm
 
 .macro PROLOG_PUSH RegList
diff --git a/src/pal/prebuilt/inc/buildnumber.h b/src/pal/prebuilt/inc/buildnumber.h
deleted file mode 100644 (file)
index 5aee76a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#define BuildNumberMajor       30319
-#define BuildNumberMinor       0
-#define BuildNumberMajor_A     "30319"
-#define BuildNumberMinor_A     "00"
-#define BuildNumbers_A         "30319.00"
-#define BuildNumbers_T         TEXT("30319.00")
-
-#define NDPBuildNumberMajor   30319
-#define NDPBuildNumberMinor   0
-#define NDPBuildNumbers_A     "30319.00"
-#define NDPBuildNumbers_T     TEXT("30319.00")
-
-#define NDPFileVersionMinor   5
-#define NDPFileVersionBuild   30319
-#define NDPFileVersionRevision   0
-
-#define NDPFileVersionMinor_A     "5"
-#define NDPFileVersionBuild_A     "30319"
-#define NDPFileVersionRevision_A     "00"
diff --git a/src/pal/prebuilt/inc/clrprivbinding.h b/src/pal/prebuilt/inc/clrprivbinding.h
deleted file mode 100644 (file)
index 3c81067..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-
-
-/* this ALWAYS GENERATED file contains the definitions for the interfaces */
-
-
- /* File created by MIDL compiler version 8.00.0603 */
-/* @@MIDL_FILE_HEADING(  ) */
-
-#pragma warning( disable: 4049 )  /* more than 64k source lines */
-
-
-/* verify that the <rpcndr.h> version is high enough to compile this file*/
-#ifndef __REQUIRED_RPCNDR_H_VERSION__
-#define __REQUIRED_RPCNDR_H_VERSION__ 475
-#endif
-
-#include "rpc.h"
-#include "rpcndr.h"
-
-#ifndef __RPCNDR_H_VERSION__
-#error this stub requires an updated version of <rpcndr.h>
-#endif /* __RPCNDR_H_VERSION__ */
-
-#ifndef COM_NO_WINDOWS_H
-#include "windows.h"
-#include "ole2.h"
-#endif /*COM_NO_WINDOWS_H*/
-
-#ifndef __clrprivbinding_h__
-#define __clrprivbinding_h__
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-#pragma once
-#endif
-
-/* Forward Declarations */ 
-
-#ifndef __ICLRPrivBinder_FWD_DEFINED__
-#define __ICLRPrivBinder_FWD_DEFINED__
-typedef interface ICLRPrivBinder ICLRPrivBinder;
-
-#endif         /* __ICLRPrivBinder_FWD_DEFINED__ */
-
-
-#ifndef __ICLRPrivAssembly_FWD_DEFINED__
-#define __ICLRPrivAssembly_FWD_DEFINED__
-typedef interface ICLRPrivAssembly ICLRPrivAssembly;
-
-#endif         /* __ICLRPrivAssembly_FWD_DEFINED__ */
-
-
-/* header files for imported files */
-#include "unknwn.h"
-#include "objidl.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif 
-
-
-/* interface __MIDL_itf_clrprivbinding_0000_0000 */
-/* [local] */ 
-
-
-
-
-
-extern RPC_IF_HANDLE __MIDL_itf_clrprivbinding_0000_0000_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_clrprivbinding_0000_0000_v0_0_s_ifspec;
-
-#ifndef __ICLRPrivBinder_INTERFACE_DEFINED__
-#define __ICLRPrivBinder_INTERFACE_DEFINED__
-
-/* interface ICLRPrivBinder */
-/* [object][local][version][uuid] */ 
-
-
-EXTERN_C const IID IID_ICLRPrivBinder;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("2601F621-E462-404C-B299-3E1DE72F8542")
-    ICLRPrivBinder : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE BindAssemblyByName( 
-            /* [in] */ struct AssemblyNameData *pAssemblyNameData,
-            /* [retval][out] */ ICLRPrivAssembly **ppAssembly) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE GetBinderID( 
-            /* [retval][out] */ UINT_PTR *pBinderId) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocator( 
-            /* [retval][out] */ LPVOID *pLoaderAllocator) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICLRPrivBinderVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICLRPrivBinder * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICLRPrivBinder * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICLRPrivBinder * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *BindAssemblyByName )( 
-            ICLRPrivBinder * This,
-            /* [in] */ struct AssemblyNameData *pAssemblyNameData,
-            /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetBinderID )( 
-            ICLRPrivBinder * This,
-            /* [retval][out] */ UINT_PTR *pBinderId);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetLoaderAllocator )( 
-            ICLRPrivBinder * This,
-            /* [retval][out] */ LPVOID *pLoaderAllocator);
-        
-        END_INTERFACE
-    } ICLRPrivBinderVtbl;
-
-    interface ICLRPrivBinder
-    {
-        CONST_VTBL struct ICLRPrivBinderVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICLRPrivBinder_QueryInterface(This,riid,ppvObject)     \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICLRPrivBinder_AddRef(This)    \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICLRPrivBinder_Release(This)   \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICLRPrivBinder_BindAssemblyByName(This,pAssemblyNameData,ppAssembly)   \
-    ( (This)->lpVtbl -> BindAssemblyByName(This,pAssemblyNameData,ppAssembly) ) 
-
-#define ICLRPrivBinder_GetBinderID(This,pBinderId)     \
-    ( (This)->lpVtbl -> GetBinderID(This,pBinderId) ) 
-
-#define ICLRPrivBinder_GetLoaderAllocator(This,pLoaderAllocator)       \
-    ( (This)->lpVtbl -> GetLoaderAllocator(This,pLoaderAllocator) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICLRPrivBinder_INTERFACE_DEFINED__ */
-
-
-/* interface __MIDL_itf_clrprivbinding_0000_0001 */
-/* [local] */ 
-
-
-enum ASSEMBLY_IMAGE_TYPES
-    {
-        ASSEMBLY_IMAGE_TYPE_IL = 0x1,
-        ASSEMBLY_IMAGE_TYPE_NATIVE     = 0x2,
-        ASSEMBLY_IMAGE_TYPE_DEFAULT    = 0x3,
-        ASSEMBLY_IMAGE_TYPE_ASSEMBLY   = 0x4
-    } ;
-
-
-extern RPC_IF_HANDLE __MIDL_itf_clrprivbinding_0000_0001_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_clrprivbinding_0000_0001_v0_0_s_ifspec;
-
-#ifndef __ICLRPrivAssembly_INTERFACE_DEFINED__
-#define __ICLRPrivAssembly_INTERFACE_DEFINED__
-
-/* interface ICLRPrivAssembly */
-/* [object][local][version][uuid] */ 
-
-
-EXTERN_C const IID IID_ICLRPrivAssembly;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("2601F621-E462-404C-B299-3E1DE72F8543")
-    ICLRPrivAssembly : public ICLRPrivBinder
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE GetAvailableImageTypes( 
-            /* [retval][out] */ LPDWORD pdwImageTypes) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICLRPrivAssemblyVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICLRPrivAssembly * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICLRPrivAssembly * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICLRPrivAssembly * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *BindAssemblyByName )( 
-            ICLRPrivAssembly * This,
-            /* [in] */ struct AssemblyNameData *pAssemblyNameData,
-            /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetBinderID )( 
-            ICLRPrivAssembly * This,
-            /* [retval][out] */ UINT_PTR *pBinderId);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetLoaderAllocator )( 
-            ICLRPrivAssembly * This,
-            /* [retval][out] */ LPVOID *pLoaderAllocator);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetAvailableImageTypes )( 
-            ICLRPrivAssembly * This,
-            /* [retval][out] */ LPDWORD pdwImageTypes);
-        
-        END_INTERFACE
-    } ICLRPrivAssemblyVtbl;
-
-    interface ICLRPrivAssembly
-    {
-        CONST_VTBL struct ICLRPrivAssemblyVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICLRPrivAssembly_QueryInterface(This,riid,ppvObject)   \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICLRPrivAssembly_AddRef(This)  \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICLRPrivAssembly_Release(This) \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICLRPrivAssembly_BindAssemblyByName(This,pAssemblyNameData,ppAssembly) \
-    ( (This)->lpVtbl -> BindAssemblyByName(This,pAssemblyNameData,ppAssembly) ) 
-
-#define ICLRPrivAssembly_GetBinderID(This,pBinderId)   \
-    ( (This)->lpVtbl -> GetBinderID(This,pBinderId) ) 
-
-#define ICLRPrivAssembly_GetLoaderAllocator(This,pLoaderAllocator)     \
-    ( (This)->lpVtbl -> GetLoaderAllocator(This,pLoaderAllocator) ) 
-
-
-#define ICLRPrivAssembly_GetAvailableImageTypes(This,pdwImageTypes)    \
-    ( (This)->lpVtbl -> GetAvailableImageTypes(This,pdwImageTypes) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICLRPrivAssembly_INTERFACE_DEFINED__ */
-
-
-/* Additional Prototypes for ALL interfaces */
-
-/* end of Additional Prototypes */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-
diff --git a/src/pal/prebuilt/inc/mscorsvc.h b/src/pal/prebuilt/inc/mscorsvc.h
deleted file mode 100644 (file)
index a00db39..0000000
+++ /dev/null
@@ -1,2823 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-
-
-/* this ALWAYS GENERATED file contains the definitions for the interfaces */
-
-
- /* File created by MIDL compiler version 8.00.0603 */
-/* @@MIDL_FILE_HEADING(  ) */
-
-#pragma warning( disable: 4049 )  /* more than 64k source lines */
-
-
-/* verify that the <rpcndr.h> version is high enough to compile this file*/
-#ifndef __REQUIRED_RPCNDR_H_VERSION__
-#define __REQUIRED_RPCNDR_H_VERSION__ 475
-#endif
-
-#include "rpc.h"
-#include "rpcndr.h"
-
-#ifndef __RPCNDR_H_VERSION__
-#error this stub requires an updated version of <rpcndr.h>
-#endif // __RPCNDR_H_VERSION__
-
-#ifndef COM_NO_WINDOWS_H
-#include "windows.h"
-#include "ole2.h"
-#endif /*COM_NO_WINDOWS_H*/
-
-#ifndef __mscorsvc_h__
-#define __mscorsvc_h__
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-#pragma once
-#endif
-
-/* Forward Declarations */ 
-
-#ifndef __ICorSvcDependencies_FWD_DEFINED__
-#define __ICorSvcDependencies_FWD_DEFINED__
-typedef interface ICorSvcDependencies ICorSvcDependencies;
-
-#endif         /* __ICorSvcDependencies_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcWorker_FWD_DEFINED__
-#define __ICorSvcWorker_FWD_DEFINED__
-typedef interface ICorSvcWorker ICorSvcWorker;
-
-#endif         /* __ICorSvcWorker_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcWorker2_FWD_DEFINED__
-#define __ICorSvcWorker2_FWD_DEFINED__
-typedef interface ICorSvcWorker2 ICorSvcWorker2;
-
-#endif         /* __ICorSvcWorker2_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcWorker3_FWD_DEFINED__
-#define __ICorSvcWorker3_FWD_DEFINED__
-typedef interface ICorSvcWorker3 ICorSvcWorker3;
-
-#endif         /* __ICorSvcWorker3_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcSetPrivateAttributes_FWD_DEFINED__
-#define __ICorSvcSetPrivateAttributes_FWD_DEFINED__
-typedef interface ICorSvcSetPrivateAttributes ICorSvcSetPrivateAttributes;
-
-#endif         /* __ICorSvcSetPrivateAttributes_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcRepository_FWD_DEFINED__
-#define __ICorSvcRepository_FWD_DEFINED__
-typedef interface ICorSvcRepository ICorSvcRepository;
-
-#endif         /* __ICorSvcRepository_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcAppX_FWD_DEFINED__
-#define __ICorSvcAppX_FWD_DEFINED__
-typedef interface ICorSvcAppX ICorSvcAppX;
-
-#endif         /* __ICorSvcAppX_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcLogger_FWD_DEFINED__
-#define __ICorSvcLogger_FWD_DEFINED__
-typedef interface ICorSvcLogger ICorSvcLogger;
-
-#endif         /* __ICorSvcLogger_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcPooledWorker_FWD_DEFINED__
-#define __ICorSvcPooledWorker_FWD_DEFINED__
-typedef interface ICorSvcPooledWorker ICorSvcPooledWorker;
-
-#endif         /* __ICorSvcPooledWorker_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcBindToWorker_FWD_DEFINED__
-#define __ICorSvcBindToWorker_FWD_DEFINED__
-typedef interface ICorSvcBindToWorker ICorSvcBindToWorker;
-
-#endif         /* __ICorSvcBindToWorker_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvc_FWD_DEFINED__
-#define __ICorSvc_FWD_DEFINED__
-typedef interface ICorSvc ICorSvc;
-
-#endif         /* __ICorSvc_FWD_DEFINED__ */
-
-
-#ifndef __ICompileProgressNotification_FWD_DEFINED__
-#define __ICompileProgressNotification_FWD_DEFINED__
-typedef interface ICompileProgressNotification ICompileProgressNotification;
-
-#endif         /* __ICompileProgressNotification_FWD_DEFINED__ */
-
-
-#ifndef __ICompileProgressNotification2_FWD_DEFINED__
-#define __ICompileProgressNotification2_FWD_DEFINED__
-typedef interface ICompileProgressNotification2 ICompileProgressNotification2;
-
-#endif         /* __ICompileProgressNotification2_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcInstaller_FWD_DEFINED__
-#define __ICorSvcInstaller_FWD_DEFINED__
-typedef interface ICorSvcInstaller ICorSvcInstaller;
-
-#endif         /* __ICorSvcInstaller_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcAdvancedInstaller_FWD_DEFINED__
-#define __ICorSvcAdvancedInstaller_FWD_DEFINED__
-typedef interface ICorSvcAdvancedInstaller ICorSvcAdvancedInstaller;
-
-#endif         /* __ICorSvcAdvancedInstaller_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcOptimizer_FWD_DEFINED__
-#define __ICorSvcOptimizer_FWD_DEFINED__
-typedef interface ICorSvcOptimizer ICorSvcOptimizer;
-
-#endif         /* __ICorSvcOptimizer_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcOptimizer2_FWD_DEFINED__
-#define __ICorSvcOptimizer2_FWD_DEFINED__
-typedef interface ICorSvcOptimizer2 ICorSvcOptimizer2;
-
-#endif         /* __ICorSvcOptimizer2_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcOptimizer3_FWD_DEFINED__
-#define __ICorSvcOptimizer3_FWD_DEFINED__
-typedef interface ICorSvcOptimizer3 ICorSvcOptimizer3;
-
-#endif         /* __ICorSvcOptimizer3_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcManager_FWD_DEFINED__
-#define __ICorSvcManager_FWD_DEFINED__
-typedef interface ICorSvcManager ICorSvcManager;
-
-#endif         /* __ICorSvcManager_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcManager2_FWD_DEFINED__
-#define __ICorSvcManager2_FWD_DEFINED__
-typedef interface ICorSvcManager2 ICorSvcManager2;
-
-#endif         /* __ICorSvcManager2_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcSetLegacyServiceBehavior_FWD_DEFINED__
-#define __ICorSvcSetLegacyServiceBehavior_FWD_DEFINED__
-typedef interface ICorSvcSetLegacyServiceBehavior ICorSvcSetLegacyServiceBehavior;
-
-#endif         /* __ICorSvcSetLegacyServiceBehavior_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcSetTaskBootTriggerState_FWD_DEFINED__
-#define __ICorSvcSetTaskBootTriggerState_FWD_DEFINED__
-typedef interface ICorSvcSetTaskBootTriggerState ICorSvcSetTaskBootTriggerState;
-
-#endif         /* __ICorSvcSetTaskBootTriggerState_FWD_DEFINED__ */
-
-
-#ifndef __ICorSvcSetTaskDelayStartTriggerState_FWD_DEFINED__
-#define __ICorSvcSetTaskDelayStartTriggerState_FWD_DEFINED__
-typedef interface ICorSvcSetTaskDelayStartTriggerState ICorSvcSetTaskDelayStartTriggerState;
-
-#endif         /* __ICorSvcSetTaskDelayStartTriggerState_FWD_DEFINED__ */
-
-
-/* header files for imported files */
-#include "unknwn.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif 
-
-
-/* interface __MIDL_itf_mscorsvc_0000_0000 */
-/* [local] */ 
-
-#if 0
-#endif
-EXTERN_GUID(CLSID_CorSvcWorker, 0x8ed1a844, 0x32a7, 0x4a67, 0xba, 0x62, 0xf8, 0xd5, 0xaf, 0xdf, 0xf4, 0x60);
-EXTERN_GUID(CLSID_CorSvcBindToWorker, 0x9f74fb09, 0x4221, 0x40b4, 0xae, 0x21, 0xae, 0xb6, 0xdf, 0xf2, 0x99, 0x4e);
-STDAPI CorGetSvc(IUnknown **pIUnknown);
-
-
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0000_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0000_v0_0_s_ifspec;
-
-
-#ifndef __mscorsvc_LIBRARY_DEFINED__
-#define __mscorsvc_LIBRARY_DEFINED__
-
-/* library mscorsvc */
-/* [helpstring][version][uuid] */ 
-
-typedef /* [public][public][public][public][public][public][public][public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0001_0004_0001
-    {
-        ScenarioDefault        = 0,
-        ScenarioAll    = 0x1,
-        ScenarioDebug  = 0x2,
-        ScenarioProfile        = 0x8,
-        ScenarioTuningDataCollection   = 0x10,
-        ScenarioLegacy = 0x20,
-        ScenarioNgenLastRetry  = 0x10000,
-        ScenarioAutoNGen       = 0x100000,
-        ScenarioRepositoryOnly = 0x200000
-    }  OptimizationScenario;
-
-typedef /* [public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0001_0004_0002
-    {
-        ScenarioEmitFixups     = 0x10000,
-        ScenarioProfileInfo    = 0x20000
-    }  PrivateOptimizationScenario;
-
-typedef struct _SvcWorkerPriority
-    {
-    DWORD dwPriorityClass;
-    }  SvcWorkerPriority;
-
-typedef /* [public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0001_0007_0001
-    {
-        DbgTypePdb     = 0x1
-    }  NGenPrivateAttributesFlags;
-
-typedef struct _NGenPrivateAttributes
-    {
-    DWORD Flags;
-    DWORD ZapStats;
-    BSTR DbgDir;
-    }  NGenPrivateAttributes;
-
-typedef /* [public][public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0001_0008_0001
-    {
-        RepositoryDefault      = 0,
-        MoveFromRepository     = 0x1,
-        CopyToRepository       = 0x2,
-        IgnoreRepository       = 0x4
-    }  RepositoryFlags;
-
-typedef 
-enum CorSvcLogLevel
-    {
-        LogLevel_Error = 0,
-        LogLevel_Warning       = ( LogLevel_Error + 1 ) ,
-        LogLevel_Success       = ( LogLevel_Warning + 1 ) ,
-        LogLevel_Info  = ( LogLevel_Success + 1 ) 
-    }  CorSvcLogLevel;
-
-
-EXTERN_C const IID LIBID_mscorsvc;
-
-#ifndef __ICorSvcDependencies_INTERFACE_DEFINED__
-#define __ICorSvcDependencies_INTERFACE_DEFINED__
-
-/* interface ICorSvcDependencies */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcDependencies;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("ddb34005-9ba3-4025-9554-f00a2df5dbf5")
-    ICorSvcDependencies : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE GetAssemblyDependencies( 
-            /* [in] */ BSTR pAssemblyName,
-            /* [out] */ SAFEARRAY * *pDependencies,
-            /* [out] */ DWORD *assemblyNGenSetting,
-            /* [out] */ BSTR *pNativeImageIdentity,
-            /* [out] */ BSTR *pAssemblyDisplayName,
-            /* [out] */ SAFEARRAY * *pDependencyLoadSetting,
-            /* [out] */ SAFEARRAY * *pDependencyNGenSetting) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcDependenciesVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcDependencies * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcDependencies * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcDependencies * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetAssemblyDependencies )( 
-            ICorSvcDependencies * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [out] */ SAFEARRAY * *pDependencies,
-            /* [out] */ DWORD *assemblyNGenSetting,
-            /* [out] */ BSTR *pNativeImageIdentity,
-            /* [out] */ BSTR *pAssemblyDisplayName,
-            /* [out] */ SAFEARRAY * *pDependencyLoadSetting,
-            /* [out] */ SAFEARRAY * *pDependencyNGenSetting);
-        
-        END_INTERFACE
-    } ICorSvcDependenciesVtbl;
-
-    interface ICorSvcDependencies
-    {
-        CONST_VTBL struct ICorSvcDependenciesVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcDependencies_QueryInterface(This,riid,ppvObject)        \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcDependencies_AddRef(This)       \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcDependencies_Release(This)      \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcDependencies_GetAssemblyDependencies(This,pAssemblyName,pDependencies,assemblyNGenSetting,pNativeImageIdentity,pAssemblyDisplayName,pDependencyLoadSetting,pDependencyNGenSetting)      \
-    ( (This)->lpVtbl -> GetAssemblyDependencies(This,pAssemblyName,pDependencies,assemblyNGenSetting,pNativeImageIdentity,pAssemblyDisplayName,pDependencyLoadSetting,pDependencyNGenSetting) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcDependencies_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcWorker_INTERFACE_DEFINED__
-#define __ICorSvcWorker_INTERFACE_DEFINED__
-
-/* interface ICorSvcWorker */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcWorker;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("d1047bc2-67c0-400c-a94c-e64446a67fbe")
-    ICorSvcWorker : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE SetPriority( 
-            /* [in] */ SvcWorkerPriority priority) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE OptimizeAssembly( 
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pApplicationName,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ SAFEARRAY * loadAlwaysList,
-            /* [in] */ SAFEARRAY * loadSometimesList,
-            /* [in] */ SAFEARRAY * loadNeverList,
-            /* [out] */ BSTR *pNativeImageIdentity) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE DeleteNativeImage( 
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pNativeImage) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE DisplayNativeImages( 
-            /* [in] */ BSTR pAssemblyName) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE GetCorSvcDependencies( 
-            /* [in] */ BSTR pApplicationName,
-            /* [in] */ OptimizationScenario scenario,
-            /* [out] */ ICorSvcDependencies **pCorSvcDependencies) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcWorkerVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcWorker * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcWorker * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcWorker * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetPriority )( 
-            ICorSvcWorker * This,
-            /* [in] */ SvcWorkerPriority priority);
-        
-        HRESULT ( STDMETHODCALLTYPE *OptimizeAssembly )( 
-            ICorSvcWorker * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pApplicationName,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ SAFEARRAY * loadAlwaysList,
-            /* [in] */ SAFEARRAY * loadSometimesList,
-            /* [in] */ SAFEARRAY * loadNeverList,
-            /* [out] */ BSTR *pNativeImageIdentity);
-        
-        HRESULT ( STDMETHODCALLTYPE *DeleteNativeImage )( 
-            ICorSvcWorker * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pNativeImage);
-        
-        HRESULT ( STDMETHODCALLTYPE *DisplayNativeImages )( 
-            ICorSvcWorker * This,
-            /* [in] */ BSTR pAssemblyName);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetCorSvcDependencies )( 
-            ICorSvcWorker * This,
-            /* [in] */ BSTR pApplicationName,
-            /* [in] */ OptimizationScenario scenario,
-            /* [out] */ ICorSvcDependencies **pCorSvcDependencies);
-        
-        HRESULT ( STDMETHODCALLTYPE *Stop )( 
-            ICorSvcWorker * This);
-        
-        END_INTERFACE
-    } ICorSvcWorkerVtbl;
-
-    interface ICorSvcWorker
-    {
-        CONST_VTBL struct ICorSvcWorkerVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcWorker_QueryInterface(This,riid,ppvObject)      \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcWorker_AddRef(This)     \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcWorker_Release(This)    \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcWorker_SetPriority(This,priority)       \
-    ( (This)->lpVtbl -> SetPriority(This,priority) ) 
-
-#define ICorSvcWorker_OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity)       \
-    ( (This)->lpVtbl -> OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) ) 
-
-#define ICorSvcWorker_DeleteNativeImage(This,pAssemblyName,pNativeImage)       \
-    ( (This)->lpVtbl -> DeleteNativeImage(This,pAssemblyName,pNativeImage) ) 
-
-#define ICorSvcWorker_DisplayNativeImages(This,pAssemblyName)  \
-    ( (This)->lpVtbl -> DisplayNativeImages(This,pAssemblyName) ) 
-
-#define ICorSvcWorker_GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies)        \
-    ( (This)->lpVtbl -> GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) ) 
-
-#define ICorSvcWorker_Stop(This)       \
-    ( (This)->lpVtbl -> Stop(This) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcWorker_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcWorker2_INTERFACE_DEFINED__
-#define __ICorSvcWorker2_INTERFACE_DEFINED__
-
-/* interface ICorSvcWorker2 */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcWorker2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("f3358a7d-0061-4776-880e-a2f21b9ef93e")
-    ICorSvcWorker2 : public ICorSvcWorker
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE CreatePdb( 
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pAppBaseOrConfig,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ BSTR pNativeImagePath,
-            /* [in] */ BSTR pPdbPath) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcWorker2Vtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcWorker2 * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcWorker2 * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcWorker2 * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetPriority )( 
-            ICorSvcWorker2 * This,
-            /* [in] */ SvcWorkerPriority priority);
-        
-        HRESULT ( STDMETHODCALLTYPE *OptimizeAssembly )( 
-            ICorSvcWorker2 * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pApplicationName,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ SAFEARRAY * loadAlwaysList,
-            /* [in] */ SAFEARRAY * loadSometimesList,
-            /* [in] */ SAFEARRAY * loadNeverList,
-            /* [out] */ BSTR *pNativeImageIdentity);
-        
-        HRESULT ( STDMETHODCALLTYPE *DeleteNativeImage )( 
-            ICorSvcWorker2 * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pNativeImage);
-        
-        HRESULT ( STDMETHODCALLTYPE *DisplayNativeImages )( 
-            ICorSvcWorker2 * This,
-            /* [in] */ BSTR pAssemblyName);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetCorSvcDependencies )( 
-            ICorSvcWorker2 * This,
-            /* [in] */ BSTR pApplicationName,
-            /* [in] */ OptimizationScenario scenario,
-            /* [out] */ ICorSvcDependencies **pCorSvcDependencies);
-        
-        HRESULT ( STDMETHODCALLTYPE *Stop )( 
-            ICorSvcWorker2 * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *CreatePdb )( 
-            ICorSvcWorker2 * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pAppBaseOrConfig,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ BSTR pNativeImagePath,
-            /* [in] */ BSTR pPdbPath);
-        
-        END_INTERFACE
-    } ICorSvcWorker2Vtbl;
-
-    interface ICorSvcWorker2
-    {
-        CONST_VTBL struct ICorSvcWorker2Vtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcWorker2_QueryInterface(This,riid,ppvObject)     \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcWorker2_AddRef(This)    \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcWorker2_Release(This)   \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcWorker2_SetPriority(This,priority)      \
-    ( (This)->lpVtbl -> SetPriority(This,priority) ) 
-
-#define ICorSvcWorker2_OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity)      \
-    ( (This)->lpVtbl -> OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) ) 
-
-#define ICorSvcWorker2_DeleteNativeImage(This,pAssemblyName,pNativeImage)      \
-    ( (This)->lpVtbl -> DeleteNativeImage(This,pAssemblyName,pNativeImage) ) 
-
-#define ICorSvcWorker2_DisplayNativeImages(This,pAssemblyName) \
-    ( (This)->lpVtbl -> DisplayNativeImages(This,pAssemblyName) ) 
-
-#define ICorSvcWorker2_GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies)       \
-    ( (This)->lpVtbl -> GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) ) 
-
-#define ICorSvcWorker2_Stop(This)      \
-    ( (This)->lpVtbl -> Stop(This) ) 
-
-
-#define ICorSvcWorker2_CreatePdb(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath)       \
-    ( (This)->lpVtbl -> CreatePdb(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcWorker2_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcWorker3_INTERFACE_DEFINED__
-#define __ICorSvcWorker3_INTERFACE_DEFINED__
-
-/* interface ICorSvcWorker3 */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcWorker3;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("DC516615-47BE-477e-8B55-C5ABE0D76B8F")
-    ICorSvcWorker3 : public ICorSvcWorker2
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE CreatePdb2( 
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pAppBaseOrConfig,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ BSTR pNativeImagePath,
-            /* [in] */ BSTR pPdbPath,
-            /* [in] */ BOOL pdbLines,
-            /* [in] */ BSTR managedPdbSearchPath) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcWorker3Vtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcWorker3 * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcWorker3 * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcWorker3 * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetPriority )( 
-            ICorSvcWorker3 * This,
-            /* [in] */ SvcWorkerPriority priority);
-        
-        HRESULT ( STDMETHODCALLTYPE *OptimizeAssembly )( 
-            ICorSvcWorker3 * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pApplicationName,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ SAFEARRAY * loadAlwaysList,
-            /* [in] */ SAFEARRAY * loadSometimesList,
-            /* [in] */ SAFEARRAY * loadNeverList,
-            /* [out] */ BSTR *pNativeImageIdentity);
-        
-        HRESULT ( STDMETHODCALLTYPE *DeleteNativeImage )( 
-            ICorSvcWorker3 * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pNativeImage);
-        
-        HRESULT ( STDMETHODCALLTYPE *DisplayNativeImages )( 
-            ICorSvcWorker3 * This,
-            /* [in] */ BSTR pAssemblyName);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetCorSvcDependencies )( 
-            ICorSvcWorker3 * This,
-            /* [in] */ BSTR pApplicationName,
-            /* [in] */ OptimizationScenario scenario,
-            /* [out] */ ICorSvcDependencies **pCorSvcDependencies);
-        
-        HRESULT ( STDMETHODCALLTYPE *Stop )( 
-            ICorSvcWorker3 * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *CreatePdb )( 
-            ICorSvcWorker3 * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pAppBaseOrConfig,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ BSTR pNativeImagePath,
-            /* [in] */ BSTR pPdbPath);
-        
-        HRESULT ( STDMETHODCALLTYPE *CreatePdb2 )( 
-            ICorSvcWorker3 * This,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BSTR pAppBaseOrConfig,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ BSTR pNativeImagePath,
-            /* [in] */ BSTR pPdbPath,
-            /* [in] */ BOOL pdbLines,
-            /* [in] */ BSTR managedPdbSearchPath);
-        
-        END_INTERFACE
-    } ICorSvcWorker3Vtbl;
-
-    interface ICorSvcWorker3
-    {
-        CONST_VTBL struct ICorSvcWorker3Vtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcWorker3_QueryInterface(This,riid,ppvObject)     \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcWorker3_AddRef(This)    \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcWorker3_Release(This)   \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcWorker3_SetPriority(This,priority)      \
-    ( (This)->lpVtbl -> SetPriority(This,priority) ) 
-
-#define ICorSvcWorker3_OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity)      \
-    ( (This)->lpVtbl -> OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) ) 
-
-#define ICorSvcWorker3_DeleteNativeImage(This,pAssemblyName,pNativeImage)      \
-    ( (This)->lpVtbl -> DeleteNativeImage(This,pAssemblyName,pNativeImage) ) 
-
-#define ICorSvcWorker3_DisplayNativeImages(This,pAssemblyName) \
-    ( (This)->lpVtbl -> DisplayNativeImages(This,pAssemblyName) ) 
-
-#define ICorSvcWorker3_GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies)       \
-    ( (This)->lpVtbl -> GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) ) 
-
-#define ICorSvcWorker3_Stop(This)      \
-    ( (This)->lpVtbl -> Stop(This) ) 
-
-
-#define ICorSvcWorker3_CreatePdb(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath)       \
-    ( (This)->lpVtbl -> CreatePdb(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath) ) 
-
-
-#define ICorSvcWorker3_CreatePdb2(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath,pdbLines,managedPdbSearchPath)        \
-    ( (This)->lpVtbl -> CreatePdb2(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath,pdbLines,managedPdbSearchPath) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcWorker3_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcSetPrivateAttributes_INTERFACE_DEFINED__
-#define __ICorSvcSetPrivateAttributes_INTERFACE_DEFINED__
-
-/* interface ICorSvcSetPrivateAttributes */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcSetPrivateAttributes;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("b18e0b40-c089-4350-8328-066c668bccc2")
-    ICorSvcSetPrivateAttributes : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE SetNGenPrivateAttributes( 
-            /* [in] */ NGenPrivateAttributes ngenPrivateAttributes) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcSetPrivateAttributesVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcSetPrivateAttributes * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcSetPrivateAttributes * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcSetPrivateAttributes * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetNGenPrivateAttributes )( 
-            ICorSvcSetPrivateAttributes * This,
-            /* [in] */ NGenPrivateAttributes ngenPrivateAttributes);
-        
-        END_INTERFACE
-    } ICorSvcSetPrivateAttributesVtbl;
-
-    interface ICorSvcSetPrivateAttributes
-    {
-        CONST_VTBL struct ICorSvcSetPrivateAttributesVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcSetPrivateAttributes_QueryInterface(This,riid,ppvObject)        \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcSetPrivateAttributes_AddRef(This)       \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcSetPrivateAttributes_Release(This)      \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcSetPrivateAttributes_SetNGenPrivateAttributes(This,ngenPrivateAttributes)       \
-    ( (This)->lpVtbl -> SetNGenPrivateAttributes(This,ngenPrivateAttributes) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcSetPrivateAttributes_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcRepository_INTERFACE_DEFINED__
-#define __ICorSvcRepository_INTERFACE_DEFINED__
-
-/* interface ICorSvcRepository */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcRepository;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("d5346658-b5fd-4353-9647-07ad4783d5a0")
-    ICorSvcRepository : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE SetRepository( 
-            /* [in] */ BSTR pRepositoryDir,
-            /* [in] */ RepositoryFlags repositoryFlags) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcRepositoryVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcRepository * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcRepository * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcRepository * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetRepository )( 
-            ICorSvcRepository * This,
-            /* [in] */ BSTR pRepositoryDir,
-            /* [in] */ RepositoryFlags repositoryFlags);
-        
-        END_INTERFACE
-    } ICorSvcRepositoryVtbl;
-
-    interface ICorSvcRepository
-    {
-        CONST_VTBL struct ICorSvcRepositoryVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcRepository_QueryInterface(This,riid,ppvObject)  \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcRepository_AddRef(This) \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcRepository_Release(This)        \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcRepository_SetRepository(This,pRepositoryDir,repositoryFlags)   \
-    ( (This)->lpVtbl -> SetRepository(This,pRepositoryDir,repositoryFlags) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcRepository_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcAppX_INTERFACE_DEFINED__
-#define __ICorSvcAppX_INTERFACE_DEFINED__
-
-/* interface ICorSvcAppX */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcAppX;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("5c814791-559e-4f7f-83ce-184a4ccbae24")
-    ICorSvcAppX : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE SetPackage( 
-            /* [in] */ BSTR pPackageFullName) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE SetLocalAppDataDirectory( 
-            /* [in] */ BSTR pLocalAppDataDirectory) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcAppXVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcAppX * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcAppX * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcAppX * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetPackage )( 
-            ICorSvcAppX * This,
-            /* [in] */ BSTR pPackageFullName);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetLocalAppDataDirectory )( 
-            ICorSvcAppX * This,
-            /* [in] */ BSTR pLocalAppDataDirectory);
-        
-        END_INTERFACE
-    } ICorSvcAppXVtbl;
-
-    interface ICorSvcAppX
-    {
-        CONST_VTBL struct ICorSvcAppXVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcAppX_QueryInterface(This,riid,ppvObject)        \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcAppX_AddRef(This)       \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcAppX_Release(This)      \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcAppX_SetPackage(This,pPackageFullName)  \
-    ( (This)->lpVtbl -> SetPackage(This,pPackageFullName) ) 
-
-#define ICorSvcAppX_SetLocalAppDataDirectory(This,pLocalAppDataDirectory)      \
-    ( (This)->lpVtbl -> SetLocalAppDataDirectory(This,pLocalAppDataDirectory) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcAppX_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcLogger_INTERFACE_DEFINED__
-#define __ICorSvcLogger_INTERFACE_DEFINED__
-
-/* interface ICorSvcLogger */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcLogger;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("d189ff1a-e266-4f13-9637-4b9522279ffc")
-    ICorSvcLogger : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE Log( 
-            /* [in] */ CorSvcLogLevel logLevel,
-            /* [in] */ BSTR message) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcLoggerVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcLogger * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcLogger * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcLogger * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *Log )( 
-            ICorSvcLogger * This,
-            /* [in] */ CorSvcLogLevel logLevel,
-            /* [in] */ BSTR message);
-        
-        END_INTERFACE
-    } ICorSvcLoggerVtbl;
-
-    interface ICorSvcLogger
-    {
-        CONST_VTBL struct ICorSvcLoggerVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcLogger_QueryInterface(This,riid,ppvObject)      \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcLogger_AddRef(This)     \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcLogger_Release(This)    \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcLogger_Log(This,logLevel,message)       \
-    ( (This)->lpVtbl -> Log(This,logLevel,message) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcLogger_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcPooledWorker_INTERFACE_DEFINED__
-#define __ICorSvcPooledWorker_INTERFACE_DEFINED__
-
-/* interface ICorSvcPooledWorker */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcPooledWorker;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("0631e7e2-6046-4fde-8b6d-a09b64fda6f3")
-    ICorSvcPooledWorker : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE CanReuseProcess( 
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ ICorSvcLogger *pCorSvcLogger,
-            /* [out] */ BOOL *pCanContinue) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcPooledWorkerVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcPooledWorker * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcPooledWorker * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcPooledWorker * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *CanReuseProcess )( 
-            ICorSvcPooledWorker * This,
-            /* [in] */ OptimizationScenario scenario,
-            /* [in] */ ICorSvcLogger *pCorSvcLogger,
-            /* [out] */ BOOL *pCanContinue);
-        
-        END_INTERFACE
-    } ICorSvcPooledWorkerVtbl;
-
-    interface ICorSvcPooledWorker
-    {
-        CONST_VTBL struct ICorSvcPooledWorkerVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcPooledWorker_QueryInterface(This,riid,ppvObject)        \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcPooledWorker_AddRef(This)       \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcPooledWorker_Release(This)      \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcPooledWorker_CanReuseProcess(This,scenario,pCorSvcLogger,pCanContinue)  \
-    ( (This)->lpVtbl -> CanReuseProcess(This,scenario,pCorSvcLogger,pCanContinue) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcPooledWorker_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcBindToWorker_INTERFACE_DEFINED__
-#define __ICorSvcBindToWorker_INTERFACE_DEFINED__
-
-/* interface ICorSvcBindToWorker */
-/* [unique][uuid][oleautomation][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcBindToWorker;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("5c6fb596-4828-4ed5-b9dd-293dad736fb5")
-    ICorSvcBindToWorker : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE BindToRuntimeWorker( 
-            /* [in] */ BSTR pRuntimeVersion,
-            /* [in] */ DWORD ParentProcessID,
-            /* [in] */ BSTR pInterruptEventName,
-            /* [in] */ ICorSvcLogger *pCorSvcLogger,
-            /* [out] */ ICorSvcWorker **pCorSvcWorker) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcBindToWorkerVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcBindToWorker * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcBindToWorker * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcBindToWorker * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *BindToRuntimeWorker )( 
-            ICorSvcBindToWorker * This,
-            /* [in] */ BSTR pRuntimeVersion,
-            /* [in] */ DWORD ParentProcessID,
-            /* [in] */ BSTR pInterruptEventName,
-            /* [in] */ ICorSvcLogger *pCorSvcLogger,
-            /* [out] */ ICorSvcWorker **pCorSvcWorker);
-        
-        END_INTERFACE
-    } ICorSvcBindToWorkerVtbl;
-
-    interface ICorSvcBindToWorker
-    {
-        CONST_VTBL struct ICorSvcBindToWorkerVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcBindToWorker_QueryInterface(This,riid,ppvObject)        \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcBindToWorker_AddRef(This)       \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcBindToWorker_Release(This)      \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcBindToWorker_BindToRuntimeWorker(This,pRuntimeVersion,ParentProcessID,pInterruptEventName,pCorSvcLogger,pCorSvcWorker)  \
-    ( (This)->lpVtbl -> BindToRuntimeWorker(This,pRuntimeVersion,ParentProcessID,pInterruptEventName,pCorSvcLogger,pCorSvcWorker) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcBindToWorker_INTERFACE_DEFINED__ */
-
-#endif /* __mscorsvc_LIBRARY_DEFINED__ */
-
-/* interface __MIDL_itf_mscorsvc_0000_0001 */
-/* [local] */ 
-
-typedef /* [public][public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0000_0001_0001
-    {
-        Service_NoAction       = -1,
-        Service_Start  = 0,
-        Service_Stop   = 0x1,
-        Service_Pause  = 0x2,
-        Service_Continue       = 0x3,
-        Service_Interrogate    = 0x4,
-        Service_StartPaused    = 0x5
-    }  ControlServiceAction;
-
-typedef struct _COR_SERVICE_STATUS
-    {
-    WCHAR sServiceName[ 64 ];
-    DWORD dwServiceType;
-    DWORD dwCurrentState;
-    DWORD dwControlsAccepted;
-    DWORD dwWin32ExitCode;
-    DWORD dwServiceSpecificExitCode;
-    DWORD dwCheckPoint;
-    DWORD dwWaitHint;
-    }  COR_SERVICE_STATUS;
-
-typedef struct _COR_SERVICE_STATUS *LPCOR_SERVICE_STATUS;
-
-typedef struct _ServiceOptions
-    {
-    BOOL RunAsWindowsService;
-    BOOL RunAsPrivateRuntime;
-    BOOL StartPaused;
-    }  ServiceOptions;
-
-
-
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0001_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0001_v0_0_s_ifspec;
-
-#ifndef __ICorSvc_INTERFACE_DEFINED__
-#define __ICorSvc_INTERFACE_DEFINED__
-
-/* interface ICorSvc */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvc;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("3eef5ff0-3680-4f20-8a8f-9051aca66b22")
-    ICorSvc : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE GetServiceManagerInterface( 
-            /* [in] */ IUnknown **pIUnknown) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE InstallService( void) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE UninstallService( void) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE ControlService( 
-            /* [in] */ ControlServiceAction Action,
-            /* [out] */ LPCOR_SERVICE_STATUS lpServiceStatus) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE RunService( 
-            /* [in] */ ServiceOptions options) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvc * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvc * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvc * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *GetServiceManagerInterface )( 
-            ICorSvc * This,
-            /* [in] */ IUnknown **pIUnknown);
-        
-        HRESULT ( STDMETHODCALLTYPE *InstallService )( 
-            ICorSvc * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *UninstallService )( 
-            ICorSvc * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *ControlService )( 
-            ICorSvc * This,
-            /* [in] */ ControlServiceAction Action,
-            /* [out] */ LPCOR_SERVICE_STATUS lpServiceStatus);
-        
-        HRESULT ( STDMETHODCALLTYPE *RunService )( 
-            ICorSvc * This,
-            /* [in] */ ServiceOptions options);
-        
-        END_INTERFACE
-    } ICorSvcVtbl;
-
-    interface ICorSvc
-    {
-        CONST_VTBL struct ICorSvcVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvc_QueryInterface(This,riid,ppvObject)    \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvc_AddRef(This)   \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvc_Release(This)  \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvc_GetServiceManagerInterface(This,pIUnknown)     \
-    ( (This)->lpVtbl -> GetServiceManagerInterface(This,pIUnknown) ) 
-
-#define ICorSvc_InstallService(This)   \
-    ( (This)->lpVtbl -> InstallService(This) ) 
-
-#define ICorSvc_UninstallService(This) \
-    ( (This)->lpVtbl -> UninstallService(This) ) 
-
-#define ICorSvc_ControlService(This,Action,lpServiceStatus)    \
-    ( (This)->lpVtbl -> ControlService(This,Action,lpServiceStatus) ) 
-
-#define ICorSvc_RunService(This,options)       \
-    ( (This)->lpVtbl -> RunService(This,options) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvc_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICompileProgressNotification_INTERFACE_DEFINED__
-#define __ICompileProgressNotification_INTERFACE_DEFINED__
-
-/* interface ICompileProgressNotification */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICompileProgressNotification;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("01c10030-6c81-4671-bd51-14b184c673b2")
-    ICompileProgressNotification : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE CompileStarted( 
-            /* [in] */ DWORD cAssembliesToCompile,
-            /* [in] */ DWORD cTimeEstimate) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE ProgressNotification( 
-            /* [in] */ DWORD cAssembly,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BOOL isStartNotification,
-            /* [in] */ HRESULT hrResult,
-            /* [in] */ BSTR errorExplanation,
-            /* [in] */ DWORD cTimeRemainingEstimate) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICompileProgressNotificationVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICompileProgressNotification * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICompileProgressNotification * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICompileProgressNotification * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *CompileStarted )( 
-            ICompileProgressNotification * This,
-            /* [in] */ DWORD cAssembliesToCompile,
-            /* [in] */ DWORD cTimeEstimate);
-        
-        HRESULT ( STDMETHODCALLTYPE *ProgressNotification )( 
-            ICompileProgressNotification * This,
-            /* [in] */ DWORD cAssembly,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BOOL isStartNotification,
-            /* [in] */ HRESULT hrResult,
-            /* [in] */ BSTR errorExplanation,
-            /* [in] */ DWORD cTimeRemainingEstimate);
-        
-        END_INTERFACE
-    } ICompileProgressNotificationVtbl;
-
-    interface ICompileProgressNotification
-    {
-        CONST_VTBL struct ICompileProgressNotificationVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICompileProgressNotification_QueryInterface(This,riid,ppvObject)       \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICompileProgressNotification_AddRef(This)      \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICompileProgressNotification_Release(This)     \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICompileProgressNotification_CompileStarted(This,cAssembliesToCompile,cTimeEstimate)   \
-    ( (This)->lpVtbl -> CompileStarted(This,cAssembliesToCompile,cTimeEstimate) ) 
-
-#define ICompileProgressNotification_ProgressNotification(This,cAssembly,pAssemblyName,isStartNotification,hrResult,errorExplanation,cTimeRemainingEstimate)   \
-    ( (This)->lpVtbl -> ProgressNotification(This,cAssembly,pAssemblyName,isStartNotification,hrResult,errorExplanation,cTimeRemainingEstimate) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICompileProgressNotification_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICompileProgressNotification2_INTERFACE_DEFINED__
-#define __ICompileProgressNotification2_INTERFACE_DEFINED__
-
-/* interface ICompileProgressNotification2 */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICompileProgressNotification2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("98E5BDE2-E9A0-4ADE-9CB2-6CD06FDB1A85")
-    ICompileProgressNotification2 : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE CompileStarted( 
-            /* [in] */ DWORD cAssembliesToCompile,
-            /* [in] */ DWORD cTimeEstimate,
-            /* [in] */ DWORD threadID) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE ProgressNotification( 
-            /* [in] */ DWORD cAssembly,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BOOL isStartNotification,
-            /* [in] */ HRESULT hrResult,
-            /* [in] */ BSTR errorExplanation,
-            /* [in] */ DWORD cTimeRemainingEstimate,
-            /* [in] */ DWORD threadID) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICompileProgressNotification2Vtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICompileProgressNotification2 * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICompileProgressNotification2 * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICompileProgressNotification2 * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *CompileStarted )( 
-            ICompileProgressNotification2 * This,
-            /* [in] */ DWORD cAssembliesToCompile,
-            /* [in] */ DWORD cTimeEstimate,
-            /* [in] */ DWORD threadID);
-        
-        HRESULT ( STDMETHODCALLTYPE *ProgressNotification )( 
-            ICompileProgressNotification2 * This,
-            /* [in] */ DWORD cAssembly,
-            /* [in] */ BSTR pAssemblyName,
-            /* [in] */ BOOL isStartNotification,
-            /* [in] */ HRESULT hrResult,
-            /* [in] */ BSTR errorExplanation,
-            /* [in] */ DWORD cTimeRemainingEstimate,
-            /* [in] */ DWORD threadID);
-        
-        END_INTERFACE
-    } ICompileProgressNotification2Vtbl;
-
-    interface ICompileProgressNotification2
-    {
-        CONST_VTBL struct ICompileProgressNotification2Vtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICompileProgressNotification2_QueryInterface(This,riid,ppvObject)      \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICompileProgressNotification2_AddRef(This)     \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICompileProgressNotification2_Release(This)    \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICompileProgressNotification2_CompileStarted(This,cAssembliesToCompile,cTimeEstimate,threadID) \
-    ( (This)->lpVtbl -> CompileStarted(This,cAssembliesToCompile,cTimeEstimate,threadID) ) 
-
-#define ICompileProgressNotification2_ProgressNotification(This,cAssembly,pAssemblyName,isStartNotification,hrResult,errorExplanation,cTimeRemainingEstimate,threadID) \
-    ( (This)->lpVtbl -> ProgressNotification(This,cAssembly,pAssemblyName,isStartNotification,hrResult,errorExplanation,cTimeRemainingEstimate,threadID) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICompileProgressNotification2_INTERFACE_DEFINED__ */
-
-
-/* interface __MIDL_itf_mscorsvc_0000_0004 */
-/* [local] */ 
-
-typedef /* [public][public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0000_0004_0001
-    {
-        DefaultOptimizeFlags   = 0,
-        TolerateCompilationFailures    = 0x1,
-        OptimizeNGenQueueOnly  = 0x2
-    }  OptimizeFlags;
-
-
-
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0004_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0004_v0_0_s_ifspec;
-
-#ifndef __ICorSvcInstaller_INTERFACE_DEFINED__
-#define __ICorSvcInstaller_INTERFACE_DEFINED__
-
-/* interface ICorSvcInstaller */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcInstaller;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("0523feee-eb0e-4857-b2aa-db787521d077")
-    ICorSvcInstaller : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE Install( 
-            /* [in] */ BSTR path) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE Uninstall( 
-            /* [in] */ BSTR path) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE Optimize( 
-            /* [in] */ ICompileProgressNotification *pCompileProgressNotification,
-            /* [in] */ OptimizeFlags optimizeFlags) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE SetLogger( 
-            /* [in] */ ICorSvcLogger *pCorSvcLogger) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcInstallerVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcInstaller * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcInstaller * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcInstaller * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *Install )( 
-            ICorSvcInstaller * This,
-            /* [in] */ BSTR path);
-        
-        HRESULT ( STDMETHODCALLTYPE *Uninstall )( 
-            ICorSvcInstaller * This,
-            /* [in] */ BSTR path);
-        
-        HRESULT ( STDMETHODCALLTYPE *Optimize )( 
-            ICorSvcInstaller * This,
-            /* [in] */ ICompileProgressNotification *pCompileProgressNotification,
-            /* [in] */ OptimizeFlags optimizeFlags);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetLogger )( 
-            ICorSvcInstaller * This,
-            /* [in] */ ICorSvcLogger *pCorSvcLogger);
-        
-        END_INTERFACE
-    } ICorSvcInstallerVtbl;
-
-    interface ICorSvcInstaller
-    {
-        CONST_VTBL struct ICorSvcInstallerVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcInstaller_QueryInterface(This,riid,ppvObject)   \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcInstaller_AddRef(This)  \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcInstaller_Release(This) \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcInstaller_Install(This,path)    \
-    ( (This)->lpVtbl -> Install(This,path) ) 
-
-#define ICorSvcInstaller_Uninstall(This,path)  \
-    ( (This)->lpVtbl -> Uninstall(This,path) ) 
-
-#define ICorSvcInstaller_Optimize(This,pCompileProgressNotification,optimizeFlags)     \
-    ( (This)->lpVtbl -> Optimize(This,pCompileProgressNotification,optimizeFlags) ) 
-
-#define ICorSvcInstaller_SetLogger(This,pCorSvcLogger) \
-    ( (This)->lpVtbl -> SetLogger(This,pCorSvcLogger) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcInstaller_INTERFACE_DEFINED__ */
-
-
-/* interface __MIDL_itf_mscorsvc_0000_0005 */
-/* [local] */ 
-
-typedef /* [public][public][public][public][public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0000_0005_0001
-    {
-        DefaultFlags   = 0,
-        AllowPartialNames      = 0x1,
-        KeepPriority   = 0x2,
-        NoRoot = 0x4
-    }  GeneralFlags;
-
-typedef /* [public][public][public][public][public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0000_0005_0002
-    {
-        Priority_None  = -1,
-        Priority_0     = 0,
-        Priority_1     = 0x1,
-        Priority_2     = 0x2,
-        Priority_3     = 0x3,
-        Priority_Default       = Priority_3,
-        Priority_Lowest        = Priority_3,
-        Priority_LowestAggressive      = Priority_2,
-        Priority_Highest       = Priority_0,
-        Priority_Highest_Root  = Priority_1,
-        Priority_Lowest_Root   = Priority_3
-    }  PriorityLevel;
-
-
-
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0005_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0005_v0_0_s_ifspec;
-
-#ifndef __ICorSvcAdvancedInstaller_INTERFACE_DEFINED__
-#define __ICorSvcAdvancedInstaller_INTERFACE_DEFINED__
-
-/* interface ICorSvcAdvancedInstaller */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcAdvancedInstaller;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("0871fb80-3ea0-47cc-9b51-d92e2aee75db")
-    ICorSvcAdvancedInstaller : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE Install( 
-            /* [in] */ BSTR path,
-            /* [in] */ OptimizationScenario optScenario,
-            /* [in] */ BSTR config,
-            /* [in] */ GeneralFlags generalFlags,
-            /* [in] */ PriorityLevel priorityLevel) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE Uninstall( 
-            /* [in] */ BSTR path,
-            /* [in] */ OptimizationScenario optScenario,
-            /* [in] */ BSTR config,
-            /* [in] */ GeneralFlags generalFlags) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcAdvancedInstallerVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcAdvancedInstaller * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcAdvancedInstaller * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcAdvancedInstaller * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *Install )( 
-            ICorSvcAdvancedInstaller * This,
-            /* [in] */ BSTR path,
-            /* [in] */ OptimizationScenario optScenario,
-            /* [in] */ BSTR config,
-            /* [in] */ GeneralFlags generalFlags,
-            /* [in] */ PriorityLevel priorityLevel);
-        
-        HRESULT ( STDMETHODCALLTYPE *Uninstall )( 
-            ICorSvcAdvancedInstaller * This,
-            /* [in] */ BSTR path,
-            /* [in] */ OptimizationScenario optScenario,
-            /* [in] */ BSTR config,
-            /* [in] */ GeneralFlags generalFlags);
-        
-        END_INTERFACE
-    } ICorSvcAdvancedInstallerVtbl;
-
-    interface ICorSvcAdvancedInstaller
-    {
-        CONST_VTBL struct ICorSvcAdvancedInstallerVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcAdvancedInstaller_QueryInterface(This,riid,ppvObject)   \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcAdvancedInstaller_AddRef(This)  \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcAdvancedInstaller_Release(This) \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcAdvancedInstaller_Install(This,path,optScenario,config,generalFlags,priorityLevel)      \
-    ( (This)->lpVtbl -> Install(This,path,optScenario,config,generalFlags,priorityLevel) ) 
-
-#define ICorSvcAdvancedInstaller_Uninstall(This,path,optScenario,config,generalFlags)  \
-    ( (This)->lpVtbl -> Uninstall(This,path,optScenario,config,generalFlags) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcAdvancedInstaller_INTERFACE_DEFINED__ */
-
-
-/* interface __MIDL_itf_mscorsvc_0000_0006 */
-/* [local] */ 
-
-typedef /* [public][public][public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0000_0006_0001
-    {
-        UpdateDefault  = 0,
-        Force  = 0x1,
-        PostReboot     = 0x2
-    }  UpdateFlags;
-
-
-
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0006_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0006_v0_0_s_ifspec;
-
-#ifndef __ICorSvcOptimizer_INTERFACE_DEFINED__
-#define __ICorSvcOptimizer_INTERFACE_DEFINED__
-
-/* interface ICorSvcOptimizer */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcOptimizer;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("94af0ec4-c10d-45d4-a625-d68d1b02a396")
-    ICorSvcOptimizer : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE Update( 
-            /* [in] */ BSTR path,
-            /* [in] */ UpdateFlags updateFlags,
-            /* [in] */ GeneralFlags generalFlags) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE Display( 
-            /* [in] */ BSTR path,
-            /* [in] */ GeneralFlags generalFlags) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE ScheduleWork( 
-            /* [in] */ PriorityLevel priorityLevel) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcOptimizerVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcOptimizer * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcOptimizer * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcOptimizer * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *Update )( 
-            ICorSvcOptimizer * This,
-            /* [in] */ BSTR path,
-            /* [in] */ UpdateFlags updateFlags,
-            /* [in] */ GeneralFlags generalFlags);
-        
-        HRESULT ( STDMETHODCALLTYPE *Display )( 
-            ICorSvcOptimizer * This,
-            /* [in] */ BSTR path,
-            /* [in] */ GeneralFlags generalFlags);
-        
-        HRESULT ( STDMETHODCALLTYPE *ScheduleWork )( 
-            ICorSvcOptimizer * This,
-            /* [in] */ PriorityLevel priorityLevel);
-        
-        END_INTERFACE
-    } ICorSvcOptimizerVtbl;
-
-    interface ICorSvcOptimizer
-    {
-        CONST_VTBL struct ICorSvcOptimizerVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcOptimizer_QueryInterface(This,riid,ppvObject)   \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcOptimizer_AddRef(This)  \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcOptimizer_Release(This) \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcOptimizer_Update(This,path,updateFlags,generalFlags)    \
-    ( (This)->lpVtbl -> Update(This,path,updateFlags,generalFlags) ) 
-
-#define ICorSvcOptimizer_Display(This,path,generalFlags)       \
-    ( (This)->lpVtbl -> Display(This,path,generalFlags) ) 
-
-#define ICorSvcOptimizer_ScheduleWork(This,priorityLevel)      \
-    ( (This)->lpVtbl -> ScheduleWork(This,priorityLevel) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcOptimizer_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcOptimizer2_INTERFACE_DEFINED__
-#define __ICorSvcOptimizer2_INTERFACE_DEFINED__
-
-/* interface ICorSvcOptimizer2 */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcOptimizer2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("ee3b09c2-0110-4b6e-a73f-a3d6562f98ab")
-    ICorSvcOptimizer2 : public ICorSvcOptimizer
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE CreatePdb( 
-            /* [in] */ BSTR nativeImagePath,
-            /* [in] */ BSTR pdbPath) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcOptimizer2Vtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcOptimizer2 * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcOptimizer2 * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcOptimizer2 * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *Update )( 
-            ICorSvcOptimizer2 * This,
-            /* [in] */ BSTR path,
-            /* [in] */ UpdateFlags updateFlags,
-            /* [in] */ GeneralFlags generalFlags);
-        
-        HRESULT ( STDMETHODCALLTYPE *Display )( 
-            ICorSvcOptimizer2 * This,
-            /* [in] */ BSTR path,
-            /* [in] */ GeneralFlags generalFlags);
-        
-        HRESULT ( STDMETHODCALLTYPE *ScheduleWork )( 
-            ICorSvcOptimizer2 * This,
-            /* [in] */ PriorityLevel priorityLevel);
-        
-        HRESULT ( STDMETHODCALLTYPE *CreatePdb )( 
-            ICorSvcOptimizer2 * This,
-            /* [in] */ BSTR nativeImagePath,
-            /* [in] */ BSTR pdbPath);
-        
-        END_INTERFACE
-    } ICorSvcOptimizer2Vtbl;
-
-    interface ICorSvcOptimizer2
-    {
-        CONST_VTBL struct ICorSvcOptimizer2Vtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcOptimizer2_QueryInterface(This,riid,ppvObject)  \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcOptimizer2_AddRef(This) \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcOptimizer2_Release(This)        \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcOptimizer2_Update(This,path,updateFlags,generalFlags)   \
-    ( (This)->lpVtbl -> Update(This,path,updateFlags,generalFlags) ) 
-
-#define ICorSvcOptimizer2_Display(This,path,generalFlags)      \
-    ( (This)->lpVtbl -> Display(This,path,generalFlags) ) 
-
-#define ICorSvcOptimizer2_ScheduleWork(This,priorityLevel)     \
-    ( (This)->lpVtbl -> ScheduleWork(This,priorityLevel) ) 
-
-
-#define ICorSvcOptimizer2_CreatePdb(This,nativeImagePath,pdbPath)      \
-    ( (This)->lpVtbl -> CreatePdb(This,nativeImagePath,pdbPath) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcOptimizer2_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcOptimizer3_INTERFACE_DEFINED__
-#define __ICorSvcOptimizer3_INTERFACE_DEFINED__
-
-/* interface ICorSvcOptimizer3 */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcOptimizer3;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("6EED164F-61EE-4a07-ABE8-670F92B4B7A9")
-    ICorSvcOptimizer3 : public ICorSvcOptimizer2
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE CreatePdb2( 
-            /* [in] */ BSTR nativeImagePath,
-            /* [in] */ BSTR pdbPath,
-            /* [in] */ BOOL pdbLines,
-            /* [in] */ BSTR managedPdbSearchPath) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcOptimizer3Vtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcOptimizer3 * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcOptimizer3 * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcOptimizer3 * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *Update )( 
-            ICorSvcOptimizer3 * This,
-            /* [in] */ BSTR path,
-            /* [in] */ UpdateFlags updateFlags,
-            /* [in] */ GeneralFlags generalFlags);
-        
-        HRESULT ( STDMETHODCALLTYPE *Display )( 
-            ICorSvcOptimizer3 * This,
-            /* [in] */ BSTR path,
-            /* [in] */ GeneralFlags generalFlags);
-        
-        HRESULT ( STDMETHODCALLTYPE *ScheduleWork )( 
-            ICorSvcOptimizer3 * This,
-            /* [in] */ PriorityLevel priorityLevel);
-        
-        HRESULT ( STDMETHODCALLTYPE *CreatePdb )( 
-            ICorSvcOptimizer3 * This,
-            /* [in] */ BSTR nativeImagePath,
-            /* [in] */ BSTR pdbPath);
-        
-        HRESULT ( STDMETHODCALLTYPE *CreatePdb2 )( 
-            ICorSvcOptimizer3 * This,
-            /* [in] */ BSTR nativeImagePath,
-            /* [in] */ BSTR pdbPath,
-            /* [in] */ BOOL pdbLines,
-            /* [in] */ BSTR managedPdbSearchPath);
-        
-        END_INTERFACE
-    } ICorSvcOptimizer3Vtbl;
-
-    interface ICorSvcOptimizer3
-    {
-        CONST_VTBL struct ICorSvcOptimizer3Vtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcOptimizer3_QueryInterface(This,riid,ppvObject)  \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcOptimizer3_AddRef(This) \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcOptimizer3_Release(This)        \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcOptimizer3_Update(This,path,updateFlags,generalFlags)   \
-    ( (This)->lpVtbl -> Update(This,path,updateFlags,generalFlags) ) 
-
-#define ICorSvcOptimizer3_Display(This,path,generalFlags)      \
-    ( (This)->lpVtbl -> Display(This,path,generalFlags) ) 
-
-#define ICorSvcOptimizer3_ScheduleWork(This,priorityLevel)     \
-    ( (This)->lpVtbl -> ScheduleWork(This,priorityLevel) ) 
-
-
-#define ICorSvcOptimizer3_CreatePdb(This,nativeImagePath,pdbPath)      \
-    ( (This)->lpVtbl -> CreatePdb(This,nativeImagePath,pdbPath) ) 
-
-
-#define ICorSvcOptimizer3_CreatePdb2(This,nativeImagePath,pdbPath,pdbLines,managedPdbSearchPath)       \
-    ( (This)->lpVtbl -> CreatePdb2(This,nativeImagePath,pdbPath,pdbLines,managedPdbSearchPath) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcOptimizer3_INTERFACE_DEFINED__ */
-
-
-/* interface __MIDL_itf_mscorsvc_0000_0009 */
-/* [local] */ 
-
-typedef /* [public][public] */ 
-enum __MIDL___MIDL_itf_mscorsvc_0000_0009_0001
-    {
-        NewWorkAvailable       = 0,
-        ClientWorkStart        = 0x1,
-        ClientWorkDone = 0x2,
-        UpdatePostReboot       = 0x3,
-        NewWorkAvailableWithDelay      = 0x4
-    }  ServiceNotification;
-
-
-
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0009_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0009_v0_0_s_ifspec;
-
-#ifndef __ICorSvcManager_INTERFACE_DEFINED__
-#define __ICorSvcManager_INTERFACE_DEFINED__
-
-/* interface ICorSvcManager */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcManager;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("8f416a48-d663-4a7e-9732-fbca3fc46ea8")
-    ICorSvcManager : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE ScheduleWorkForSinglePriorityLevel( 
-            /* [in] */ PriorityLevel priorityLevel,
-            /* [in] */ BSTR pInterruptEventName,
-            /* [out] */ BOOL *pWorkScheduled) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE Optimize( 
-            /* [in] */ DWORD dwWorkerPriorityClass,
-            /* [in] */ ICompileProgressNotification *pCompileProgressNotification,
-            /* [in] */ BSTR pInterruptEventName) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE NotifyService( 
-            ServiceNotification notification) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE IsWorkAvailable( 
-            /* [in] */ PriorityLevel priorityLevel,
-            /* [out] */ BOOL *pWorkAvailable) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE Update( 
-            /* [in] */ UpdateFlags updateFlags,
-            /* [in] */ BSTR pInterruptEventName) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE SetSvcLogger( 
-            /* [in] */ ICorSvcLogger *pCorSvcLogger) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcManagerVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcManager * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcManager * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcManager * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *ScheduleWorkForSinglePriorityLevel )( 
-            ICorSvcManager * This,
-            /* [in] */ PriorityLevel priorityLevel,
-            /* [in] */ BSTR pInterruptEventName,
-            /* [out] */ BOOL *pWorkScheduled);
-        
-        HRESULT ( STDMETHODCALLTYPE *Optimize )( 
-            ICorSvcManager * This,
-            /* [in] */ DWORD dwWorkerPriorityClass,
-            /* [in] */ ICompileProgressNotification *pCompileProgressNotification,
-            /* [in] */ BSTR pInterruptEventName);
-        
-        HRESULT ( STDMETHODCALLTYPE *NotifyService )( 
-            ICorSvcManager * This,
-            ServiceNotification notification);
-        
-        HRESULT ( STDMETHODCALLTYPE *IsWorkAvailable )( 
-            ICorSvcManager * This,
-            /* [in] */ PriorityLevel priorityLevel,
-            /* [out] */ BOOL *pWorkAvailable);
-        
-        HRESULT ( STDMETHODCALLTYPE *Update )( 
-            ICorSvcManager * This,
-            /* [in] */ UpdateFlags updateFlags,
-            /* [in] */ BSTR pInterruptEventName);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetSvcLogger )( 
-            ICorSvcManager * This,
-            /* [in] */ ICorSvcLogger *pCorSvcLogger);
-        
-        END_INTERFACE
-    } ICorSvcManagerVtbl;
-
-    interface ICorSvcManager
-    {
-        CONST_VTBL struct ICorSvcManagerVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcManager_QueryInterface(This,riid,ppvObject)     \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcManager_AddRef(This)    \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcManager_Release(This)   \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcManager_ScheduleWorkForSinglePriorityLevel(This,priorityLevel,pInterruptEventName,pWorkScheduled)       \
-    ( (This)->lpVtbl -> ScheduleWorkForSinglePriorityLevel(This,priorityLevel,pInterruptEventName,pWorkScheduled) ) 
-
-#define ICorSvcManager_Optimize(This,dwWorkerPriorityClass,pCompileProgressNotification,pInterruptEventName)   \
-    ( (This)->lpVtbl -> Optimize(This,dwWorkerPriorityClass,pCompileProgressNotification,pInterruptEventName) ) 
-
-#define ICorSvcManager_NotifyService(This,notification)        \
-    ( (This)->lpVtbl -> NotifyService(This,notification) ) 
-
-#define ICorSvcManager_IsWorkAvailable(This,priorityLevel,pWorkAvailable)      \
-    ( (This)->lpVtbl -> IsWorkAvailable(This,priorityLevel,pWorkAvailable) ) 
-
-#define ICorSvcManager_Update(This,updateFlags,pInterruptEventName)    \
-    ( (This)->lpVtbl -> Update(This,updateFlags,pInterruptEventName) ) 
-
-#define ICorSvcManager_SetSvcLogger(This,pCorSvcLogger)        \
-    ( (This)->lpVtbl -> SetSvcLogger(This,pCorSvcLogger) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcManager_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcManager2_INTERFACE_DEFINED__
-#define __ICorSvcManager2_INTERFACE_DEFINED__
-
-/* interface ICorSvcManager2 */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcManager2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("29626056-8031-441b-affa-7a82480058b3")
-    ICorSvcManager2 : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE SetRuntimeVersion( 
-            BSTR version) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE SetPackageMoniker( 
-            BSTR moniker) = 0;
-        
-        virtual HRESULT STDMETHODCALLTYPE SetLocalAppData( 
-            BSTR directory) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcManager2Vtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcManager2 * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcManager2 * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcManager2 * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetRuntimeVersion )( 
-            ICorSvcManager2 * This,
-            BSTR version);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetPackageMoniker )( 
-            ICorSvcManager2 * This,
-            BSTR moniker);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetLocalAppData )( 
-            ICorSvcManager2 * This,
-            BSTR directory);
-        
-        END_INTERFACE
-    } ICorSvcManager2Vtbl;
-
-    interface ICorSvcManager2
-    {
-        CONST_VTBL struct ICorSvcManager2Vtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcManager2_QueryInterface(This,riid,ppvObject)    \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcManager2_AddRef(This)   \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcManager2_Release(This)  \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcManager2_SetRuntimeVersion(This,version)        \
-    ( (This)->lpVtbl -> SetRuntimeVersion(This,version) ) 
-
-#define ICorSvcManager2_SetPackageMoniker(This,moniker)        \
-    ( (This)->lpVtbl -> SetPackageMoniker(This,moniker) ) 
-
-#define ICorSvcManager2_SetLocalAppData(This,directory)        \
-    ( (This)->lpVtbl -> SetLocalAppData(This,directory) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcManager2_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcSetLegacyServiceBehavior_INTERFACE_DEFINED__
-#define __ICorSvcSetLegacyServiceBehavior_INTERFACE_DEFINED__
-
-/* interface ICorSvcSetLegacyServiceBehavior */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcSetLegacyServiceBehavior;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("35e5d609-ec3d-4fc2-9ba2-5f99e42ff42f")
-    ICorSvcSetLegacyServiceBehavior : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE SetLegacyServiceBehavior( void) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcSetLegacyServiceBehaviorVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcSetLegacyServiceBehavior * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcSetLegacyServiceBehavior * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcSetLegacyServiceBehavior * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetLegacyServiceBehavior )( 
-            ICorSvcSetLegacyServiceBehavior * This);
-        
-        END_INTERFACE
-    } ICorSvcSetLegacyServiceBehaviorVtbl;
-
-    interface ICorSvcSetLegacyServiceBehavior
-    {
-        CONST_VTBL struct ICorSvcSetLegacyServiceBehaviorVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcSetLegacyServiceBehavior_QueryInterface(This,riid,ppvObject)    \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcSetLegacyServiceBehavior_AddRef(This)   \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcSetLegacyServiceBehavior_Release(This)  \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcSetLegacyServiceBehavior_SetLegacyServiceBehavior(This) \
-    ( (This)->lpVtbl -> SetLegacyServiceBehavior(This) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcSetLegacyServiceBehavior_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcSetTaskBootTriggerState_INTERFACE_DEFINED__
-#define __ICorSvcSetTaskBootTriggerState_INTERFACE_DEFINED__
-
-/* interface ICorSvcSetTaskBootTriggerState */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcSetTaskBootTriggerState;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("115466A4-7005-4CA3-971F-01F0A2C8EF09")
-    ICorSvcSetTaskBootTriggerState : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE SetTaskBootTriggerState( 
-            BOOL bEnabled) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcSetTaskBootTriggerStateVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcSetTaskBootTriggerState * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcSetTaskBootTriggerState * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcSetTaskBootTriggerState * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetTaskBootTriggerState )( 
-            ICorSvcSetTaskBootTriggerState * This,
-            BOOL bEnabled);
-        
-        END_INTERFACE
-    } ICorSvcSetTaskBootTriggerStateVtbl;
-
-    interface ICorSvcSetTaskBootTriggerState
-    {
-        CONST_VTBL struct ICorSvcSetTaskBootTriggerStateVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcSetTaskBootTriggerState_QueryInterface(This,riid,ppvObject)     \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcSetTaskBootTriggerState_AddRef(This)    \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcSetTaskBootTriggerState_Release(This)   \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcSetTaskBootTriggerState_SetTaskBootTriggerState(This,bEnabled)  \
-    ( (This)->lpVtbl -> SetTaskBootTriggerState(This,bEnabled) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcSetTaskBootTriggerState_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICorSvcSetTaskDelayStartTriggerState_INTERFACE_DEFINED__
-#define __ICorSvcSetTaskDelayStartTriggerState_INTERFACE_DEFINED__
-
-/* interface ICorSvcSetTaskDelayStartTriggerState */
-/* [unique][uuid][object] */ 
-
-
-EXTERN_C const IID IID_ICorSvcSetTaskDelayStartTriggerState;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-    
-    MIDL_INTERFACE("261DD1E3-F07E-4B8D-B54E-F26889413626")
-    ICorSvcSetTaskDelayStartTriggerState : public IUnknown
-    {
-    public:
-        virtual HRESULT STDMETHODCALLTYPE SetTaskDelayStartTriggerState( 
-            BOOL bEnabled) = 0;
-        
-    };
-    
-    
-#else  /* C style interface */
-
-    typedef struct ICorSvcSetTaskDelayStartTriggerStateVtbl
-    {
-        BEGIN_INTERFACE
-        
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
-            ICorSvcSetTaskDelayStartTriggerState * This,
-            /* [in] */ REFIID riid,
-            /* [annotation][iid_is][out] */ 
-            _COM_Outptr_  void **ppvObject);
-        
-        ULONG ( STDMETHODCALLTYPE *AddRef )( 
-            ICorSvcSetTaskDelayStartTriggerState * This);
-        
-        ULONG ( STDMETHODCALLTYPE *Release )( 
-            ICorSvcSetTaskDelayStartTriggerState * This);
-        
-        HRESULT ( STDMETHODCALLTYPE *SetTaskDelayStartTriggerState )( 
-            ICorSvcSetTaskDelayStartTriggerState * This,
-            BOOL bEnabled);
-        
-        END_INTERFACE
-    } ICorSvcSetTaskDelayStartTriggerStateVtbl;
-
-    interface ICorSvcSetTaskDelayStartTriggerState
-    {
-        CONST_VTBL struct ICorSvcSetTaskDelayStartTriggerStateVtbl *lpVtbl;
-    };
-
-    
-
-#ifdef COBJMACROS
-
-
-#define ICorSvcSetTaskDelayStartTriggerState_QueryInterface(This,riid,ppvObject)       \
-    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
-
-#define ICorSvcSetTaskDelayStartTriggerState_AddRef(This)      \
-    ( (This)->lpVtbl -> AddRef(This) ) 
-
-#define ICorSvcSetTaskDelayStartTriggerState_Release(This)     \
-    ( (This)->lpVtbl -> Release(This) ) 
-
-
-#define ICorSvcSetTaskDelayStartTriggerState_SetTaskDelayStartTriggerState(This,bEnabled)      \
-    ( (This)->lpVtbl -> SetTaskDelayStartTriggerState(This,bEnabled) ) 
-
-#endif /* COBJMACROS */
-
-
-#endif         /* C style interface */
-
-
-
-
-#endif         /* __ICorSvcSetTaskDelayStartTriggerState_INTERFACE_DEFINED__ */
-
-
-/* Additional Prototypes for ALL interfaces */
-
-unsigned long             __RPC_USER  BSTR_UserSize(     unsigned long *, unsigned long            , BSTR * ); 
-unsigned char * __RPC_USER  BSTR_UserMarshal(  unsigned long *, unsigned char *, BSTR * ); 
-unsigned char * __RPC_USER  BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * ); 
-void                      __RPC_USER  BSTR_UserFree(     unsigned long *, BSTR * ); 
-
-/* end of Additional Prototypes */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-
index 3f7278de34a86d3519be846dc4e8c3ef9884cf46..8eccc070641f89ab6b6e3cec3b6113acaccf2604 100644 (file)
@@ -33,6 +33,9 @@ if(CLR_CMAKE_HOST_ARCH_AMD64)
   set(PAL_ARCH_SOURCES_DIR amd64)
 elseif(CLR_CMAKE_HOST_ARCH_ARM)
   set(PAL_ARCH_SOURCES_DIR arm)
+elseif(CLR_CMAKE_HOST_ARCH_ARMV6)
+  set(PAL_ARCH_SOURCES_DIR arm)
+  add_definitions(-D__armv6__)
 elseif(CLR_CMAKE_HOST_ARCH_ARM64)
   set(PAL_ARCH_SOURCES_DIR arm64)
 elseif(CLR_CMAKE_HOST_ARCH_I386)
@@ -101,7 +104,6 @@ set(SOURCES
   cruntime/string.cpp
   cruntime/stringtls.cpp
   cruntime/wchar.cpp
-  cruntime/wchartls.cpp
   debug/debug.cpp
   file/directory.cpp
   file/file.cpp
@@ -113,14 +115,12 @@ set(SOURCES
   init/pal.cpp
   init/sxs.cpp
   loader/module.cpp
-  loader/modulename.cpp
   locale/unicode.cpp
   locale/unicodedata.cpp
   locale/utf8.cpp
   map/common.cpp
   map/map.cpp
   map/virtual.cpp
-  memory/local.cpp
   misc/dbgmsg.cpp
   misc/environ.cpp
   misc/error.cpp
@@ -167,7 +167,13 @@ set(SOURCES
   safecrt/xtow_s.cpp
   shmemory/shmemory.cpp
   sync/cs.cpp
+  synchobj/mutex.cpp
+  synchmgr/synchcontrollers.cpp
+  synchmgr/synchmanager.cpp
+  synchmgr/wait.cpp
+  thread/process.cpp
   thread/thread.cpp
+  thread/threadsusp.cpp
 )
 
 add_library(coreclrpal
index d7e992c090a00b89bcab3c22c5363398b0033af7..fee79c91df12b4eeacdde94f67d6835a68bc2af3 100644 (file)
@@ -86,7 +86,7 @@ static int Internal_Convertfwrite(CPalThread *pthrCurrent, const void *buffer, s
             free(newBuff);
             return -1;
         }
-        ret = InternalFwrite(newBuff, 1, count, stream, &iError);
+        ret = InternalFwrite(newBuff, 1, nsize, stream, &iError);
         if (iError != 0)
         {
             ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError);
index c2d425a48d621aefdbabe58583651721dce23cb8..6a404217d11a67528e3f6f287f846293d705aa44 100644 (file)
@@ -3,8 +3,6 @@
 
 /*++
 
-
-
 Module Name:
 
     wchar.c
@@ -13,11 +11,8 @@ Abstract:
 
     Implementation of wide char string functions.
 
-
-
 --*/
 
-
 #include "pal/palinternal.h"
 #include "pal/cruntime.h"
 #include "pal/dbgmsg.h"
@@ -25,7 +20,6 @@ Abstract:
 #include "pal/thread.hpp"
 #include "pal/threadsusp.hpp"
 
-
 #if HAVE_CONFIG_H
 #include "config.h"
 #endif
diff --git a/src/pal/src/cruntime/wchartls.cpp b/src/pal/src/cruntime/wchartls.cpp
deleted file mode 100644 (file)
index 35b7335..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/*++
-
-
-
-Module Name:
-
-    wchartls.c
-
-Abstract:
-
-    Implementation of wide char string functions that depend on per-thread data
-
-
-
---*/
-
-#include "pal/palinternal.h"
-#include "pal/thread.hpp"
-#include "pal/dbgmsg.h"
-
-using namespace CorUnix;
-
-
-SET_DEFAULT_DEBUG_CHANNEL(CRT);
-
-/*++
-Function:
-   PAL_wcstok
-
-Finds the next token in a wide character string.
-
-Return value:
-
-A pointer to the next token found in strToken.  Returns NULL when no more
-tokens are found.  Each call modifies strToken by substituting a NULL
-character for each delimiter that is encountered.
-
-Parameters:
-strToken        String containing token(s)
-strDelimit      Set of delimiter characters
-
---*/
-WCHAR *
-__cdecl
-PAL_wcstok(WCHAR *strToken, const WCHAR *strDelimit)
-{
-    CPalThread *pThread = NULL;
-    WCHAR *retval = NULL;
-    WCHAR *delim_ptr;
-    WCHAR *next_context;     /* string to save in TLS for future calls */
-
-    PERF_ENTRY(wcstok);
-    ENTRY("PAL_wcstok (strToken=%p (%S), strDelimit=%p (%S))\n",
-          strToken?strToken:W16_NULLSTRING,
-          strToken?strToken:W16_NULLSTRING,
-          strDelimit?strDelimit:W16_NULLSTRING,
-          strDelimit?strDelimit:W16_NULLSTRING);
-
-    /* Get the per-thread buffer from the thread structure. */
-    pThread = InternalGetCurrentThread();
-
-    if(NULL == strDelimit)
-    {
-        ERROR("delimiter string is NULL\n");
-        goto done;
-    }
-
-    /* get token string from TLS if none is provided */
-    if(NULL == strToken)
-    {
-        TRACE("wcstok() called with NULL string, using previous string\n");
-        strToken = pThread->crtInfo.wcstokContext;
-        if(NULL == strToken)
-        {
-            ERROR("wcstok called with NULL string without a previous call\n");
-            goto done;
-        }
-    }
-
-    /* first, skip all leading delimiters */
-    while ((*strToken != '\0') && (PAL_wcschr(strDelimit,*strToken)))
-    {
-        strToken++;
-    }
-
-    /* if there were only delimiters, there's no string */
-    if('\0' == strToken[0])
-    {
-        TRACE("end of string already reached, returning NULL\n");
-        goto done;
-    }
-
-    /* we're now at the beginning of the token; look for the first delimiter */
-    delim_ptr = PAL_wcspbrk(strToken,strDelimit);
-    if(NULL == delim_ptr)
-    {
-        TRACE("no delimiters found, this is the last token\n");
-        /* place the next context at the end of the string, so that subsequent
-           calls will return NULL */
-        next_context = strToken+PAL_wcslen(strToken);
-        retval = strToken;
-    }
-    else
-    {
-        /* null-terminate current token */
-        *delim_ptr=0;
-
-        /* place the next context right after the delimiter */
-        next_context = delim_ptr+1;
-        retval = strToken;
-
-        TRACE("found delimiter; next token will be %p\n",next_context);
-    }
-
-    pThread->crtInfo.wcstokContext = next_context;
-
-done:
-    LOGEXIT("PAL_wcstok() returns %p (%S)\n", retval?retval:W16_NULLSTRING, retval?retval:W16_NULLSTRING);
-    PERF_EXIT(wcstok);
-    return(retval);
-}
-
index 6c5a052ecbdbd0809167a372c03198841dca19d1..79bdf026003d10ef0380428a0851f67511124d3a 100644 (file)
@@ -183,17 +183,10 @@ namespace CorUnix
 
     enum PalObjectTypeId
     {
-        otiAutoResetEvent = 0,
-        otiManualResetEvent,
-        otiMutex,
-        otiNamedMutex,
-        otiSemaphore,
-        otiFile,
+        otiFile = 0,
         otiFileMapping,
-        otiSocket,
         otiProcess,
         otiThread,
-        otiIOCompletionPort,
         ObjectTypeIdCount    // This entry must come last in the enumeration
     };
 
@@ -1097,6 +1090,148 @@ namespace CorUnix
     };
 
     extern IPalObjectManager *g_pObjectManager;
+
+    enum ThreadWakeupReason
+    {
+        WaitSucceeded,
+        MutexAbondoned,
+        WaitTimeout,
+        WaitFailed
+    };
+
+    class IPalSynchronizationManager
+    {
+    public:
+
+        //
+        // A thread calls BlockThread to put itself to sleep after it has
+        // registered itself with the objects it is to wait on. A thread
+        // need not have registered with any objects, as would occur in
+        // the implementation of Sleep[Ex].
+        //
+        // Needless to say a thread must not be holding any PAL locks
+        // directly or implicitly (e.g., by holding a reference to a
+        // synchronization controller) when it calls this method.
+        //
+
+        virtual
+        PAL_ERROR
+        BlockThread(
+            CPalThread *pCurrentThread,
+            DWORD dwTimeout,
+            bool fAlertable,
+            bool fIsSleep,
+            ThreadWakeupReason *peWakeupReason, // OUT
+            DWORD *pdwSignaledObject       // OUT
+            ) = 0;
+
+        virtual
+        PAL_ERROR
+        AbandonObjectsOwnedByThread(
+            CPalThread *pCallingThread,
+            CPalThread *pTargetThread
+            ) = 0;
+
+        //
+        // This routine is primarily meant for use by WaitForMultipleObjects[Ex].
+        // The caller must individually release each of the returned controller
+        // interfaces.
+        //
+
+        virtual
+        PAL_ERROR
+        GetSynchWaitControllersForObjects(
+            CPalThread *pThread,
+            IPalObject *rgObjects[],
+            DWORD dwObjectCount,
+            ISynchWaitController *rgControllers[]
+            ) = 0;
+
+        virtual
+        PAL_ERROR
+        GetSynchStateControllersForObjects(
+            CPalThread *pThread,
+            IPalObject *rgObjects[],
+            DWORD dwObjectCount,
+            ISynchStateController *rgControllers[]
+            ) = 0;
+
+        //
+        // These following routines are meant for use only by IPalObject
+        // implementations. The first two routines are used to
+        // allocate and free an object's synchronization state; the third
+        // is called during object promotion.
+        //
+
+        virtual
+        PAL_ERROR
+        AllocateObjectSynchData(
+            CObjectType *pObjectType,
+            ObjectDomain eObjectDomain,
+            VOID **ppvSynchData                 // OUT
+            ) = 0;
+
+        virtual
+        void
+        FreeObjectSynchData(
+            CObjectType *pObjectType,
+            ObjectDomain eObjectDomain,
+            VOID *pvSynchData
+            ) = 0;
+
+        virtual
+        PAL_ERROR
+        PromoteObjectSynchData(
+            CPalThread *pThread,
+            VOID *pvLocalSynchData,
+            VOID **ppvSharedSynchData           // OUT
+            ) = 0;
+
+        //
+        // The next two routines provide access to the process-wide
+        // synchronization lock
+        //
+
+        virtual
+        void
+        AcquireProcessLock(
+            CPalThread *pThread
+            ) = 0;
+
+        virtual
+        void
+        ReleaseProcessLock(
+            CPalThread *pThread
+            ) = 0;
+
+        //
+        // The final routines are used by IPalObject::GetSynchStateController
+        // and IPalObject::GetSynchWaitController
+        //
+
+        virtual
+        PAL_ERROR
+        CreateSynchStateController(
+            CPalThread *pThread,                // IN, OPTIONAL
+            CObjectType *pObjectType,
+            VOID *pvSynchData,
+            ObjectDomain eObjectDomain,
+            ISynchStateController **ppStateController       // OUT
+            ) = 0;
+
+        virtual
+        PAL_ERROR
+        CreateSynchWaitController(
+            CPalThread *pThread,                // IN, OPTIONAL
+            CObjectType *pObjectType,
+            VOID *pvSynchData,
+            ObjectDomain eObjectDomain,
+            ISynchWaitController **ppWaitController       // OUT
+            ) = 0;
+    };
+
+    extern IPalSynchronizationManager *g_pSynchronizationManager;
+
 }
 
 #endif // _CORUNIX_H
diff --git a/src/pal/src/include/pal/modulename.h b/src/pal/src/include/pal/modulename.h
deleted file mode 100644 (file)
index 87d54b7..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/*++
-
-
-
-Module Name:
-
-    include/pal/modulename.h
-
-Abstract:
-    Header file for functions to get the name of a module
-
-Revision History:
-
-
-
---*/
-
-#ifndef _PAL_MODULENAME_H_
-#define _PAL_MODULENAME_H_
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif // __cplusplus
-
-const char *PAL_dladdr(LPVOID ProcAddress);
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif /*_PAL_MODULENAME_H_*/
diff --git a/src/pal/src/include/pal/mutex.hpp b/src/pal/src/include/pal/mutex.hpp
new file mode 100644 (file)
index 0000000..bd6dde1
--- /dev/null
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    mutex.hpp
+
+Abstract:
+
+    Mutex object structure definition.
+
+
+
+--*/
+
+#ifndef _PAL_MUTEX_H_
+#define _PAL_MUTEX_H_
+
+#include "corunix.hpp"
+#include "sharedmemory.h"
+
+#include <pthread.h>
+
+#define SYNCSPINLOCK_F_ASYMMETRIC  1
+
+#define SPINLOCKInit(lock) (*(lock) = 0)
+#define SPINLOCKDestroy SPINLOCKInit
+
+void SPINLOCKAcquire (LONG * lock, unsigned int flags);
+void SPINLOCKRelease (LONG * lock);
+DWORD SPINLOCKTryAcquire (LONG * lock);
+
+#endif //_PAL_MUTEX_H_
index e5a6f9f5a3a1dfac3c095a843446346cec068894..f023f840a53e65a1491008b735f0962c0994703a 100644 (file)
@@ -35,11 +35,58 @@ extern "C"
    calls to CreateThread from succeeding once shutdown has started
    [defined in process.c]
 */
+extern Volatile<LONG> terminator;
 
 // The process and session ID of this process, so we can avoid excessive calls to getpid() and getsid().
 extern DWORD gPID;
 extern DWORD gSID;
 
+
+/*++
+Function:
+  PROCGetProcessIDFromHandle
+
+Abstract
+  Return the process ID from a process handle
+--*/
+DWORD PROCGetProcessIDFromHandle(HANDLE hProcess);
+
+/*++
+Function:
+  PROCCleanupInitialProcess
+
+Abstract
+  Cleanup all the structures for the initial process.
+
+Parameter
+  VOID
+
+Return
+  VOID
+
+--*/
+VOID PROCCleanupInitialProcess(VOID);
+
+
+/*++
+Function:
+  PROCProcessLock
+
+Abstract
+  Enter the critical section associated to the current process
+--*/
+VOID PROCProcessLock(VOID);
+
+
+/*++
+Function:
+  PROCProcessUnlock
+
+Abstract
+  Leave the critical section associated to the current process
+--*/
+VOID PROCProcessUnlock(VOID);
+
 /*++
 Function:
   PROCAbort()
diff --git a/src/pal/src/include/pal/procobj.hpp b/src/pal/src/include/pal/procobj.hpp
new file mode 100644 (file)
index 0000000..32357c4
--- /dev/null
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    include/pal/procobj.hpp
+
+Abstract:
+    Header file for process structures
+
+
+
+--*/
+
+#ifndef _PAL_PROCOBJ_HPP_
+#define _PAL_PROCOBJ_HPP_
+
+#include "corunix.hpp"
+
+namespace CorUnix
+{
+    extern CObjectType otProcess;
+
+    typedef enum
+    {
+        PS_IDLE,
+        PS_STARTING,
+        PS_RUNNING,
+        PS_DONE
+    } PROCESS_STATE;
+
+    //
+    // Struct for process module list (EnumProcessModules)
+    //
+    struct ProcessModules
+    {
+        ProcessModules *Next;
+        PVOID BaseAddress;
+        CHAR Name[0];
+    };
+
+    //
+    // Ideally dwProcessId would be part of the process object's immutable
+    // data. Doing so, though, creates complications in CreateProcess. The
+    // contents of the immutable data for a new object must be set before
+    // that object is registered with the object manager (as the object
+    // manager may make a copy of the immutable data). The PID for a new
+    // process, though, is not known until after creation. Registering the
+    // process object after process creation creates an undesirable error path
+    // -- if we are not able to register the process object (say, because of
+    // a low resource condition) we would be forced to return an error to
+    // the caller of CreateProcess, even though the new process was actually
+    // created...
+    //
+    // Note: we could work around this by effectively always going down
+    // the create suspended path. That is, the new process would not exec until
+    // the parent process released it. It's unclear how much benefit this would
+    // provide us.
+    //
+
+    class CProcProcessLocalData
+    {
+    public:
+        CProcProcessLocalData()
+            :
+            dwProcessId(0),
+            ps(PS_IDLE),
+            dwExitCode(0),
+            lAttachCount(0),
+            pProcessModules(NULL),
+            cProcessModules(0)
+        {
+        };
+
+        ~CProcProcessLocalData();
+
+        DWORD dwProcessId;
+        PROCESS_STATE ps;
+        DWORD dwExitCode;
+        LONG lAttachCount;
+        ProcessModules *pProcessModules;
+        DWORD cProcessModules;
+    };
+
+    PAL_ERROR
+    InternalCreateProcess(
+        CPalThread *pThread,
+        LPCWSTR lpApplicationName,
+        LPWSTR lpCommandLine,
+        LPSECURITY_ATTRIBUTES lpProcessAttributes,
+        LPSECURITY_ATTRIBUTES lpThreadAttributes,
+        DWORD dwCreationFlags,
+        LPVOID lpEnvironment,
+        LPCWSTR lpCurrentDirectory,
+        LPSTARTUPINFOW lpStartupInfo,
+        LPPROCESS_INFORMATION lpProcessInformation
+        );
+
+    PAL_ERROR
+    InitializeProcessData(
+        void
+        );
+
+    PAL_ERROR
+    InitializeProcessCommandLine(
+        LPWSTR lpwstrCmdLine,
+        LPWSTR lpwstrFullPath
+        );
+
+    PAL_ERROR
+    CreateInitialProcessAndThreadObjects(
+        CPalThread *pThread
+        );
+
+    extern IPalObject *g_pobjProcess;
+}
+
+#endif // _PAL_PROCOBJ_HPP_
+
diff --git a/src/pal/src/include/pal/synchcache.hpp b/src/pal/src/include/pal/synchcache.hpp
new file mode 100644 (file)
index 0000000..821f509
--- /dev/null
@@ -0,0 +1,396 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    include/pal/synchcache.hpp
+
+Abstract:
+    Simple look-aside cache for unused objects with default
+    constructor or no constructor
+
+
+
+--*/
+
+#ifndef _SYNCH_CACHE_H_
+#define _SYNCH_CACHE_H_
+
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+
+namespace CorUnix
+{
+    template <typename T> class CSynchCache
+    {
+        typedef union _USynchCacheStackNode
+        {
+            union _USynchCacheStackNode * next;
+            BYTE objraw[sizeof(T)];
+        } USynchCacheStackNode;
+
+        static const int MaxDepth = 256;
+
+        Volatile<USynchCacheStackNode*> m_pHead;
+        CRITICAL_SECTION m_cs;
+        Volatile<int> m_iDepth;
+        int m_iMaxDepth;
+#ifdef _DEBUG
+        int m_iMaxTrackedDepth;
+#endif
+
+        void Lock(CPalThread * pthrCurrent)
+            { InternalEnterCriticalSection(pthrCurrent, &m_cs); }
+        void Unlock(CPalThread * pthrCurrent)
+            { InternalLeaveCriticalSection(pthrCurrent, &m_cs); }
+
+     public:
+        CSynchCache(int iMaxDepth = MaxDepth) :
+            m_pHead(NULL),
+            m_iDepth(0),
+            m_iMaxDepth(iMaxDepth)
+#ifdef _DEBUG
+            ,m_iMaxTrackedDepth(0)
+#endif
+        {
+            InternalInitializeCriticalSection(&m_cs);
+            if (m_iMaxDepth < 0)
+            {
+                m_iMaxDepth = 0;
+            }
+        }
+
+        ~CSynchCache()
+        {
+            Flush(NULL, true);
+            InternalDeleteCriticalSection(&m_cs);
+        }
+
+#ifdef _DEBUG
+        int GetMaxTrackedDepth() { return m_iMaxTrackedDepth; }
+#endif
+
+        T * Get(CPalThread * pthrCurrent)
+        {
+            T * pObj = NULL;
+
+            Get(pthrCurrent, 1, &pObj);
+            return pObj;
+        }
+
+        int Get(CPalThread * pthrCurrent, int n, T ** ppObjs)
+        {
+            void * pvObjRaw;
+            USynchCacheStackNode * pNode;
+            int i = 0,j;
+
+            Lock(pthrCurrent);
+            pNode = m_pHead;
+            while (pNode && i < n)
+            {
+                ppObjs[i] = (T *)pNode;
+                pNode = pNode->next;
+                i++;
+            }
+            m_pHead = pNode;
+            m_iDepth -= i;
+
+#ifdef _DEBUG
+            if (NULL == m_pHead && m_iDepth != 0)
+            {
+                // Can't use ASSERT here, since this is header
+                // is included by other headers with inline methods
+                // which causes template instatiation in the header
+                // where the DEBUG CHANNEL is not defined and cannot
+                // be defined
+                fprintf(stderr,"SYNCCACHE: Invalid cache depth value");
+                DebugBreak();
+            }
+#endif // _DEBUG
+
+            Unlock(pthrCurrent);
+
+            for (j=i;j<n;j++)
+            {
+                pvObjRaw = (void *) InternalNew<USynchCacheStackNode>();
+                if (NULL == pvObjRaw)
+                    break;
+#ifdef _DEBUG
+                memset(pvObjRaw, 0, sizeof(USynchCacheStackNode));
+#endif
+                ppObjs[j] = reinterpret_cast<T*>(pvObjRaw);
+            }
+
+            for (i=0;i<j;i++)
+            {
+                new ((void *)ppObjs[i]) T;
+            }
+
+            return j;
+        }
+
+        void Add(CPalThread * pthrCurrent, T * pobj)
+        {
+            USynchCacheStackNode * pNode = reinterpret_cast<USynchCacheStackNode *>(pobj);
+
+            if (NULL == pobj)
+            {
+                return;
+            }
+
+            pobj->~T();
+
+            Lock(pthrCurrent);
+            if (m_iDepth < m_iMaxDepth)
+            {
+#ifdef _DEBUG
+                if (m_iDepth > m_iMaxTrackedDepth)
+                {
+                    m_iMaxTrackedDepth = m_iDepth;
+                }
+#endif
+                pNode->next = m_pHead;
+                m_pHead = pNode;
+                m_iDepth++;
+            }
+            else
+            {
+                InternalDelete((char *)pNode);
+            }
+            Unlock(pthrCurrent);
+        }
+
+        void Flush(CPalThread * pthrCurrent, bool fDontLock = false)
+        {
+            USynchCacheStackNode * pNode, * pTemp;
+
+            if (!fDontLock)
+            {
+                Lock(pthrCurrent);
+            }
+            pNode = m_pHead;
+            m_pHead = NULL;
+            m_iDepth = 0;
+            if (!fDontLock)
+            {
+                Unlock(pthrCurrent);
+            }
+
+            while (pNode)
+            {
+                pTemp = pNode;
+                pNode = pNode->next;
+                InternalDelete((char *)pTemp);
+            }
+        }
+    };
+
+    template <typename T> class CSHRSynchCache
+    {
+        union _USHRSynchCacheStackNode; // fwd declaration
+        typedef struct _SHRCachePTRs
+        {
+            union _USHRSynchCacheStackNode * pNext;
+            SharedID shrid;
+        } SHRCachePTRs;
+        typedef union _USHRSynchCacheStackNode
+        {
+            SHRCachePTRs  pointers;
+            BYTE objraw[sizeof(T)];
+        } USHRSynchCacheStackNode;
+
+        static const int MaxDepth       = 256;
+        static const int PreAllocFactor = 10; // Everytime a Get finds no available
+                                              // cached raw intances, it preallocates
+                                              // MaxDepth/PreAllocFactor new raw
+                                              // instances and store them into the
+                                              // cache before continuing
+
+        Volatile<USHRSynchCacheStackNode*> m_pHead;
+        CRITICAL_SECTION m_cs;
+        Volatile<int> m_iDepth;
+        int m_iMaxDepth;
+#ifdef _DEBUG
+        int m_iMaxTrackedDepth;
+#endif
+
+        void Lock(CPalThread * pthrCurrent)
+            { InternalEnterCriticalSection(pthrCurrent, &m_cs); }
+        void Unlock(CPalThread * pthrCurrent)
+            { InternalLeaveCriticalSection(pthrCurrent, &m_cs); }
+
+     public:
+        CSHRSynchCache(int iMaxDepth = MaxDepth) :
+            m_pHead(NULL),
+            m_iDepth(0),
+            m_iMaxDepth(iMaxDepth)
+#ifdef _DEBUG
+            ,m_iMaxTrackedDepth(0)
+#endif
+        {
+            InternalInitializeCriticalSection(&m_cs);
+            if (m_iMaxDepth < 0)
+            {
+                m_iMaxDepth = 0;
+            }
+        }
+
+        ~CSHRSynchCache()
+        {
+            Flush(NULL, true);
+            InternalDeleteCriticalSection(&m_cs);
+        }
+
+#ifdef _DEBUG
+        int GetMaxTrackedDepth() { return m_iMaxTrackedDepth; }
+#endif
+
+        SharedID Get(CPalThread * pthrCurrent)
+        {
+            SharedID shridObj = NULL;
+
+            Get(pthrCurrent, 1, &shridObj);
+            return shridObj;
+        }
+
+        int Get(CPalThread * pthrCurrent, int n, SharedID * shridpObjs)
+        {
+            SharedID shridObj;
+            void * pvObjRaw = NULL;
+            USHRSynchCacheStackNode * pNode;
+            int i = 0, j, k;
+
+            Lock(pthrCurrent);
+            pNode = m_pHead;
+            while (pNode && i < n)
+            {
+                shridpObjs[i] = pNode->pointers.shrid;
+                pvObjRaw = (void *)pNode;
+                pNode = pNode->pointers.pNext;
+                i++;
+            }
+            m_pHead = pNode;
+            m_iDepth -= i;
+
+#ifdef _DEBUG
+            if (NULL == m_pHead && m_iDepth != 0)
+            {
+                    // Can't use ASSERT here, since this is header
+                    // (see comment above)
+                    fprintf(stderr,"SYNCCACHE: Invalid cache depth value");
+                    DebugBreak();
+            }
+#endif // _DEBUG
+
+            if (0 == m_iDepth)
+            {
+                for (k=0; k<m_iMaxDepth/PreAllocFactor-n+i; k++)
+                {
+                    shridObj = malloc(sizeof(USHRSynchCacheStackNode));
+                    if (NULL == shridObj)
+                    {
+                        Flush(pthrCurrent, true);
+                        break;
+                    }
+                    pNode = SharedIDToTypePointer(USHRSynchCacheStackNode, shridObj);
+#ifdef _DEBUG
+                    memset(reinterpret_cast<void*>(pNode), 0, sizeof(USHRSynchCacheStackNode));
+#endif
+                    pNode->pointers.shrid = shridObj;
+                    pNode->pointers.pNext = m_pHead;
+                    m_pHead = pNode;
+                    m_iDepth++;
+                }
+            }
+
+            Unlock(pthrCurrent);
+
+            for (j=i;j<n;j++)
+            {
+                shridObj = malloc(sizeof(USHRSynchCacheStackNode));
+                if (NULL == shridObj)
+                    break;
+#ifdef _DEBUG
+                pvObjRaw = SharedIDToPointer(shridObj);
+                memset(pvObjRaw, 0, sizeof(USHRSynchCacheStackNode));
+#endif
+                shridpObjs[j] = shridObj;
+            }
+
+            for (i=0;i<j;i++)
+            {
+                pvObjRaw = SharedIDToPointer(shridpObjs[i]);
+                new (pvObjRaw) T;
+            }
+
+            return j;
+        }
+
+        void Add(CPalThread * pthrCurrent, SharedID shridObj)
+        {
+            if (NULL == shridObj)
+            {
+                return;
+            }
+
+            USHRSynchCacheStackNode * pNode = SharedIDToTypePointer(USHRSynchCacheStackNode, shridObj);
+            T * pObj = reinterpret_cast<T *>(pNode);
+
+            pObj->~T();
+
+            pNode->pointers.shrid = shridObj;
+
+            Lock(pthrCurrent);
+            if (m_iDepth < m_iMaxDepth)
+            {
+                m_iDepth++;
+#ifdef _DEBUG
+                if (m_iDepth > m_iMaxTrackedDepth)
+                {
+                    m_iMaxTrackedDepth = m_iDepth;
+                }
+#endif
+                pNode->pointers.pNext = m_pHead;
+                m_pHead = pNode;
+            }
+            else
+            {
+                free(shridObj);
+            }
+            Unlock(pthrCurrent);
+        }
+
+        void Flush(CPalThread * pthrCurrent, bool fDontLock = false)
+        {
+            USHRSynchCacheStackNode * pNode, * pTemp;
+            SharedID shridTemp;
+
+            if (!fDontLock)
+            {
+                Lock(pthrCurrent);
+            }
+            pNode = m_pHead;
+            m_pHead = NULL;
+            m_iDepth = 0;
+            if (!fDontLock)
+            {
+                Unlock(pthrCurrent);
+            }
+
+            while (pNode)
+            {
+                pTemp = pNode;
+                pNode = pNode->pointers.pNext;
+                shridTemp = pTemp->pointers.shrid;
+                free(shridTemp);
+            }
+        }
+    };
+}
+
+#endif // _SYNCH_CACHE_H_
+
diff --git a/src/pal/src/include/pal/synchobjects.hpp b/src/pal/src/include/pal/synchobjects.hpp
new file mode 100644 (file)
index 0000000..bf53413
--- /dev/null
@@ -0,0 +1,183 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    include/pal/synchobjects.hpp
+
+Abstract:
+    Header file for synchronization manager and controllers
+
+
+
+--*/
+
+#ifndef _SINCHOBJECTS_HPP_
+#define _SINCHOBJECTS_HPP_
+
+#include "corunix.hpp"
+#include "threadinfo.hpp"
+#include "mutex.hpp"
+#include "shm.hpp"
+#include "list.h"
+
+#include <pthread.h>
+
+#define SharedID SHMPTR
+#define SharedIDToPointer(shID) SHMPTR_TO_TYPED_PTR(PVOID, shID)
+#define SharedIDToTypePointer(TYPE,shID) SHMPTR_TO_TYPED_PTR(TYPE, shID)
+
+namespace CorUnix
+{
+    DWORD InternalWaitForMultipleObjectsEx(
+        CPalThread * pthrCurrent,
+        DWORD nCount,
+        CONST HANDLE *lpHandles,
+        BOOL bWaitAll,
+        DWORD dwMilliseconds,
+        BOOL bAlertable,
+        BOOL bPrioritize = FALSE);
+
+    enum THREAD_STATE
+    {
+        TS_IDLE,
+        TS_STARTING,
+        TS_RUNNING,
+        TS_FAILED,
+        TS_DONE,
+    };
+
+    // forward declarations
+    struct _ThreadWaitInfo;
+    struct _WaitingThreadsListNode;
+    class CSynchData;
+
+    typedef struct _WaitingThreadsListNode * PWaitingThreadsListNode;
+    typedef struct _OwnedObjectsListNode * POwnedObjectsListNode;
+    typedef struct _ThreadApcInfoNode * PThreadApcInfoNode;
+
+    typedef struct _ThreadWaitInfo
+    {
+        WaitType wtWaitType;
+        WaitDomain wdWaitDomain;
+        LONG lObjCount;
+        LONG lSharedObjCount;
+        CPalThread * pthrOwner;
+        PWaitingThreadsListNode rgpWTLNodes[MAXIMUM_WAIT_OBJECTS];
+
+        _ThreadWaitInfo() : wtWaitType(SingleObject), wdWaitDomain(LocalWait),
+                            lObjCount(0), lSharedObjCount(0),
+                            pthrOwner(NULL) {}
+    } ThreadWaitInfo;
+
+    typedef struct _ThreadNativeWaitData
+    {
+        pthread_mutex_t     mutex;
+        pthread_cond_t      cond;
+        int                 iPred;
+        DWORD               dwObjectIndex;
+        ThreadWakeupReason  twrWakeupReason;
+        bool                fInitialized;
+
+        _ThreadNativeWaitData() :
+            iPred(0),
+            dwObjectIndex(0),
+            twrWakeupReason(WaitSucceeded),
+            fInitialized(false)
+        {
+        }
+
+        ~_ThreadNativeWaitData();
+    } ThreadNativeWaitData;
+
+    class CThreadSynchronizationInfo : public CThreadInfoInitializer
+    {
+        friend class CPalSynchronizationManager;
+        friend class CSynchWaitController;
+
+        THREAD_STATE           m_tsThreadState;
+        SharedID               m_shridWaitAwakened;
+        Volatile<LONG>         m_lLocalSynchLockCount;
+        Volatile<LONG>         m_lSharedSynchLockCount;
+        LIST_ENTRY             m_leOwnedObjsList;
+
+        ThreadNativeWaitData   m_tnwdNativeData;
+        ThreadWaitInfo         m_twiWaitInfo;
+
+#ifdef SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        static const int       PendingSignalingsArraySize = 10;
+        LONG                   m_lPendingSignalingCount;
+        CPalThread *           m_rgpthrPendingSignalings[PendingSignalingsArraySize];
+        LIST_ENTRY             m_lePendingSignalingsOverflowList;
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+    public:
+
+        CThreadSynchronizationInfo();
+        virtual ~CThreadSynchronizationInfo();
+
+        //
+        // CThreadInfoInitializer methods
+        //
+        virtual PAL_ERROR InitializePreCreate(void);
+
+        virtual PAL_ERROR InitializePostCreate(
+            CPalThread *pthrCurrent,
+            SIZE_T threadId,
+            DWORD dwLwpId
+            );
+
+        THREAD_STATE GetThreadState(void)
+        {
+            return m_tsThreadState;
+        };
+
+        void SetThreadState(THREAD_STATE tsThreadState)
+        {
+            m_tsThreadState = tsThreadState;
+        };
+
+        ThreadNativeWaitData * GetNativeData()
+        {
+            return &m_tnwdNativeData;
+        }
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        PAL_ERROR RunDeferredThreadConditionSignalings();
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+        // NOTE: the following methods provide non-synchronized access to
+        //       the list of owned objects for this thread. Any thread
+        //       accessing this list MUST own the appropriate
+        //       synchronization lock(s).
+        void AddObjectToOwnedList(POwnedObjectsListNode pooln);
+        void RemoveObjectFromOwnedList(POwnedObjectsListNode pooln);
+        POwnedObjectsListNode RemoveFirstObjectFromOwnedList(void);
+
+        // The following methods provide access to the native wait lock for
+        // those implementations that need a lock to protect the support for
+        // native thread blocking (e.g.: pthread conditions)
+        void AcquireNativeWaitLock(void);
+        void ReleaseNativeWaitLock(void);
+        bool TryAcquireNativeWaitLock(void);
+    };
+
+    class CPalSynchMgrController
+    {
+    public:
+        static IPalSynchronizationManager * CreatePalSynchronizationManager();
+
+        static PAL_ERROR StartWorker(CPalThread * pthrCurrent);
+
+        static PAL_ERROR PrepareForShutdown(void);
+
+        static PAL_ERROR Shutdown(CPalThread *pthrCurrent, bool fFullCleanup);
+    };
+}
+
+#endif // _SINCHOBJECTS_HPP_
+
index f335b86672fba99aefc1319f7048c1d9c2555985..735e060a80f95e6c1c92f08b0bcfb0e092df01c1 100644 (file)
@@ -28,6 +28,7 @@ Abstract:
 
 #include "threadsusp.hpp"
 #include "threadinfo.hpp"
+#include "synchobjects.hpp"
 #include <errno.h>
 
 namespace CorUnix
@@ -39,11 +40,53 @@ namespace CorUnix
         SignalHandlerThread
     };
     
+    PAL_ERROR
+    InternalCreateThread(
+        CPalThread *pThread,
+        LPSECURITY_ATTRIBUTES lpThreadAttributes,
+        DWORD dwStackSize,
+        LPTHREAD_START_ROUTINE lpStartAddress,
+        LPVOID lpParameter,
+        DWORD dwCreationFlags,
+        PalThreadType eThreadType,
+        SIZE_T* pThreadId,
+        HANDLE *phThread
+        );
+
+    PAL_ERROR
+    InternalGetThreadDataFromHandle(
+        CPalThread *pThread,
+        HANDLE hThread,
+        CPalThread **ppTargetThread,
+        IPalObject **ppobjThread
+        );
+
+    VOID
+    InternalEndCurrentThread(
+        CPalThread *pThread
+        );
+
+    PAL_ERROR
+    InternalCreateDummyThread(
+        CPalThread *pThread,
+        LPSECURITY_ATTRIBUTES lpThreadAttributes,
+        CPalThread **ppDummyThread,
+        HANDLE *phThread
+        );
+
     PAL_ERROR
     CreateThreadData(
         CPalThread **ppThread
         );
 
+    PAL_ERROR
+    CreateThreadObject(
+        CPalThread *pThread,
+        CPalThread *pNewThread,
+        HANDLE *phThread
+        );
+
     /* In the windows CRT there is a constant defined for the max width
     of a _ecvt conversion. That constant is 348. 348 for the value, plus
     the exponent value, decimal, and sign if required. */
@@ -69,15 +112,48 @@ namespace CorUnix
 
     class CPalThread
     {
+        friend
+            PAL_ERROR
+            InternalCreateThread(
+                CPalThread *,
+                LPSECURITY_ATTRIBUTES,
+                DWORD,
+                LPTHREAD_START_ROUTINE,
+                LPVOID,
+                DWORD,
+                PalThreadType,
+                SIZE_T*,
+                HANDLE*
+                );
+
+        friend
+            PAL_ERROR
+            InternalCreateDummyThread(
+                CPalThread *pThread,
+                LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                CPalThread **ppDummyThread,
+                HANDLE *phThread
+                );
+
         friend
             PAL_ERROR
             CreateThreadData(
                 CPalThread **ppThread
                 );
 
+        friend
+            PAL_ERROR
+            CreateThreadObject(
+                CPalThread *pThread,
+                CPalThread *pNewThread,
+                HANDLE *phThread
+                );
+
     private:
 
         CPalThread *m_pNext;
+        DWORD m_dwExitCode;
+        BOOL m_fExitCodeSet;
         CRITICAL_SECTION m_csLock;
         bool m_fLockInitialized;
         bool m_fIsDummy;
@@ -96,6 +172,13 @@ namespace CorUnix
 
         LONG m_lRefCount;
 
+        //
+        // The IPalObject for this thread. The thread will release its reference
+        // to this object when it exits.
+        //
+
+        IPalObject *m_pThreadObject;
+
         //
         // Thread ID info
         //
@@ -104,22 +187,76 @@ namespace CorUnix
         DWORD m_dwLwpId;
         pthread_t m_pthreadSelf;
 
+        //
+        // Start info
+        //
+
+        LPTHREAD_START_ROUTINE m_lpStartAddress;
+        LPVOID m_lpStartParameter;
+        BOOL m_bCreateSuspended;
+        PalThreadType m_eThreadType;
+
+        //
+        // pthread mutex / condition variable for gating thread startup.
+        // InternalCreateThread waits on the condition variable to determine
+        // when the new thread has reached passed all failure points in
+        // the entry routine
+        //
+
+        pthread_mutex_t m_startMutex;
+        pthread_cond_t m_startCond;
+        bool m_fStartItemsInitialized;
+        bool m_fStartStatus;
+        bool m_fStartStatusSet;
+
+        // Base address of the stack of this thread
+        void* m_stackBase;
+        // Limit address of the stack of this thread
+        void* m_stackLimit;
+        // Signal handler's alternate stack to help with stack overflow
+        void* m_alternateStack;
+
+        //
+        // The thread entry routine (called from InternalCreateThread)
+        //
+
+        static void* ThreadEntry(void * pvParam);
+
+        //
+        // Data for PAL side-by-side support
+        //
+
     public:
 
         //
         // Embedded information for areas owned by other subsystems
         //
 
+        CThreadSynchronizationInfo synchronizationInfo;
+        CThreadSuspensionInfo suspensionInfo;
         CThreadCRTInfo crtInfo;
 
         CPalThread()
             :
             m_pNext(NULL),
+            m_dwExitCode(STILL_ACTIVE),
+            m_fExitCodeSet(FALSE),
             m_fLockInitialized(FALSE),
+            m_fIsDummy(FALSE),
             m_lRefCount(1),
+            m_pThreadObject(NULL),
             m_threadId(0),
             m_dwLwpId(0),
-            m_pthreadSelf(0)
+            m_pthreadSelf(0),
+            m_lpStartAddress(NULL),
+            m_lpStartParameter(NULL),
+            m_bCreateSuspended(FALSE),
+            m_eThreadType(UserCreatedThread),
+            m_fStartItemsInitialized(FALSE),
+            m_fStartStatus(FALSE),
+            m_fStartStatusSet(FALSE),
+            m_stackBase(NULL),
+            m_stackLimit(NULL)
         {
         };
 
@@ -140,6 +277,24 @@ namespace CorUnix
             void
             );
 
+        //
+        // SetStartStatus is called by THREADEntry or InternalSuspendNewThread
+        // to inform InternalCreateThread of the results of the thread's
+        // initialization. InternalCreateThread calls WaitForStartStatus to
+        // obtain this information (and will not return to its caller until
+        // the info is available).
+        //
+
+        void
+        SetStartStatus(
+            bool fStartSucceeded
+            );
+
+        bool
+        WaitForStartStatus(
+            void
+            );
+
         void
         Lock(
             CPalThread *pThread
@@ -156,6 +311,35 @@ namespace CorUnix
             InternalLeaveCriticalSection(pThread, &m_csLock);
         };
 
+        //
+        // The following three methods provide access to the
+        // native lock used to protect thread native wait data.
+        //
+
+        void
+        AcquireNativeWaitLock(
+            void
+            )
+        {
+            synchronizationInfo.AcquireNativeWaitLock();
+        }
+
+        void
+        ReleaseNativeWaitLock(
+            void
+            )
+        {
+            synchronizationInfo.ReleaseNativeWaitLock();
+        }
+
+        bool
+        TryAcquireNativeWaitLock(
+            void
+            )
+        {
+            return synchronizationInfo.TryAcquireNativeWaitLock();
+        }
+
         static void
         SetLastError(
             DWORD dwLastError
@@ -174,6 +358,24 @@ namespace CorUnix
             return errno;
         };
 
+        void
+        SetExitCode(
+            DWORD dwExitCode
+            )
+        {
+            m_dwExitCode = dwExitCode;
+            m_fExitCodeSet = TRUE;
+        };
+
+        BOOL
+        GetExitCode(
+            DWORD *pdwExitCode
+            )
+        {
+            *pdwExitCode = m_dwExitCode;
+            return m_fExitCodeSet;
+        };
+
         SIZE_T
         GetThreadId(
             void
@@ -198,6 +400,53 @@ namespace CorUnix
             return m_pthreadSelf;
         };
 
+        LPTHREAD_START_ROUTINE
+        GetStartAddress(
+            void
+            )
+        {
+            return m_lpStartAddress;
+        };
+
+        LPVOID
+        GetStartParameter(
+            void
+            )
+        {
+            return m_lpStartParameter;
+        };
+
+        BOOL
+        GetCreateSuspended(
+            void
+            )
+        {
+            return m_bCreateSuspended;
+        };
+
+        PalThreadType
+        GetThreadType(
+            void
+            )
+        {
+            return m_eThreadType;
+        };
+
+        IPalObject *
+        GetThreadObject(
+            void
+            )
+        {
+            return m_pThreadObject;
+        }
+        BOOL
+        IsDummy(
+            void
+            )
+        {
+            return m_fIsDummy;
+        };
+
         CPalThread*
         GetNext(
             void
@@ -239,6 +488,37 @@ namespace CorUnix
             pThread = CreateCurrentThreadData();
         return pThread;
     }
+
+/***
+
+    $$TODO: These are needed only to support cross-process thread duplication
+
+    class CThreadImmutableData
+    {
+    public:
+        DWORD dwProcessId;
+    };
+
+    class CThreadSharedData
+    {
+    public:
+        DWORD dwThreadId;
+        DWORD dwExitCode;
+    };
+***/
+
+    //
+    // The process local information for a thread is just a pointer
+    // to the underlying CPalThread object.
+    //
+
+    class CThreadProcessLocalData
+    {
+    public:
+        CPalThread *pThread;
+    };
+
+    extern CObjectType otThread;
 }
 
 BOOL
index 98b8559e919bc60b028478f435285b5f175cfeeb..0c84a5183e5b8fdb9084580a0b4d8edeae039598 100644 (file)
@@ -22,13 +22,281 @@ Abstract:
 // Need this ifdef since this header is included by .c files so they can use the diagnostic function.
 #ifdef __cplusplus
 
+// Note: do not include malloc.hpp from this header. The template InternalDelete
+// needs to know the layout of class CPalThread, which includes a member of type
+// CThreadSuspensionInfo, which is defined later in this header, and it is not
+// yet known at this point.
+// If any future change should bring this issue back, the circular dependency can
+// be further broken by making the InternalDelete's CPalThread argument a
+// templatized argument, so that type checking on it takes place only at
+// instantiation time.
 #include "pal/threadinfo.hpp"
 #include "pal/thread.hpp"
 #include "pal/printfcpp.hpp"
+#include "pal/mutex.hpp"
 #include "pal/init.h"
 #include <signal.h>
-#include "pal/sharedmemory.h"
+#include <semaphore.h>
+#include <sched.h>
 
+// We have a variety of options for synchronizing thread suspensions and resumptions between the requestor and
+// target threads. Analyze the various capabilities given to us by configure and define one of three macros
+// here for simplicity:
+//  USE_POSIX_SEMAPHORES
+//  USE_SYSV_SEMAPHORES
+//  USE_PTHREAD_CONDVARS
+#if HAS_POSIX_SEMAPHORES
+
+// Favor posix semaphores.
+#define USE_POSIX_SEMAPHORES 1
+
+#if HAVE_SYS_SEMAPHORE_H
+#include <sys/semaphore.h>
+#elif HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif // HAVE_SYS_SEMAPHORE_H
+
+#elif HAS_PTHREAD_MUTEXES && HAVE_MACH_EXCEPTIONS
+
+// Can only use the pthread solution if we're not using signals since pthread mutexes are not signal safe.
+#define USE_PTHREAD_CONDVARS 1
+
+#include <pthread.h>
+
+#elif HAS_SYSV_SEMAPHORES
+
+// SYSV semaphores are our last choice since they're shared across processes so it's possible to leak them
+// on abnormal process termination.
+#define USE_SYSV_SEMAPHORES 1
+
+#include <sys/sem.h>
+#include <sys/types.h>
+
+#else
+#error "Don't know how to synchronize thread suspends and resumes on this platform"
+#endif // HAS_POSIX_SEMAPHORES
+
+#include <stdarg.h>
+
+namespace CorUnix
+{
+#ifdef _DEBUG
+#define MAX_TRACKED_CRITSECS 8
+#endif
+
+    PAL_ERROR
+    InternalResumeThread(
+        CPalThread *pthrResumer,
+        HANDLE hTarget,
+        DWORD *pdwSuspendCount
+    );
+
+    class CThreadSuspensionInfo : public CThreadInfoInitializer
+    {
+        private:
+            BOOL m_fPending; // TRUE if a suspension is pending on a thread (because the thread is in an unsafe region)
+            BOOL m_fSelfsusp; // TRUE if thread is self suspending and while thread is self suspended
+            BOOL m_fSuspendedForShutdown; // TRUE once the thread is suspended during PAL cleanup
+            int m_nBlockingPipe; // blocking pipe used for a process that was created suspended
+#ifdef _DEBUG
+            Volatile<LONG> m_lNumThreadsSuspendedByThisThread; // number of threads that this thread has suspended; used for suspension diagnostics
+#endif
+#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+            int m_nSpinlock; // thread's suspension spinlock, which is used to synchronize suspension and resumption attempts
+#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+            pthread_mutex_t m_ptmSuspmutex; // thread's suspension mutex, which is used to synchronize suspension and resumption attempts
+            BOOL m_fSuspmutexInitialized;
+#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+#if USE_POSIX_SEMAPHORES
+            sem_t m_semSusp; // suspension semaphore
+            sem_t m_semResume; // resumption semaphore
+            BOOL m_fSemaphoresInitialized;
+#elif USE_SYSV_SEMAPHORES
+            // necessary id's and sembuf structures for SysV semaphores
+            int m_nSemsuspid; // id for the suspend semaphore
+            int m_nSemrespid; // id for the resume semaphore
+            struct sembuf m_sbSemwait; // struct representing a wait operation
+            struct sembuf m_sbSempost; // struct representing a post operation
+#elif USE_PTHREAD_CONDVARS
+            pthread_cond_t m_condSusp; // suspension condition variable
+            pthread_mutex_t m_mutexSusp; // mutex associated with the condition above
+            BOOL m_fSuspended; // set to true once the suspend has been acknowledged
+
+            pthread_cond_t m_condResume; // resumption condition variable
+            pthread_mutex_t m_mutexResume; // mutex associated with the condition above
+            BOOL m_fResumed; // set to true once the resume has been acknowledged
+
+            BOOL m_fSemaphoresInitialized;
+#endif // USE_POSIX_SEMAPHORES
+
+            /* Most of the variables above are either accessed by a thread
+            holding the appropriate suspension mutex(es) or are only
+            accessed by their own threads (and thus don't require
+            synchronization).
+
+            m_fPending, m_fSuspendedForShutdown,
+            m_fSuspendSignalSent, and m_fResumeSignalSent
+            may be set by a different thread than the owner and thus
+            require synchronization.
+
+            m_fSelfsusp is set to TRUE only by its own thread but may be later
+            accessed by other threads.
+
+            m_lNumThreadsSuspendedByThisThread is accessed by its owning
+            thread and therefore does not require synchronization. */
+            VOID
+            AcquireSuspensionLocks(
+                CPalThread *pthrSuspender,
+                CPalThread *pthrTarget
+            );
+
+            VOID
+            ReleaseSuspensionLocks(
+                CPalThread *pthrSuspender,
+                CPalThread *pthrTarget
+            );
+
+#if USE_POSIX_SEMAPHORES
+            sem_t*
+            GetSuspendSemaphore(
+                void
+                )
+            {
+                return &m_semSusp;
+            };
+
+            sem_t*
+            GetResumeSemaphore(
+                void
+                )
+            {
+                return &m_semResume;
+            };
+#elif USE_SYSV_SEMAPHORES
+            int
+            GetSuspendSemaphoreId(
+                void
+                )
+            {
+                return m_nSemsuspid;
+            };
+
+            sembuf*
+            GetSemaphorePostBuffer(
+                void
+                )
+            {
+                return &m_sbSempost;
+            };
+#endif // USE_POSIX_SEMAPHORES
+
+#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+            LONG*
+            GetSuspensionSpinlock(
+                void
+                )
+            {
+                return &m_nSpinlock;
+            }
+#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+            pthread_mutex_t*
+            GetSuspensionMutex(
+                void
+                )
+            {
+                return &m_ptmSuspmutex;
+            }
+#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+
+            void
+            SetSelfSusp(
+                BOOL fSelfsusp
+                )
+            {
+                m_fSelfsusp = fSelfsusp;
+            };
+
+            BOOL
+            GetSelfSusp(
+                void
+                )
+            {
+                return m_fSelfsusp;
+            };
+
+            static
+            BOOL
+            TryAcquireSuspensionLock(
+                CPalThread* pthrTarget
+            );
+
+            int GetBlockingPipe(
+                void
+                )
+            {
+                return m_nBlockingPipe;
+            };
+
+        public:
+            virtual PAL_ERROR InitializePreCreate();
+
+            CThreadSuspensionInfo()
+                : m_fPending(FALSE)
+                , m_fSelfsusp(FALSE)
+                , m_fSuspendedForShutdown(FALSE)
+                , m_nBlockingPipe(-1)
+#ifdef _DEBUG
+                , m_lNumThreadsSuspendedByThisThread(0)
+#endif // _DEBUG
+#if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+                , m_fSuspmutexInitialized(FALSE)
+#endif
+#if USE_POSIX_SEMAPHORES || USE_PTHREAD_CONDVARS
+                , m_fSemaphoresInitialized(FALSE)
+#endif
+            {
+                InitializeSuspensionLock();
+            };
+
+            virtual ~CThreadSuspensionInfo();
+            void
+            AcquireSuspensionLock(
+                CPalThread *pthrCurrent
+            );
+
+            void
+            ReleaseSuspensionLock(
+                CPalThread *pthrCurrent
+            );
+
+            PAL_ERROR
+            InternalSuspendNewThreadFromData(
+                CPalThread *pThread
+            );
+
+            PAL_ERROR
+            InternalResumeThreadFromData(
+                CPalThread *pthrResumer,
+                CPalThread *pthrTarget,
+                DWORD *pdwSuspendCount
+            );
+
+            VOID InitializeSuspensionLock();
+
+            void SetBlockingPipe(
+                int nBlockingPipe
+                )
+            {
+                m_nBlockingPipe = nBlockingPipe;
+            };
+    };
+} //end CorUnix
+
+extern const BYTE WAKEUPCODE; // use for pipe reads during self suspend.
 #endif // __cplusplus
 
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+extern LONG g_ssSuspensionLock;
+#endif
+
 #endif // _PAL_THREADSUSP_HPP
index bb9e0fe61e861074e9e5033263b377c0a56c1b58..83cf2b104c1ff9ef75d594e464a033ab5d80aa18 100644 (file)
@@ -24,7 +24,6 @@ Abstract:
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <minipal/utils.h>
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Alignment helpers (copied for PAL use from stdmacros.h)
index 21f36c04b8c2024b74dcd5d7bac097785f1e1946..7f1127027faacfbb63018ea60cec592473a6f7ec 100644 (file)
@@ -17,13 +17,17 @@ Abstract:
 SET_DEFAULT_DEBUG_CHANNEL(PAL); // some headers have code with asserts, so do this first
 
 #include "pal/thread.hpp"
+#include "pal/synchobjects.hpp"
+#include "pal/procobj.hpp"
 #include "pal/cs.hpp"
 #include "pal/file.hpp"
 #include "pal/map.hpp"
 #include "../objmgr/shmobjectmanager.hpp"
 #include "pal/palinternal.h"
 #include "pal/sharedmemory.h"
+#include "pal/shmemory.h"
 #include "pal/process.h"
+#include "../thread/procprivate.hpp"
 #include "pal/module.h"
 #include "pal/virtual.h"
 #include "pal/misc.h"
@@ -91,6 +95,7 @@ using namespace CorUnix;
 extern "C" BOOL CRTInitStdStreams( void );
 
 Volatile<INT> init_count = 0;
+Volatile<BOOL> shutdown_intent = 0;
 static BOOL g_fThreadDataAvailable = FALSE;
 static pthread_mutex_t init_critsec_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -107,16 +112,6 @@ static PCRITICAL_SECTION init_critsec = NULL;
 static int Initialize(int argc, const char *const argv[], DWORD flags);
 static BOOL INIT_IncreaseDescriptorLimit(void);
 
-// Process and session ID of this process.
-DWORD gPID = (DWORD) -1;
-DWORD gSID = (DWORD) -1;
-
-//
-// Key used for associating CPalThread's with the underlying pthread
-// (through pthread_setspecific)
-//
-pthread_key_t CorUnix::thObjKey;
-
 #if defined(__APPLE__)
 static bool RunningNatively()
 {
@@ -132,12 +127,15 @@ static bool RunningNatively()
 }
 #endif // __APPLE__
 
+
 /*++
 Function:
-  PAL_InitializeDLL
+  PAL_InitializeWithFlags
 
 Abstract:
-    Initializes the non-runtime DLLs/modules like the DAC and SOS.
+  This function is the first function of the PAL to be called.
+  Internal structure initialization is done here. It could be called
+  several time by the same process, a reference count is kept.
 
 Return:
   0 if successful
@@ -146,35 +144,32 @@ Return:
 --*/
 int
 PALAPI
-PAL_InitializeDLL()
+PAL_InitializeWithFlags(
+    int argc,
+    const char *const argv[],
+    DWORD flags)
 {
-    return Initialize(0, NULL, PAL_INITIALIZE_DLL);
+    return Initialize(argc, argv, flags);
 }
 
-#ifdef ENSURE_PRIMARY_STACK_SIZE
 /*++
 Function:
-  EnsureStackSize
+  PAL_InitializeDLL
 
 Abstract:
-  This fixes a problem on MUSL where the initial stack size reported by the
-  pthread_attr_getstack is about 128kB, but this limit is not fixed and
-  the stack can grow dynamically. The problem is that it makes the
-  functions ReflectionInvocation::[Try]EnsureSufficientExecutionStack
-  to fail for real life scenarios like e.g. compilation of corefx.
-  Since there is no real fixed limit for the stack, the code below
-  ensures moving the stack limit to a value that makes reasonable
-  real life scenarios work.
+    Initializes the non-runtime DLLs/modules like the DAC and SOS.
+
+Return:
+  0 if successful
+  -1 if it failed
 
 --*/
-__attribute__((noinline,NOOPT_ATTRIBUTE))
-void
-EnsureStackSize(SIZE_T stackSize)
+int
+PALAPI
+PAL_InitializeDLL()
 {
-    volatile uint8_t *s = (uint8_t *)_alloca(stackSize);
-    *s = 0;
+    return Initialize(0, NULL, PAL_INITIALIZE_DLL);
 }
-#endif // ENSURE_PRIMARY_STACK_SIZE
 
 /*++
 Function:
@@ -187,20 +182,6 @@ Abstract:
 void
 InitializeDefaultStackSize()
 {
-    char* defaultStackSizeStr = getenv("COMPlus_DefaultStackSize");
-    if (defaultStackSizeStr != NULL)
-    {
-        errno = 0;
-        // Like all numeric values specific by the COMPlus_xxx variables, it is a
-        // hexadecimal string without any prefix.
-        long int size = strtol(defaultStackSizeStr, NULL, 16);
-
-        if (errno == 0)
-        {
-            g_defaultStackSize = std::max(size, (long int)PTHREAD_STACK_MIN);
-        }
-    }
-
 #ifdef ENSURE_PRIMARY_STACK_SIZE
     if (g_defaultStackSize == 0)
     {
@@ -301,14 +282,6 @@ Initialize(
 
         InitializeDefaultStackSize();
 
-#ifdef ENSURE_PRIMARY_STACK_SIZE
-        if (flags & PAL_INITIALIZE_ENSURE_STACK_SIZE)
-        {
-            EnsureStackSize(g_defaultStackSize);
-        }
-#endif // ENSURE_PRIMARY_STACK_SIZE
-
-
         // Initialize the environment.
         if (FALSE == EnvironInitialize())
         {
@@ -324,7 +297,25 @@ Initialize(
             // we use large numbers of threads or have many open files.
         }
 
+        /* initialize the shared memory infrastructure */
+        if (!SHMInitialize())
+        {
+            ERROR("Shared memory initialization failed!\n");
+            palError = ERROR_PALINIT_SHM;
+            goto CLEANUP0;
+        }
+
         //
+        // Initialize global process data
+        //
+
+        palError = InitializeProcessData();
+        if (NO_ERROR != palError)
+        {
+            ERROR("Unable to initialize process data\n");
+            goto CLEANUP1;
+        }
+
         // Allocate the initial thread data
         //
 
@@ -332,9 +323,11 @@ Initialize(
         if (NO_ERROR != palError)
         {
             ERROR("Unable to create initial thread data\n");
-            goto CLEANUP2;
+            goto CLEANUP1a;
         }
 
+        PROCAddThread(pThread, pThread);
+
         //
         // It's now safe to access our thread data
         //
@@ -372,6 +365,19 @@ Initialize(
         }
 
         g_pObjectManager = pshmom;
+
+        //
+        // Initialize the synchronization manager
+        //
+        g_pSynchronizationManager =
+            CPalSynchMgrController::CreatePalSynchronizationManager();
+
+        if (NULL == g_pSynchronizationManager)
+        {
+            palError = ERROR_NOT_ENOUGH_MEMORY;
+            ERROR("Failure creating synchronization manager\n");
+            goto CLEANUP1c;
+        }
     }
     else
     {
@@ -382,6 +388,16 @@ Initialize(
 
     if (init_count == 0)
     {
+        //
+        // Create the initial process and thread objects
+        //
+        palError = CreateInitialProcessAndThreadObjects(pThread);
+        if (NO_ERROR != palError)
+        {
+            ERROR("Unable to create initial process and thread objects\n");
+            goto CLEANUP2;
+        }
+
         palError = ERROR_GEN_FAILURE;
 
         /* Initialize the File mapping critical section. */
@@ -401,6 +417,19 @@ Initialize(
             goto CLEANUP10;
         }
 
+        if (flags & PAL_INITIALIZE_SYNC_THREAD)
+        {
+            //
+            // Tell the synchronization manager to start its worker thread
+            //
+            palError = CPalSynchMgrController::StartWorker(pThread);
+            if (NO_ERROR != palError)
+            {
+                ERROR("Synch manager failed to start worker thread\n");
+                goto CLEANUP13;
+            }
+        }
+
         if (flags & PAL_INITIALIZE_STD_HANDLES)
         {
             /* create file objects for standard handles */
@@ -442,12 +471,21 @@ Initialize(
 CLEANUP15:
     FILECleanupStdHandles();
 CLEANUP14:
+CLEANUP13:
     VIRTUALCleanup();
 CLEANUP10:
     MAPCleanup();
 CLEANUP6:
+    PROCCleanupInitialProcess();
 CLEANUP2:
+    // Cleanup synchronization manager
+CLEANUP1c:
+    // Cleanup object manager
 CLEANUP1b:
+    // Cleanup initial thread data
+CLEANUP1a:
+    // Cleanup global process data
+CLEANUP1:
     SHMCleanup();
 CLEANUP0:
 CLEANUP0a:
@@ -596,6 +634,50 @@ BOOL PALIsThreadDataInitialized()
     return g_fThreadDataAvailable;
 }
 
+/*++
+Function:
+  PALCommonCleanup
+
+  Utility function to prepare for shutdown.
+
+--*/
+void
+PALCommonCleanup()
+{
+    static bool cleanupDone = false;
+
+    // Declare the beginning of shutdown
+    PALSetShutdownIntent();
+
+    if (!cleanupDone)
+    {
+        cleanupDone = true;
+
+        //
+        // Let the synchronization manager know we're about to shutdown
+        //
+        CPalSynchMgrController::PrepareForShutdown();
+    }
+}
+
+BOOL PALIsShuttingDown()
+{
+    /* TODO: This function may be used to provide a reader/writer-like
+       mechanism (or a ref counting one) to prevent PAL APIs that need to access
+       PAL runtime data, from working when PAL is shutting down. Each of those API
+       should acquire a read access while executing. The shutting down code would
+       acquire a write lock, i.e. suspending any new incoming reader, and waiting
+       for the current readers to be done. That would allow us to get rid of the
+       dangerous suspend-all-other-threads at shutdown time */
+    return shutdown_intent;
+}
+
+void PALSetShutdownIntent()
+{
+    /* TODO: See comment in PALIsShuttingDown */
+    shutdown_intent = TRUE;
+}
+
 /*++
 Function:
   PALInitLock
@@ -687,60 +769,3 @@ static BOOL INIT_IncreaseDescriptorLimit(void)
 #endif // !DONT_SET_RLIMIT_NOFILE
     return TRUE;
 }
-
-/*++
-Function:
-  PROCAbort()
-
-  Aborts the process after calling the shutdown cleanup handler. This function
-  should be called instead of calling abort() directly.
-  
-  Does not return
---*/
-PAL_NORETURN
-VOID
-PROCAbort()
-{
-    // Abort the process after waiting for the core dump to complete
-    abort();
-}
-
-/*++
-Function:
-  GetCurrentProcessId
-
-See MSDN doc.
---*/
-DWORD
-PALAPI
-GetCurrentProcessId(
-            VOID)
-{
-    PERF_ENTRY(GetCurrentProcessId);
-    ENTRY("GetCurrentProcessId()\n" );
-
-    LOGEXIT("GetCurrentProcessId returns DWORD %#x\n", gPID);
-    PERF_EXIT(GetCurrentProcessId);
-    return gPID;
-}
-
-
-/*++
-Function:
-  GetCurrentSessionId
-
-See MSDN doc.
---*/
-DWORD
-PALAPI
-GetCurrentSessionId(
-            VOID)
-{
-    PERF_ENTRY(GetCurrentSessionId);
-    ENTRY("GetCurrentSessionId()\n" );
-
-    LOGEXIT("GetCurrentSessionId returns DWORD %#x\n", gSID);
-    PERF_EXIT(GetCurrentSessionId);
-    return gSID;
-}
-
index 0edc8a98ac6dee73f70735100be034b514b6e9fb..95daa7cb32ee2a07ba62f47bb22a1fb25c15a4ab 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "pal/dbgmsg.h"
 #include "pal/thread.hpp"
-#include "pal/init.h"
+#include "../thread/procprivate.hpp"
 #include "pal/module.h"
 #include "pal/process.h"
 
@@ -62,6 +62,22 @@ AllocatePalThread(CPalThread **ppThread)
         goto exit;
     }
 
+    HANDLE hThread;
+    palError = CreateThreadObject(pThread, pThread, &hThread);
+    if (NO_ERROR != palError)
+    {
+        pthread_setspecific(thObjKey, NULL);
+        pThread->ReleaseThreadReference();
+        goto exit;
+    }
+
+    // Like CreateInitialProcessAndThreadObjects, we do not need this
+    // thread handle, since we're not returning it to anyone who will
+    // possibly release it.
+    (void)g_pObjectManager->RevokeHandle(pThread, hThread);
+
+    PROCAddThread(pThread, pThread);
+
 exit:
     *ppThread = pThread;
     return palError;
index 83250327786fe5a9136e0e9d3a087734a290c014..d2c4c7b69c6bfb4fbf90e118fd71b73764ea2325 100644 (file)
@@ -30,7 +30,6 @@ SET_DEFAULT_DEBUG_CHANNEL(LOADER); // some headers have code with asserts, so do
 #include "pal/file.h"
 #include "pal/utils.h"
 #include "pal/init.h"
-#include "pal/modulename.h"
 #include "pal/environ.h"
 #include "pal/virtual.h"
 #include "pal/map.hpp"
@@ -340,9 +339,10 @@ GetProcAddress(
         /* if we don't know the module's full name yet, this is our chance to obtain it */
         if (!module->lib_name && module->dl_handle)
         {
-            const char* libName = PAL_dladdr((LPVOID)ProcAddress);
-            if (libName)
+            Dl_info dl_info;
+            if (dladdr((LPVOID)ProcAddress, &dl_info) != 0)
             {
+                const char* libName = dl_info.dli_fname;
                 module->lib_name = UTIL_MBToWC_Alloc(libName, -1);
                 if (nullptr == module->lib_name)
                 {
@@ -354,6 +354,10 @@ GetProcAddress(
                           module, libName);
                 }
             }
+            else
+            {
+                TRACE("GetProcAddress: dladdr() call failed!\n");
+            }
         }
     }
     else
@@ -874,11 +878,17 @@ void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved)
     MODSTRUCT *module = nullptr;
     BOOL InLoadOrder = TRUE; /* true if in load order, false for reverse */
     CPalThread *pThread;
-    
+
+    pThread = InternalGetCurrentThread();
+    if (UserCreatedThread != pThread->GetThreadType())
+    {
+        return;
+    }
+
     /* Validate dwReason */
     switch(dwReason)
     {
-    case DLL_PROCESS_ATTACH: 
+    case DLL_PROCESS_ATTACH:
         ASSERT("got called with DLL_PROCESS_ATTACH parameter! Why?\n");
         break;
     case DLL_PROCESS_DETACH:
diff --git a/src/pal/src/loader/modulename.cpp b/src/pal/src/loader/modulename.cpp
deleted file mode 100644 (file)
index 40c1c6d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/*++
-
-
-
-Module Name:
-
-    modulename.cpp
-
-Abstract:
-
-    Implementation of internal functions to get module names
-
-
-
---*/
-
-#include "pal/thread.hpp"
-#include "pal/malloc.hpp"
-#include "pal/palinternal.h"
-#include "pal/dbgmsg.h"
-#include "pal/modulename.h"
-
-#include <dlfcn.h>
-
-using namespace CorUnix;
-
-SET_DEFAULT_DEBUG_CHANNEL(LOADER);
-
-/*++
-    PAL_dladdr
-
-    Internal wrapper for dladder used only to get module name
-
-Parameters:
-    LPVOID ProcAddress: a pointer to a function in a shared library
-
-Return value:
-    Pointer to string with the fullpath to the shared library containing
-    ProcAddress.
-
-    NULL if error occurred.
-
-Notes:
-    The string returned by this function is owned by the OS.
-    If you need to keep it, strdup() it, because it is unknown how long
-    this ptr will point at the string you want (over the lifetime of
-    the system running)  It is only safe to use it immediately after calling
-    this function.
---*/
-const char *PAL_dladdr(LPVOID ProcAddress)
-{
-    Dl_info dl_info;
-    if (!dladdr(ProcAddress, &dl_info))
-    {
-        WARN("dladdr() call failed!\n");
-        /* If we get an error, return NULL */
-        return (NULL);
-    }
-    else
-    {
-        /* Return the module name */
-        return dl_info.dli_fname;
-    }
-}
-
diff --git a/src/pal/src/memory/local.cpp b/src/pal/src/memory/local.cpp
deleted file mode 100644 (file)
index fc62ef4..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/*++
-
-
-
-Module Name:
-
-    local.c
-
-Abstract:
-
-    Implementation of local memory management functions.
-
-Revision History:
-
-
-
---*/
-
-#include "pal/palinternal.h"
-#include "pal/dbgmsg.h"
-
-
-SET_DEFAULT_DEBUG_CHANNEL(MEM);
-
-
-/*++
-Function:
-  LocalAlloc
-
-See MSDN doc.
---*/
-HLOCAL
-PALAPI
-LocalAlloc(
-          IN UINT uFlags,
-          IN SIZE_T uBytes)
-{
-    LPVOID lpRetVal = NULL;
-    PERF_ENTRY(LocalAlloc);
-    ENTRY("LocalAlloc (uFlags=%#x, uBytes=%u)\n", uFlags, uBytes);
-
-    if ((uFlags & ~LMEM_ZEROINIT) != 0)
-    {
-        ASSERT("Invalid parameter AllocFlags=0x%x\n", uFlags);
-        SetLastError(ERROR_INVALID_PARAMETER);
-        goto done;
-    }
-
-    lpRetVal = PAL_malloc(uBytes);
-
-    if (lpRetVal == NULL)
-    {
-        ERROR("Not enough memory\n");
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        goto done;
-    }
-
-    if ((uFlags & LMEM_ZEROINIT) != 0)
-    {
-        memset(lpRetVal, 0, uBytes);
-    }
-
-done:
-    LOGEXIT( "LocalAlloc returning %p.\n", lpRetVal );
-    PERF_EXIT(LocalAlloc);
-    return (HLOCAL) lpRetVal;
-}
-
-/*++
-Function:
-  LocalFree
-
-See MSDN doc.
---*/
-HLOCAL
-PALAPI
-LocalFree(
-         IN HLOCAL hMem)
-{
-    BOOL bRetVal = FALSE;
-    PERF_ENTRY(LocalFree);
-    ENTRY("LocalFree (hmem=%p)\n", hMem);
-
-    free(hMem);
-    bRetVal = TRUE;
-
-    LOGEXIT( "LocalFree returning %p.\n", bRetVal == TRUE ? (HLOCAL)NULL : hMem );
-    PERF_EXIT(LocalFree);
-    return bRetVal == TRUE ? (HLOCAL)NULL : hMem;
-}
index 81502bfc7722edf25baf1c76b3ff51f9f0394879..e9d87d19c4a080be443f66136fec24f1b87924a5 100644 (file)
@@ -63,7 +63,7 @@ static LPWSTR FMTMSG_GetMessageString( DWORD dwErrCode )
         allocChars = MAX_ERROR_STRING_LENGTH + 1;
     }
 
-    LPWSTR lpRetVal = (LPWSTR)LocalAlloc(LMEM_FIXED, allocChars * sizeof(WCHAR));
+    LPWSTR lpRetVal = (LPWSTR)PAL_malloc(allocChars * sizeof(WCHAR));
 
     if (lpRetVal)
     {
@@ -135,7 +135,7 @@ static INT FMTMSG__watoi( LPWSTR str )
         UINT NumOfBytes = 0; \
         nSize *= 2; \
         NumOfBytes = nSize * sizeof( WCHAR ); \
-        lpTemp = static_cast<WCHAR *>( LocalAlloc( LMEM_FIXED, NumOfBytes ) ); \
+        lpTemp = static_cast<WCHAR *>( PAL_malloc( NumOfBytes ) ); \
         TRACE( "Growing the buffer.\n" );\
         \
         if ( !lpTemp ) \
@@ -149,7 +149,7 @@ static INT FMTMSG__watoi( LPWSTR str )
         \
         *lpWorkingString = '\0';\
         PAL_wcscpy( lpTemp, lpReturnString );\
-        LocalFree( lpReturnString ); \
+        free( lpReturnString ); \
         lpWorkingString = lpReturnString = lpTemp; \
         lpWorkingString += nCount; \
     } \
@@ -341,7 +341,7 @@ FormatMessageW(
     /* Parameter processing. */
     if ( dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER )
     {
-        TRACE( "Allocated %d TCHARs. Don't forget to call LocalFree to "
+        TRACE( "Allocated %d TCHARs. Don't forget to call free to "
                "free the memory when done.\n", nSize );
         bIsLocalAlloced = TRUE;
     }
@@ -418,7 +418,7 @@ FormatMessageW(
     }
 
     lpWorkingString = static_cast<WCHAR *>(
-        LocalAlloc( LMEM_FIXED, nSize * sizeof( WCHAR ) ) );
+        PAL_malloc( nSize * sizeof( WCHAR ) ) );
     if ( !lpWorkingString )
     {
         ERROR( "Unable to allocate memory for the working string.\n" );
@@ -675,14 +675,14 @@ exit: /* Function clean-up and exit. */
         {
             TRACE( "Copying the string into the buffer.\n" );
             PAL_wcsncpy( lpBuffer, lpReturnString, nCount + 1 );
-            LocalFree( lpReturnString );
+            free( lpReturnString );
         }
     }
     else /* Error, something occurred. */
     {
         if ( lpReturnString )
         {
-            LocalFree( lpReturnString );
+            free( lpReturnString );
         }
     }
     LOGEXIT( "FormatMessageW returns %d.\n", nCount );
index de9b7cbd6b2b7f4cd6f40aa3309bde8969d5a1d2..35cfc76f33d635aee9f5d0e080717d2955774f48 100644 (file)
@@ -989,3 +989,240 @@ CSharedMemoryObject::GetObjectSynchData(
     ASSERT("Attempt to obtain a synch data for a non-waitable object\n");
     return ERROR_INVALID_HANDLE;
 }
+
+/*++
+Function:
+  CSharedMemoryWaitableObject::Initialize
+
+  Performs possibly-failing initialization for a newly-constructed
+  object
+
+Parameters:
+  pthr -- thread data for calling thread
+  poa -- the object attributes (e.g., name) for the object
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::Initialize(
+    CPalThread *pthr,
+    CObjectAttributes *poa
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+
+    _ASSERTE(NULL != pthr);
+    _ASSERTE(NULL != poa);
+
+    ENTRY("CSharedMemoryWaitableObject::Initialize"
+        "(this = %p, pthr = %p, poa = %p)\n",
+        this,
+        pthr,
+        poa
+        );
+
+    palError = CSharedMemoryObject::Initialize(pthr, poa);
+    if (NO_ERROR != palError)
+    {
+        goto InitializeExit;
+    }
+
+    //
+    // Sanity check the passed in object type
+    //
+
+    _ASSERTE(CObjectType::WaitableObject == m_pot->GetSynchronizationSupport());
+
+    palError = g_pSynchronizationManager->AllocateObjectSynchData(
+        m_pot,
+        m_ObjectDomain,
+        &m_pvSynchData
+        );
+
+    if (NO_ERROR == palError && SharedObject == m_ObjectDomain)
+    {
+        SHMObjData *pshmod = SHMPTR_TO_TYPED_PTR(SHMObjData, m_shmod);
+        _ASSERTE(NULL != pshmod);
+
+        pshmod->pvSynchData = m_pvSynchData;
+    }
+
+InitializeExit:
+
+    LOGEXIT("CSharedMemoryWaitableObject::Initialize returns %d\n", palError);
+
+    return palError;
+}
+
+/*++
+Function:
+  CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject
+
+  Destructor; should only be called from ReleaseReference
+--*/
+
+CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject()
+{
+    ENTRY("CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject"
+        "(this = %p)\n",
+        this
+        );
+
+    if (!m_fSharedDataDereferenced)
+    {
+        ASSERT("DereferenceSharedData not called before object destructor -- delete called directly?\n");
+        DereferenceSharedData();
+    }
+
+    if (NULL != m_pvSynchData && m_fDeleteSharedData)
+    {
+        g_pSynchronizationManager->FreeObjectSynchData(
+            m_pot,
+            m_ObjectDomain,
+            m_pvSynchData
+            );
+    }
+
+    LOGEXIT("CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject\n");
+}
+
+/*++
+Function:
+  CSharedMemoryWaitableObject::GetSynchStateController
+
+  Obtain a synchronization state controller for this object.
+
+Parameters:
+  pthr -- thread data for calling thread
+  ppStateController -- on success, receives a pointer to the state controller
+    instance
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::GetSynchStateController(
+    CPalThread *pthr,                // IN, OPTIONAL
+    ISynchStateController **ppStateController    // OUT
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+
+    _ASSERTE(NULL != pthr);
+    _ASSERTE(NULL != ppStateController);
+
+    ENTRY("CSharedMemoryWaitableObject::GetSynchStateController"
+        "(this = %p, pthr = %p, ppStateController = %p",
+        this,
+        pthr,
+        ppStateController
+        );
+
+    //
+    // We need to grab the local synch lock before creating the controller
+    // (otherwise we could get promoted after passing in our parameters)
+    //
+
+    g_pSynchronizationManager->AcquireProcessLock(pthr);
+
+    palError = g_pSynchronizationManager->CreateSynchStateController(
+        pthr,
+        m_pot,
+        m_pvSynchData,
+        m_ObjectDomain,
+        ppStateController
+        );
+
+    g_pSynchronizationManager->ReleaseProcessLock(pthr);
+
+    LOGEXIT("CSharedMemoryWaitableObject::GetSynchStateController returns %d\n",
+        palError
+        );
+
+    return palError;
+}
+
+/*++
+Function:
+  CSharedMemoryWaitableObject::GetSynchWaitController
+
+  Obtain a synchronization wait controller for this object.
+
+Parameters:
+  pthr -- thread data for calling thread
+  ppWaitController -- on success, receives a pointer to the wait controller
+    instance
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::GetSynchWaitController(
+    CPalThread *pthr,                // IN, OPTIONAL
+    ISynchWaitController **ppWaitController    // OUT
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+
+    _ASSERTE(NULL != pthr);
+    _ASSERTE(NULL != ppWaitController);
+
+    ENTRY("CSharedMemoryWaitableObject::GetSynchWaitController"
+        "(this = %p, pthr = %p, ppWaitController = %p",
+        this,
+        pthr,
+        ppWaitController
+        );
+
+    //
+    // We need to grab the local synch lock before creating the controller
+    // (otherwise we could get promoted after passing in our parameters)
+    //
+
+    g_pSynchronizationManager->AcquireProcessLock(pthr);
+
+    palError = g_pSynchronizationManager->CreateSynchWaitController(
+        pthr,
+        m_pot,
+        m_pvSynchData,
+        m_ObjectDomain,
+        ppWaitController
+        );
+
+    g_pSynchronizationManager->ReleaseProcessLock(pthr);
+
+    LOGEXIT("CSharedMemoryWaitableObject::GetSynchWaitController returns %d\n",
+        palError
+        );
+
+    return palError;
+}
+
+/*++
+Function:
+  CSharedMemoryWaitableObject::GetObjectSynchData
+
+  Obtain the synchronization data for this object. This method should only
+  be called by the synchronization manager
+
+Parameters:
+  ppvSynchData -- on success, receives a pointer to the object's synch data
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::GetObjectSynchData(
+    VOID **ppvSynchData             // OUT
+    )
+{
+    _ASSERTE(NULL != ppvSynchData);
+
+    ENTRY("CSharedMemoryWaitableObject::GetObjectSynchData"
+        "(this = %p, ppvSynchData = %p)\n",
+        this,
+        ppvSynchData
+        );
+
+    *ppvSynchData = m_pvSynchData;
+
+    LOGEXIT("CSharedMemoryWaitableObject::GetObjectSynchData returns %d\n",
+        NO_ERROR
+        );
+
+    return NO_ERROR;
+}
+
index fe60f5b26cc91ae70f6fd632d596ba14edbcf35e..f50d10e0bb842262e5aa670c632e8fbb2ace4022 100644 (file)
@@ -295,6 +295,79 @@ namespace CorUnix
             );
 
     };
+
+    class CSharedMemoryWaitableObject : public CSharedMemoryObject
+    {
+        template <class T> friend void InternalDelete(T *p);
+
+    protected:
+
+        VOID *m_pvSynchData;
+
+        virtual ~CSharedMemoryWaitableObject();
+
+    public:
+
+        CSharedMemoryWaitableObject(
+            CObjectType *pot,
+            CRITICAL_SECTION *pcsObjListLock
+            )
+            :
+            CSharedMemoryObject(pot, pcsObjListLock),
+            m_pvSynchData(NULL)
+        {
+        };
+
+        //
+        // Constructor used to import a shared object into this process. The
+        // shared memory lock must be held when calling this contstructor
+        //
+
+        CSharedMemoryWaitableObject(
+            CObjectType *pot,
+            CRITICAL_SECTION *pcsObjListLock,
+            SHMPTR shmSharedObjectData,
+            SHMObjData *psmod,
+            bool fAddRefSharedData
+            )
+            :
+            CSharedMemoryObject(pot, pcsObjListLock, shmSharedObjectData, psmod, fAddRefSharedData),
+            m_pvSynchData(psmod->pvSynchData)
+        {
+        };
+
+        virtual
+        PAL_ERROR
+        Initialize(
+            CPalThread *pthr,
+            CObjectAttributes *poa
+            );
+
+        //
+        // IPalObject routines
+        //
+
+        virtual
+        PAL_ERROR
+        GetSynchStateController(
+            CPalThread *pthr,
+            ISynchStateController **ppStateController
+            );
+
+        virtual
+        PAL_ERROR
+        GetSynchWaitController(
+            CPalThread *pthr,
+            ISynchWaitController **ppWaitController
+            );
+
+        virtual
+        PAL_ERROR
+        GetObjectSynchData(
+            VOID **ppvSynchData
+            );
+    };
+
 }
 
 #endif // _PAL_SHMOBJECT_HPP
index 166dcb7428adc0358e39267bcc0750fb699342e6..73161418088bca95ebd2aa73a3f7473fcb968e74 100644 (file)
@@ -1,6 +1,5 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
 
 /*++
 
@@ -21,6 +20,7 @@ Abstract:
 #include "shmobject.hpp"
 #include "pal/cs.hpp"
 #include "pal/thread.hpp"
+#include "pal/procobj.hpp"
 #include "pal/dbgmsg.h"
 
 SET_DEFAULT_DEBUG_CHANNEL(PAL);
@@ -162,7 +162,7 @@ CSharedMemoryObjectManager::AllocateObject(
 
     if (CObjectType::WaitableObject == pot->GetSynchronizationSupport())
     {
-        _ASSERTE(FALSE);
+        pshmobj = InternalNew<CSharedMemoryWaitableObject>(pot, &m_csListLock);
     }
     else
     {
@@ -1001,7 +1001,7 @@ CSharedMemoryObjectManager::ImportSharedObjectIntoProcess(
     )
 {
     PAL_ERROR palError = NO_ERROR;
-    CSharedMemoryObject *pshmobj = NULL;
+    CSharedMemoryObject *pshmobj;
     PLIST_ENTRY pleObjectList;
 
     _ASSERTE(NULL != pthr);
@@ -1025,7 +1025,11 @@ CSharedMemoryObjectManager::ImportSharedObjectIntoProcess(
 
     if (CObjectType::WaitableObject == pot->GetSynchronizationSupport())
     {
-        _ASSERTE(FALSE);
+        pshmobj = InternalNew<CSharedMemoryWaitableObject>(pot,
+                                                           &m_csListLock,
+                                                           shmSharedObjectData,
+                                                           psmod,
+                                                           fAddRefSharedData);
     }
     else
     {
@@ -1073,14 +1077,6 @@ ImportSharedObjectIntoProcessExit:
     return palError;
 }
 
-static PalObjectTypeId RemotableObjectTypes[] =
-    {otiManualResetEvent, otiAutoResetEvent, otiMutex, otiProcess};
-
-static CAllowedObjectTypes aotRemotable(
-    RemotableObjectTypes,
-    sizeof(RemotableObjectTypes) / sizeof(RemotableObjectTypes[0])
-    );
-
 /*++
 Function:
   CheckObjectTypeAndRights
diff --git a/src/pal/src/synchmgr/synchcontrollers.cpp b/src/pal/src/synchmgr/synchcontrollers.cpp
new file mode 100644 (file)
index 0000000..22bba4a
--- /dev/null
@@ -0,0 +1,2042 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    synchcontrollers.cpp
+
+Abstract:
+    Implementation of Synchronization Controllers and related objects
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do this first
+
+#include "synchmanager.hpp"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sched.h>
+#include <errno.h>
+#include <limits.h>
+
+namespace CorUnix
+{
+#ifdef SYNCH_STATISTICS
+    LONG g_rglStatWaitCount[ObjectTypeIdCount]       = { 0 };
+    LONG g_rglStatContentionCount[ObjectTypeIdCount] = { 0 };
+#endif // SYNCH_STATISTICS
+    ////////////////////////////
+    //                        //
+    //  CSynchControllerBase  //
+    //                        //
+    ////////////////////////////
+
+    /*++
+    Method:
+      CSynchControllerBase::Init
+
+    Initializes a generic controller
+    --*/
+    PAL_ERROR CSynchControllerBase::Init(
+        CPalThread * pthrCurrent,
+        ControllerType ctCtrlrType,
+        ObjectDomain odObjectDomain,
+        CObjectType *potObjectType,
+        CSynchData * psdSynchData,
+        WaitDomain wdWaitDomain)
+    {
+        VALIDATEOBJECT(psdSynchData);
+
+        _ASSERTE(InternalGetCurrentThread() == pthrCurrent);
+
+        // Initialize internal controller data
+        m_pthrOwner      = pthrCurrent;
+        m_ctCtrlrType    = ctCtrlrType;
+        m_odObjectDomain = odObjectDomain;
+        m_potObjectType  = potObjectType;
+        m_psdSynchData   = psdSynchData;
+        m_wdWaitDomain   = wdWaitDomain;
+
+        // Add reference to target synch data
+        m_psdSynchData->AddRef();
+
+        // Acquire lock implied by the controller
+        CPalSynchronizationManager::AcquireLocalSynchLock(m_pthrOwner);
+        if (LocalWait != m_wdWaitDomain)
+        {
+            CPalSynchronizationManager::AcquireSharedSynchLock(m_pthrOwner);
+        }
+
+        return NO_ERROR;
+    }
+
+    /*++
+    Method:
+      CSynchControllerBase::Release
+
+    Releases a generic controller a return it to the appropriate cache
+    --*/
+    void CSynchControllerBase::Release()
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+#ifdef _DEBUG
+        ThreadWaitInfo * ptwiWaitInfo =
+            CPalSynchronizationManager::GetThreadWaitInfo(m_pthrOwner);
+#endif // _DEBUG
+
+        CPalSynchronizationManager * pSynchManager =
+            CPalSynchronizationManager::GetInstance();
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERTE(ptwiWaitInfo->pthrOwner == m_pthrOwner);
+
+        // Release reference to target synch data
+        m_psdSynchData->Release(m_pthrOwner);
+
+        // Release lock implied by the controller
+        if (LocalWait != m_wdWaitDomain)
+        {
+            CPalSynchronizationManager::ReleaseSharedSynchLock(m_pthrOwner);
+        }
+        CPalSynchronizationManager::ReleaseLocalSynchLock(m_pthrOwner);
+
+        // Return controller to the appropriate cache
+        if (WaitController == m_ctCtrlrType)
+        {
+            // The cast here must be static_cast and not reinterpet_cast.
+            // In fact in general static_cast<CSynchWaitController*>(this) is
+            // equal to this-sizeof(void*), given that CSynchWaitController
+            // has a virtual table, while CSynchControllerBase doesn't.
+            pSynchManager->CacheAddWaitCtrlr(m_pthrOwner,
+                static_cast<CSynchWaitController*>(this));
+        }
+        else
+        {
+            // The cast here must be static_cast and not reinterpet_cast
+            pSynchManager->CacheAddStateCtrlr(m_pthrOwner,
+                static_cast<CSynchStateController*>(this));
+        }
+    }
+
+    ////////////////////////////
+    //                        //
+    //  CSynchWaitController  //
+    //                        //
+    ////////////////////////////
+
+    /*++
+    Method:
+      CSynchWaitController::CanThreadWaitWithoutBlocking
+
+    Returns whether or not the thread owning this controller can
+    wait on the target object without blocking (i.e. the objet is
+    signaled)
+    --*/
+    PAL_ERROR CSynchWaitController::CanThreadWaitWithoutBlocking(
+        bool * pfCanWaitWithoutBlocking,
+        bool * pfAbandoned)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        bool fRetVal = false;
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERTE(NULL != pfCanWaitWithoutBlocking);
+        _ASSERTE(NULL != pfAbandoned);
+
+        fRetVal = m_psdSynchData->CanWaiterWaitWithoutBlocking(m_pthrOwner, pfAbandoned);
+
+        if(!fRetVal && otiProcess == m_psdSynchData->GetObjectTypeId())
+        {
+            // Note: if the target object is a process, here we need to check
+            // whether or not it has already exited. In fact, since currently
+            // we do not monitor a process status as long as there is no
+            // thread waiting on it, in general if the process already exited
+            // the process object is likely not to be signaled yet, therefore
+            // the above CanWaiterWaitWithoutBlocking call probably returned
+            // false, and, without the check below, that would cause the
+            // current thread to eventually go to sleep for a short time
+            // (until the worker thread notifies that the waited process has
+            // indeed exited), while it would not be necessary.
+            // As side effect that would cause a WaitForSingleObject with zero
+            // timeout to always return WAIT_TIMEOUT, even though the target
+            // process already exited. WaitForSingleObject with zero timeout
+            // is a common way to probe whether or not a process has already
+            // exited, and it is supposed to return WAIT_OBJECT_0 if the
+            // process exited, and WAIT_TIMEOUT if it is still active.
+            // In order to support this feature we need to check at this time
+            // whether or not the process has already exited.
+
+            CProcProcessLocalData * pProcLocalData = GetProcessLocalData();
+            DWORD dwExitCode = 0;
+            bool fIsActualExitCode = false;
+
+            _ASSERT_MSG(NULL != pProcLocalData,
+                        "Process synch data pointer is missing\n");
+
+            if (NULL != pProcLocalData &&
+                CPalSynchronizationManager::HasProcessExited(pProcLocalData->dwProcessId,
+                                                             &dwExitCode,
+                                                             &fIsActualExitCode))
+            {
+                TRACE("Process pid=%u exited with %s exitcode=%u\n",
+                      pProcLocalData->dwProcessId,
+                      fIsActualExitCode ? "actual" : "guessed",
+                      dwExitCode);
+
+                // Store the exit code in the process local data
+                if (fIsActualExitCode)
+                {
+                    pProcLocalData->dwExitCode = dwExitCode;
+                }
+
+                // Set process status to PS_DONE
+                pProcLocalData->ps = PS_DONE;
+
+                // Set signal count
+                m_psdSynchData->SetSignalCount(1);
+
+                // Releasing all local waiters
+                // (see comments in DoMonitorProcesses)
+                m_psdSynchData->ReleaseAllLocalWaiters(m_pthrOwner);
+
+                fRetVal = true;
+            }
+        }
+
+        *pfCanWaitWithoutBlocking = fRetVal;
+        return NO_ERROR;
+    }
+
+    /*++
+    Method:
+      CSynchWaitController::ReleaseWaitingThreadWithoutBlocking
+
+    Performs all the steps needed to be done by the controller's owner
+    thread in order to wait on the target object without blocking
+    (e.g. modifying the object signal count accordingly with its
+    thread release semantics)
+    This method should be called only after having received positive
+    response from CanThreadWaitWithoutBlocking called on the same
+    controller.
+    --*/
+    PAL_ERROR CSynchWaitController::ReleaseWaitingThreadWithoutBlocking()
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        PAL_ERROR palErr = NO_ERROR;
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+
+        palErr = m_psdSynchData->ReleaseWaiterWithoutBlocking(m_pthrOwner, m_pthrOwner);
+
+#ifdef SYNCH_STATISTICS
+        if (NO_ERROR == palErr)
+        {
+            m_psdSynchData->IncrementStatWaitCount();
+        }
+#endif
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CSynchWaitController::RegisterWaitingThread
+
+    Registers the controller's owner thread for waiting on the target
+    object
+    --*/
+    PAL_ERROR CSynchWaitController::RegisterWaitingThread(
+        WaitType wtWaitType,
+        DWORD dwIndex,
+        bool fAlertable,
+        bool fPrioritize)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        PAL_ERROR palErr = NO_ERROR;
+        WaitingThreadsListNode * pwtlnNewNode = NULL;
+        SharedID shridNewNode = NULL;
+        ThreadWaitInfo * ptwiWaitInfo;
+        DWORD * pdwWaitState;
+        bool fSharedObject = (SharedObject == m_odObjectDomain);
+        bool fEarlyDeath = false;
+        bool fSynchDataRefd = false;
+        CPalSynchronizationManager * pSynchManager =
+            CPalSynchronizationManager::GetInstance();
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+
+        ptwiWaitInfo = CPalSynchronizationManager::GetThreadWaitInfo(
+            m_pthrOwner);
+
+        _ASSERTE(ptwiWaitInfo->pthrOwner == m_pthrOwner);
+
+        pdwWaitState = SharedIDToTypePointer(DWORD,
+                m_pthrOwner->synchronizationInfo.m_shridWaitAwakened);
+
+        if (fSharedObject)
+        {
+            shridNewNode = pSynchManager->CacheGetSharedWTListNode(m_pthrOwner);
+            pwtlnNewNode = SharedIDToTypePointer(WaitingThreadsListNode, shridNewNode);
+        }
+        else
+        {
+            pwtlnNewNode = pSynchManager->CacheGetLocalWTListNode(m_pthrOwner);
+        }
+
+        if (!pwtlnNewNode)
+        {
+            if (fSharedObject && (NULL != shridNewNode))
+            {
+                ASSERT("Bad Shared Memory ptr %p\n", shridNewNode);
+                palErr = ERROR_INTERNAL_ERROR;
+            }
+            else
+            {
+                ERROR("Out of memory\n");
+                palErr = ERROR_NOT_ENOUGH_MEMORY;
+            }
+            goto RWT_exit;
+        }
+
+        if (ptwiWaitInfo->lObjCount >= MAXIMUM_WAIT_OBJECTS)
+        {
+            ASSERT("Too many objects");
+            palErr = ERROR_INTERNAL_ERROR;
+            goto RWT_exit;
+        }
+
+        if (0 == ptwiWaitInfo->lObjCount)
+        {
+            ptwiWaitInfo->wtWaitType = wtWaitType;
+            ptwiWaitInfo->wdWaitDomain = m_wdWaitDomain;
+        }
+        else
+        {
+            _ASSERT_MSG(wtWaitType == ptwiWaitInfo->wtWaitType,
+                        "Conflicting wait types in wait registration\n");
+
+            if (m_wdWaitDomain != ptwiWaitInfo->wdWaitDomain)
+            {
+                ptwiWaitInfo->wdWaitDomain = MixedWait;
+            }
+        }
+
+        pwtlnNewNode->shridSHRThis       = NULL;
+        pwtlnNewNode->ptwiWaitInfo       = ptwiWaitInfo;
+        pwtlnNewNode->dwObjIndex         = dwIndex;
+        pwtlnNewNode->dwProcessId        = gPID;
+        pwtlnNewNode->dwThreadId         = m_pthrOwner->GetThreadId();
+        pwtlnNewNode->dwFlags            = (MultipleObjectsWaitAll == wtWaitType) ?
+                                            WTLN_FLAG_WAIT_ALL : 0;
+        pwtlnNewNode->shridWaitingState  = m_pthrOwner->synchronizationInfo.m_shridWaitAwakened;
+        if (fSharedObject)
+        {
+            pwtlnNewNode->dwFlags                   |= WTLN_FLAG_OWNER_OBJECT_IS_SHARED;
+            pwtlnNewNode->shridSHRThis               = shridNewNode;
+            pwtlnNewNode->ptrOwnerObjSynchData.shrid = m_psdSynchData->GetSharedThis();
+        }
+        else
+        {
+            pwtlnNewNode->ptrOwnerObjSynchData.ptr = m_psdSynchData;
+        }
+
+        // AddRef the synch data (will be released in UnregisterWait)
+        m_psdSynchData->AddRef();
+        fSynchDataRefd = true;
+
+        ptwiWaitInfo->rgpWTLNodes[ptwiWaitInfo->lObjCount] = pwtlnNewNode;
+
+        if(otiProcess == m_psdSynchData->GetObjectTypeId())
+        {
+            CProcProcessLocalData * pProcLocalData = GetProcessLocalData();
+
+            if (NULL == pProcLocalData)
+            {
+                // Process local data pointer not set in the controller.
+                // This pointer is set in CSynchWaitController only when the
+                // wait controller for the object is created by calling
+                // GetSynchWaitControllersForObjects
+                ASSERT("Process synch data pointer is missing\n");
+                palErr = ERROR_INTERNAL_ERROR;
+                goto RWT_exit;
+            }
+
+            palErr = pSynchManager->RegisterProcessForMonitoring(m_pthrOwner,
+                                                                 m_psdSynchData,
+                                                                 m_pProcessObject,
+                                                                 pProcLocalData);
+            if (NO_ERROR != palErr)
+            {
+                goto RWT_exit;
+            }
+        }
+
+        if (0 == ptwiWaitInfo->lObjCount)
+        {
+            DWORD dwWaitState;
+
+            // Setting the thread in wait state
+            dwWaitState = (DWORD)(fAlertable ? TWS_ALERTABLE: TWS_WAITING);
+
+            TRACE("Switching my wait state [%p] from TWS_ACTIVE to %u \n",
+                  pdwWaitState, dwWaitState);
+
+            dwWaitState = InterlockedCompareExchange(
+                (LONG *)pdwWaitState, (LONG)dwWaitState, TWS_ACTIVE);
+            if ((DWORD)TWS_ACTIVE != dwWaitState)
+            {
+                if ((DWORD)TWS_EARLYDEATH == dwWaitState)
+                {
+                    // Process is terminating, this thread will soon be
+                    // suspended (by SuspendOtherThreads).
+                    WARN("Thread is about to get suspended by "
+                         "TerminateProcess\n");
+
+                    fEarlyDeath = true;
+                    palErr = WAIT_FAILED;
+                }
+                else
+                {
+                    ASSERT("Unexpected thread wait state %d\n", dwWaitState);
+                    palErr = ERROR_INTERNAL_ERROR;
+                }
+                goto RWT_exit;
+            }
+        }
+
+        // Add new node to queue
+        if (fSharedObject)
+        {
+            m_psdSynchData->SharedWaiterEnqueue(shridNewNode, fPrioritize);
+            ptwiWaitInfo->lSharedObjCount += 1;
+        }
+        else
+        {
+            m_psdSynchData->WaiterEnqueue(pwtlnNewNode, fPrioritize);
+        }
+
+        // Succeeded: update object count
+        ptwiWaitInfo->lObjCount++;
+
+    RWT_exit:
+        if (palErr != NO_ERROR)
+        {
+            // Unregister any partial wait registration
+            pSynchManager->UnRegisterWait(m_pthrOwner, ptwiWaitInfo, fSharedObject);
+
+            if (fSynchDataRefd)
+            {
+                m_psdSynchData->Release(m_pthrOwner);
+            }
+            if ((fSharedObject)  && (NULL != shridNewNode))
+            {
+                pSynchManager->CacheAddSharedWTListNode(m_pthrOwner, shridNewNode);
+            }
+            else if (NULL != pwtlnNewNode)
+            {
+                pSynchManager->CacheAddLocalWTListNode(m_pthrOwner, pwtlnNewNode);
+            }
+
+            if (fEarlyDeath)
+            {
+                // Early death detected, i.e. the process is about to exit.
+                // We need to completely release the synch lock(s) before
+                // going to sleep
+                LONG lLocalSynchLockCount;
+                LONG lSharedSynchLockCount;
+
+                lSharedSynchLockCount = CPalSynchronizationManager::ResetSharedSynchLock(m_pthrOwner);
+                lLocalSynchLockCount = CPalSynchronizationManager::ResetLocalSynchLock(m_pthrOwner);
+
+                _ASSERTE(0 < lLocalSynchLockCount);
+
+                // Sleep for ever
+                CPalSynchronizationManager::ThreadPrepareForShutdown();
+            }
+        }
+#ifdef SYNCH_STATISTICS
+        else
+        {
+            m_psdSynchData->IncrementStatWaitCount();
+            m_psdSynchData->IncrementStatContentionCount();
+        }
+#endif
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CSynchWaitController::ReleaseController
+
+    Releases the current controller
+    --*/
+    void CSynchWaitController::ReleaseController()
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+
+        Release();
+    }
+
+    /*++
+    Method:
+      CSynchWaitController::GetProcessLocalData
+
+    Accessor Get method for process local data of the target object
+    --*/
+    CProcProcessLocalData * CSynchWaitController::GetProcessLocalData()
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERT_MSG(NULL != m_pProcLocalData,
+                    "Pointer to process local data not yet initialized\n");
+
+        return m_pProcLocalData;
+    }
+
+    /*++
+    Method:
+      CSynchWaitController::SetProcessData
+
+    Accessor Set method for process local data of the target object
+    --*/
+    void CSynchWaitController::SetProcessData(IPalObject* pProcessObject, CProcProcessLocalData * pProcLocalData)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERT_MSG(m_pProcessObject == nullptr, "SetProcessData should not be called more than once");
+        _ASSERT_MSG(pProcessObject != nullptr && pProcessObject->GetObjectType()->GetId() == otiProcess, "Invalid process object passed to SetProcessData");
+
+        m_pProcessObject = pProcessObject;
+        m_pProcLocalData = pProcLocalData;
+    }
+
+    /////////////////////////////
+    //                         //
+    //  CSynchStateController  //
+    //                         //
+    /////////////////////////////
+
+    /*++
+    Method:
+      CSynchStateController::GetSignalCount
+
+    Returns the current signal count of the target object
+    --*/
+    PAL_ERROR CSynchStateController::GetSignalCount(LONG *plSignalCount)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        PAL_ERROR palErr = NO_ERROR;
+        LONG lCount = m_psdSynchData->GetSignalCount();
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERTE(NULL != plSignalCount);
+        _ASSERT_MSG(0 <= lCount,
+                    "Internal error: negative signal count [signal count=%d]",
+                    lCount);
+
+        *plSignalCount = lCount;
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CSynchStateController::SetSignalCount
+
+    Sets the signal count of the target object, possibly triggering
+    waiting threads awakening.
+    --*/
+    PAL_ERROR CSynchStateController::SetSignalCount(LONG lNewCount)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERTE(lNewCount >= 0);
+
+        m_psdSynchData->Signal(m_pthrOwner, lNewCount, false);
+
+        return NO_ERROR;
+    }
+
+    /*++
+    Method:
+      CSynchStateController::IncrementSignalCount
+
+    Increments the signal count of the target object, possibly triggering
+    waiting threads awakening.
+    --*/
+    PAL_ERROR CSynchStateController::IncrementSignalCount(
+        LONG lAmountToIncrement)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERTE(lAmountToIncrement > 0);
+
+        LONG lOldCount = m_psdSynchData->GetSignalCount();
+        LONG lNewCount = lOldCount + lAmountToIncrement;
+
+        _ASSERT_MSG(lNewCount > lOldCount,
+            "Signal count increment %d would make current signal count %d to "
+            "wrap around\n", lAmountToIncrement, lOldCount);
+
+        m_psdSynchData->Signal(m_pthrOwner, lNewCount, false);
+
+        return NO_ERROR;
+    }
+
+    /*++
+    Method:
+      CSynchStateController::DecrementSignalCount
+
+    Decrements the signal count of the target object.
+    --*/
+    PAL_ERROR CSynchStateController::DecrementSignalCount(
+        LONG lAmountToDecrement)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERTE(lAmountToDecrement > 0);
+
+        PAL_ERROR palErr = NO_ERROR;
+        LONG lCount = m_psdSynchData->GetSignalCount();
+        _ASSERTE(lAmountToDecrement <= lCount);
+
+        m_psdSynchData->SetSignalCount(lCount - lAmountToDecrement);
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CSynchStateController::SetOwner
+
+    Sets the owner of the target object and initializes the ownership
+    count to 1 (for objects with tracked ownership).
+    --*/
+    PAL_ERROR CSynchStateController::SetOwner(CPalThread * pNewOwningThread)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        PAL_ERROR palErr = NO_ERROR;
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERTE(NULL != pNewOwningThread);
+        _ASSERT_MSG(CObjectType::OwnershipTracked ==
+                    m_potObjectType->GetOwnershipSemantics(),
+                    "SetOwner called on an object without OwnershipTracked "
+                    "semantics\n");
+
+        if (0 != m_psdSynchData->GetOwnershipCount())
+        {
+            ASSERT("Ownership count should be zero at this time\n");
+            palErr = ERROR_INTERNAL_ERROR;
+            goto SO_exit;
+        }
+
+        palErr = m_psdSynchData->AssignOwnershipToThread(m_pthrOwner,
+                                                       pNewOwningThread);
+
+        _ASSERT_MSG(0 == m_psdSynchData->GetOwnershipCount() ||
+                    0 == m_psdSynchData->GetSignalCount(),
+                    "Conflicting values for SignalCount [%d] and "
+                    "OwnershipCount [%d]\n",
+                    m_psdSynchData->GetOwnershipCount(),
+                    m_psdSynchData->GetSignalCount());
+
+    SO_exit:
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CSynchStateController::DecrementOwnershipCount
+
+    Decrements the ownership count of the target object possibly triggering
+    waiting threads awakening (for objects with tracked ownership).
+    --*/
+    PAL_ERROR CSynchStateController::DecrementOwnershipCount()
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        PAL_ERROR palErr = NO_ERROR;
+        LONG lOwnershipCount = m_psdSynchData->GetOwnershipCount();
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+        _ASSERT_MSG(CObjectType::OwnershipTracked ==
+                    m_potObjectType->GetOwnershipSemantics(),
+                    "Trying to decrement ownership count on an object with "
+                    "ownership semantics other than OwnershipTracked\n");
+        _ASSERT_MSG(0 <= lOwnershipCount,
+                    "Operation would make ownership count negative - object "
+                    "should be owned at this time [ownership count=%d]\n",
+                    lOwnershipCount);
+
+        if ( (1 > lOwnershipCount) ||
+             (m_psdSynchData->GetOwnerProcessID() != gPID) ||
+             (m_psdSynchData->GetOwnerThread() != m_pthrOwner) )
+        {
+            palErr = ERROR_NOT_OWNER;
+            goto DOC_exit;
+        }
+
+        lOwnershipCount--;
+        m_psdSynchData->SetOwnershipCount(lOwnershipCount);
+
+        if (0 == lOwnershipCount)
+        {
+            CPalSynchronizationManager * pSynchManager =
+                CPalSynchronizationManager::GetInstance();
+            OwnedObjectsListNode * pooln =
+                m_psdSynchData->GetOwnershipListNode();
+
+            _ASSERT_MSG(NULL != pooln,
+                        "Null ownership node pointer in SynchData with ownership "
+                        "semantics\n");
+            _ASSERT_MSG(m_psdSynchData == pooln->pPalObjSynchData,
+                        "Corrupted ownership node\n");
+
+            // Object has been released
+            // Remove it from list of owned objs for current thread
+            m_pthrOwner->synchronizationInfo.RemoveObjectFromOwnedList(pooln);
+
+            // Release SynchData reference count implied by the ownership
+            // list node
+            m_psdSynchData->Release(m_pthrOwner);
+
+            // Return node to the cache
+            pSynchManager->CacheAddOwnedObjsListNode(m_pthrOwner, pooln);
+
+            // Reset ownership
+            m_psdSynchData->ResetOwnership();
+
+            // Signal it and trigger waiter thread awakening
+            m_psdSynchData->Signal(m_pthrOwner, 1, false);
+        }
+
+    DOC_exit:
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CSynchStateController::ReleaseController
+
+    Releases the controller.
+    --*/
+    void CSynchStateController::ReleaseController(void)
+    {
+        VALIDATEOBJECT(m_psdSynchData);
+
+        _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+
+        Release();
+    }
+
+    //////////////////
+    //              //
+    //  CSynchData  //
+    //              //
+    //////////////////
+
+    /*++
+    Method:
+      CSynchData::Release
+
+    Decremnt the reference count of the target synchdata and retrurns
+    it to the appropriate cache if the reference count reaches zero.
+    --*/
+    LONG CSynchData::Release(CPalThread * pthrCurrent)
+    {
+        VALIDATEOBJECT(this);
+
+        LONG lCount = InterlockedDecrement(&m_lRefCount);
+
+        _ASSERT_MSG(0 <= lCount,
+                    "CSynchData %p with negative reference count [%d]\n",
+                    this, lCount);
+
+        if (0 == lCount)
+        {
+            CPalSynchronizationManager * pSynchManager =
+                CPalSynchronizationManager::GetInstance();
+            bool fSharedObject = (SharedObject == m_odObjectDomain);
+
+            _ASSERT_MSG((fSharedObject && (NULL == m_ptrWTLHead.shrid)) ||
+                        (!fSharedObject && (NULL == m_ptrWTLHead.ptr)),
+                        "Final Release on CSynchData with threads still in "
+                        "the waiting list\n");
+
+            TRACE("Disposing %s waitable object with SynchData @ "
+                  "{shrid=%p, p=%p}\n",
+                  (SharedObject == m_odObjectDomain) ? "shared" : "local",
+                  (PVOID)m_shridThis, this);
+
+
+#ifdef SYNCH_STATISTICS
+            LONG lStatWaitCount = GetStatWaitCount();
+            LONG lStatContentionCount = GetStatContentionCount();
+            LONG lCount, lNewCount;
+
+            TRACE("Statistical data for SynchData of otiType=%u @ %p: WaitCount=%d "
+                  "ContentionCount=%d\n", m_otiObjectTypeId, this, lStatWaitCount,
+                  lStatContentionCount);
+
+            do {
+                lCount = g_rglStatWaitCount[m_otiObjectTypeId];
+                lNewCount = lCount + lStatWaitCount;
+                lNewCount = InterlockedCompareExchange(&(g_rglStatWaitCount[m_otiObjectTypeId]),
+                                                       lNewCount, lCount);
+            } while (lCount != lNewCount);
+
+            lStatWaitCount = lNewCount;
+
+            do {
+                lCount = g_rglStatContentionCount[m_otiObjectTypeId];
+                lNewCount = lCount + lStatContentionCount;
+                lNewCount = InterlockedCompareExchange(&(g_rglStatContentionCount[m_otiObjectTypeId]),
+                                                       lNewCount, lCount);
+            } while (lCount != lNewCount);
+
+            lStatContentionCount = lNewCount;
+
+            TRACE("Total current statistical data for otiType=%u objects: WaitCount=%d "
+                  "ContentionCount=%d\n", m_otiObjectTypeId, lStatWaitCount,
+                  lStatContentionCount);
+#endif // SYNCH_STATISTICS
+
+            if (fSharedObject)
+            {
+                pSynchManager->CacheAddSharedSynchData(pthrCurrent, m_shridThis);
+            }
+            else
+            {
+                pSynchManager->CacheAddLocalSynchData(pthrCurrent, this);
+            }
+        }
+
+        return lCount;
+    }
+
+    /*++
+    Method:
+      CSynchData::ReleaseWaiterWithoutBlocking
+
+    Performs all the steps needed to be done by the target thread in order
+    to wait without blocking on the object associated with the current
+    SynchData (e.g. modifying the object signal count accordingly with its
+    thread release semantics)
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    PAL_ERROR CSynchData::ReleaseWaiterWithoutBlocking(
+        CPalThread * pthrCurrent,
+        CPalThread * pthrTarget)
+    {
+        VALIDATEOBJECT(this);
+
+        PAL_ERROR palErr = NO_ERROR;
+        CObjectType * potObjectType = GetObjectType();
+#ifdef _DEBUG
+        CObjectType::SignalingSemantics ssSignalingSemantics =
+            potObjectType->GetSignalingSemantics();
+#endif // _DEBUG
+        CObjectType::OwnershipSemantics osOwnershipSemantics =
+            potObjectType->GetOwnershipSemantics();
+        CObjectType::ThreadReleaseSemantics trsThreadReleaseSemantics =
+            potObjectType->GetThreadReleaseSemantics();
+        bool fReenteringObjWithOwnership = false;
+
+        _ASSERT_MSG(CObjectType::SignalingNotApplicable != ssSignalingSemantics,
+                    "Signaling not applicable");
+        _ASSERT_MSG(CObjectType::ThreadReleaseNotApplicable !=
+                    trsThreadReleaseSemantics,
+                    "Thread releasing not applicable");
+        _ASSERT_MSG(CObjectType::SingleTransitionObject != ssSignalingSemantics ||
+                    (CObjectType::ThreadReleaseHasNoSideEffects ==
+                     trsThreadReleaseSemantics &&
+                     CObjectType::NoOwner == osOwnershipSemantics),
+                    "Conflicting object synchronization attributes "
+                    "[SignalingSemantics=%u OwnershipSemantics=%u "
+                    "ThreadReleaseSemantics=%u]\n", ssSignalingSemantics,
+                    osOwnershipSemantics, trsThreadReleaseSemantics);
+
+        if (CObjectType::OwnershipTracked == osOwnershipSemantics &&
+            0 < GetOwnershipCount())
+        {
+            // We are rentering an object with ownership: we need to skip
+            // the object unsignaling
+            fReenteringObjWithOwnership = true;
+        }
+
+        if (!fReenteringObjWithOwnership &&
+            CObjectType::ThreadReleaseAltersSignalCount == trsThreadReleaseSemantics)
+        {
+            _ASSERT_MSG(0 < GetSignalCount(),
+                        "Internal error: operation would make signal count "
+                        "negative - object should be signaled at this time "
+                        "[signal count=%d]", GetSignalCount());
+            _ASSERT_MSG(CObjectType::OwnershipTracked != osOwnershipSemantics ||
+                        1 == GetSignalCount(),
+                        "Ownable objects cannot have signal count greater "
+                        "than zero [current SignalCount=%d]\n",
+                        GetSignalCount());
+
+            // Unsignal the object
+            DecrementSignalCount();
+        }
+
+        if (CObjectType::OwnershipTracked == osOwnershipSemantics)
+        {
+            _ASSERT_MSG(0 == GetOwnershipCount() || 0 == GetSignalCount(),
+                        "OwnershipCount and SignalCount with conflicting "
+                        "values\n");
+
+            // Take ownership or increment ownership count.
+            // We do this after the object unsignaling to minimize possibilities
+            // of having both SignalCount and OwnershipCount greater than zero
+            // (see comment in AssignOwnershipToThread)
+            palErr = AssignOwnershipToThread(pthrCurrent, pthrTarget);
+
+            if (NO_ERROR != palErr)
+            {
+                ERROR("AssignOwnershipToThread failed with error %u; "
+                      "ownership data on object with SynchData {shrid=%p p=%p} "
+                      "may be corrupted\n", palErr, (void *)m_shridThis, this);
+            }
+        }
+
+#ifdef SYNCH_STATISTICS
+        if (NO_ERROR == palErr)
+        {
+            IncrementStatWaitCount();
+        }
+#endif
+        return palErr;
+
+    }
+
+    /*++
+    Method:
+      CSynchData::CanWaiterWaitWithoutBlocking
+
+    Returns whether or not the waiter thread can wait on the target object
+    without blocking (i.e. the objet is signaled)
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    bool CSynchData::CanWaiterWaitWithoutBlocking(
+        CPalThread * pWaiterThread,
+        bool * pfAbandoned)
+    {
+        VALIDATEOBJECT(this);
+
+        bool fRetVal = (0 < GetSignalCount());
+        bool fAbandoned = false;
+        bool fOwnershipTracked = (CObjectType::OwnershipTracked ==
+                                  GetObjectType()->GetOwnershipSemantics());
+        if (fRetVal)
+        {
+            // Object signaled: thread can wait without blocking
+            if (fOwnershipTracked)
+            {
+                fAbandoned = IsAbandoned();
+            }
+
+            goto CWWWB_exit;
+        }
+
+        // Object not signaled: thread can wait without blocking only if the
+        // object is an ownable one, and it is owned by the current thread
+        if (fOwnershipTracked)
+        {
+            _ASSERT_MSG(0 < GetSignalCount() || 0 < GetOwnershipCount(),
+                        "Objects with ownership must be either signaled or "
+                        "owned by a thread\n");
+
+            if ((GetOwnerProcessID() == gPID) &&
+                (GetOwnerThread() == pWaiterThread) )
+            {
+                fRetVal = true;
+                goto CWWWB_exit;
+            }
+        }
+
+    CWWWB_exit:
+        *pfAbandoned = fAbandoned;
+        return fRetVal;
+    }
+
+    /*++
+    Method:
+      CSynchData::Signal
+
+    Sets the signal count of the object owning the target SynchData,
+    possibly triggering awakening of waiting threads.
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    void CSynchData::Signal(
+        CPalThread * pthrCurrent,
+        LONG lSignalCount,
+        bool fWorkerThread)
+    {
+        VALIDATEOBJECT(this);
+
+        bool fThreadReleased = false;
+        bool fDelegatedSignaling = false;
+        bool fReleaseAltersSignalCount =
+            (CObjectType::ThreadReleaseAltersSignalCount ==
+                GetObjectType()->GetThreadReleaseSemantics());
+
+        _ASSERTE(0 <= lSignalCount);
+
+        // Preset the signal count to the new value, so that it can be used
+        // by ReleaseFirstWaiter when delegating signaling to another process
+        m_lSignalCount = lSignalCount;
+
+        while (m_lSignalCount > 0)
+        {
+            fThreadReleased = ReleaseFirstWaiter(pthrCurrent,
+                                                 &fDelegatedSignaling,
+                                                 fWorkerThread);
+            if (!fThreadReleased)
+            {
+                // No more threads to release: break out of the loop
+                // keeping the current signal count
+                break;
+            }
+            if (fReleaseAltersSignalCount)
+            {
+                // Adjust signal count
+                m_lSignalCount--;
+            }
+            if (fDelegatedSignaling)
+            {
+                // Object signaling has been delegated
+                m_lSignalCount = 0;
+            }
+        }
+
+        _ASSERT_MSG(CObjectType::OwnershipTracked !=
+                    GetObjectType()->GetOwnershipSemantics() ||
+                    0 == GetOwnershipCount() || 0 == GetSignalCount(),
+                    "Conflicting values for SignalCount [%d] and "
+                    "OwnershipCount [%d]\n",
+                    GetOwnershipCount(), GetSignalCount());
+
+        return;
+    }
+
+    /*++
+    Method:
+      CSynchData::ReleaseFirstWaiter
+
+    Releases the first thread from the front of the list of waiting threads
+    whose wait is fully satisfied, possibly triggering remote awakening (if
+    the target thread lives in a different process) or object signaling
+    delegation (if the target thread lives in a different processing and it
+    is blocked on a wait-all).
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    bool CSynchData::ReleaseFirstWaiter(
+        CPalThread * pthrCurrent,
+        bool * pfDelegated,
+        bool fWorkerThread)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        bool fSharedSynchLock = false;
+        bool fSharedObject = (SharedObject == GetObjectDomain());
+        bool fThreadAwakened = false;
+        bool fDelegatedSignaling = false;
+        DWORD * pdwWaitState;
+        DWORD dwObjIdx;
+        SharedID shridItem = NULL, shridNextItem = NULL;
+        WaitingThreadsListNode * pwtlnItem, * pwtlnNextItem;
+        DWORD dwPid = gPID;
+        CPalSynchronizationManager * pSynchManager =
+            CPalSynchronizationManager::GetInstance();
+
+        VALIDATEOBJECT(this);
+
+        *pfDelegated = false;
+
+        if (fSharedObject)
+        {
+            shridItem = GetWTLHeadShmPtr();
+            pwtlnItem = SharedIDToTypePointer(WaitingThreadsListNode, shridItem);
+        }
+        else
+        {
+            pwtlnItem = GetWTLHeadPtr();
+        }
+
+        while (pwtlnItem)
+        {
+            VALIDATEOBJECT(pwtlnItem);
+
+            WaitCompletionState wcsWaitCompletionState;
+            bool fWaitAll = (0 != (WTLN_FLAG_WAIT_ALL & pwtlnItem->dwFlags));
+            pdwWaitState = SharedIDToTypePointer(DWORD,
+                pwtlnItem->shridWaitingState);
+
+            if (fSharedObject)
+            {
+                shridNextItem = pwtlnItem->ptrNext.shrid;
+                pwtlnNextItem = SharedIDToTypePointer(WaitingThreadsListNode,
+                                                  shridNextItem);
+            }
+            else
+            {
+                pwtlnNextItem = pwtlnItem->ptrNext.ptr;
+            }
+
+            if (fWaitAll)
+            {
+                // Wait All: we need to find out whether the wait is satisfied,
+                // or it is not, or if that cannot be determined from within
+                // this process (WaitMayBeSatisfied); in this case we need to
+                // delegate the object signaling to the process hosting the
+                // thread that owns the current target WaitingThreadsListNode
+
+                // If the target object is local (fSharedObject == false)
+                // we're probably not holding the shared lock.
+                // If the wait is not a LocalWait, it involves at least one
+                // shared object. If that is the case, at this time we need
+                // to grab the shared lock.  In fact IsRestOfWaitAllSatisfied
+                // and UnsignalRestOfLocalAwakeningWaitAll must be called
+                // atomically to prevent that another thread living
+                // in a different process could race with us stealing the
+                // signaling from one of the objects involved in the wait-all.
+                //
+                // Note: pwtlnItem->ptwiWaitInfo is valid only if the target
+                // wait originates in the current process. Anyway in the
+                // following 'if' we don't need to check that since we are
+                // already making sure that the object is local (!fSharedObject).
+                // If a wait involves at least one object local to this process,
+                // it can only be a wait performed by a thread in the current
+                // process, therefore pwtlnItem->ptwiWaitInfo is valid.
+
+                _ASSERTE(fSharedObject || pwtlnItem->dwProcessId == gPID);
+
+                if (!fSharedSynchLock && !fSharedObject &&
+                    LocalWait != pwtlnItem->ptwiWaitInfo->wdWaitDomain)
+                {
+                    CPalSynchronizationManager::AcquireSharedSynchLock(pthrCurrent);
+                    fSharedSynchLock = true;
+                }
+
+                // First check if the current target node is already marked for
+                // wait all check in progress, and in case skip it by setting
+                // wcsWaitCompletionState to WaitIsNotSatisfied
+                bool fMarkedForDelegatedObjectSingalingInProgress =
+                    (0 != (WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS & pwtlnItem->dwFlags));
+
+                wcsWaitCompletionState =
+                    fMarkedForDelegatedObjectSingalingInProgress ? WaitIsNotSatisfied :
+                    IsRestOfWaitAllSatisfied(pwtlnItem);
+            }
+            else
+            {
+                // Normal Wait: the wait is satisfied by definition
+                wcsWaitCompletionState = WaitIsSatisfied;
+            }
+
+            if (WaitIsSatisfied == wcsWaitCompletionState)
+            {
+                //
+                // Target wait is satisfied
+                //
+                TRACE("Trying to switch wait state [%p] from WAIT/ALERTABLE "
+                      "to ACTIVE for thread=%u\n",
+                      pdwWaitState, pwtlnItem->dwThreadId);
+
+                if (CPalSynchronizationManager::InterlockedAwaken(pdwWaitState, FALSE))
+                {
+                    TRACE("Succeeded switching wait state [%p] from WAIT/ALERTABLE "
+                          "to TWS_ACTIVE for trhead=%u\n",
+                          pdwWaitState, pwtlnItem->dwThreadId);
+
+                    dwObjIdx = pwtlnItem->dwObjIndex;
+
+                    if (dwPid == pwtlnItem->dwProcessId)
+                    {
+                        ///////////////////////////
+                        //
+                        // Local Thread Awakening
+                        //
+                        ///////////////////////////
+                        ThreadWaitInfo * ptwiWaitInfo = pwtlnItem->ptwiWaitInfo;
+                        bool fAbandoned = false;
+
+                        if (CObjectType::OwnershipTracked ==
+                            GetObjectType()->GetOwnershipSemantics())
+                        {
+                            // Get the abandoned status before resetting it by
+                            // assigning ownership to target thread
+                            fAbandoned = IsAbandoned();
+
+                            // Assign ownership to target thread
+                            // Note: This will cause both ownership count and
+                            //       signal count to be greater than zero at the
+                            //       same time; the signal count will be anyway
+                            //       decremented immediately by the caller
+                            //       CsynchData::Signal
+                            palErr = AssignOwnershipToThread(pthrCurrent,
+                                                             ptwiWaitInfo->pthrOwner);
+                            if (NO_ERROR != palErr)
+                            {
+                                ERROR("Synch Worker: AssignOwnershipToThread "
+                                      "failed with error %u; ownership data on "
+                                      "object with SynchData %p may be "
+                                      "corrupted\n", palErr, this);
+                            }
+                        }
+
+                        if (fWaitAll)
+                        {
+                            // Wait all satisfied: unsignal other objects
+                            // involved in the wait
+                            CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll(
+                                pthrCurrent,
+                                ptwiWaitInfo->pthrOwner,
+                                pwtlnItem,
+                                this);
+                        }
+
+                        TRACE("Unregistering wait for thread %u and waking it up "
+                              "[pdwWaitState=%p]\n", pwtlnItem->dwThreadId,
+                              pdwWaitState);
+
+                        // Unregister the wait
+                        pSynchManager->UnRegisterWait(pthrCurrent,
+                                                      ptwiWaitInfo,
+                                                      fSharedObject || fSharedSynchLock);
+
+                        // After UnRegisterWait pwtlnItem is invalid
+                        pwtlnItem = NULL;
+
+                        palErr = CPalSynchronizationManager::WakeUpLocalThread(
+                            pthrCurrent,
+                            ptwiWaitInfo->pthrOwner,
+                            fAbandoned ? MutexAbondoned : WaitSucceeded,
+                            dwObjIdx);
+
+                        if (NO_ERROR != palErr)
+                        {
+                            ERROR("Failed to wakeup local thread %#x: "
+                                  "object signaling may be "
+                                  "lost\n", ptwiWaitInfo->pthrOwner->GetThreadId());
+                        }
+                    }
+                    else
+                    {
+                        ///////////////////////////
+                        //
+                        // Remote Thread Awakening
+                        //
+                        ///////////////////////////
+
+                        // Note: if we are here, this cannot be a wait-all
+                        _ASSERT_MSG(!fWaitAll,
+                                    "Control should never reach this point if "
+                                    "target wait is a wait-all\n");
+
+                        // Wake up remote thread
+                        palErr = CPalSynchronizationManager::WakeUpRemoteThread(shridItem);
+
+                        if (NO_ERROR != palErr)
+                        {
+                            ERROR("Failed to dispatch remote awakening cmd to "
+                                  "worker thread in process pid=%d to wake up"
+                                  "thread tid=%#x; object signaling may be "
+                                  "lost\n", pwtlnItem->dwProcessId,
+                                  pwtlnItem->dwThreadId);
+                        }
+                    }
+
+                    // A thread has been awakened
+                    fThreadAwakened = true;
+
+                    // break out of the while loop
+                    break;
+                }
+            }
+            else if (WaitMayBeSatisfied == wcsWaitCompletionState)
+            {
+                //////////////////////////////////////////
+                //
+                // Wait All with remote thread awakening
+                //
+                //////////////////////////////////////////
+
+                //
+                // We need to transfer the object signaling to the process
+                // hosting the target waiter thread
+                //
+
+                _ASSERT_MSG(fWaitAll,
+                            "IsRestOfWaitAllSatisfied() apparently "
+                            "returned -1 on a normal (non wait all) "
+                            "wait\n");
+                _ASSERT_MSG(fSharedObject,
+                            "About to delegate object signaling to a remote "
+                            "process, but the signaled object is actually "
+                            "local\n");
+
+                // Delegate object signaling to target process
+                palErr = CPalSynchronizationManager::DelegateSignalingToRemoteProcess(
+                    pthrCurrent,
+                    pwtlnItem->dwProcessId,
+                    pwtlnItem->ptrOwnerObjSynchData.shrid);
+
+                TRACE("Delegating object signaling for SynchData shrid=%p\n",
+                      (VOID *)pwtlnItem->ptrOwnerObjSynchData.shrid);
+
+                if (NO_ERROR == palErr)
+                {
+                    // A remote thread will be awakened
+                    // This will also cause the object to be unsignaled by the
+                    // code calling ReleaseFirstWaiter before releasing the
+                    // synch locks, so no other WaitForMultipleObjects
+                    // involving the target object may race stealing this
+                    // particuklar object signaling
+                    fThreadAwakened = true;
+
+                    fDelegatedSignaling = true;
+
+                    // break out of the while loop
+                    break;
+                }
+                else
+                {
+                    ERROR("Failed to delegate object signaling to remote "
+                          "process %d. Looking for another waiter.\n",
+                          pwtlnItem->dwProcessId);
+
+                    // Go on: a different target waiter will be selected
+                }
+            }
+
+            if (fWorkerThread && fWaitAll && (dwPid == pwtlnItem->dwProcessId))
+            {
+                // Mark the target wait for object signaling
+                CPalSynchronizationManager::MarkWaitForDelegatedObjectSignalingInProgress(
+                    pthrCurrent,
+                    pwtlnItem);
+            }
+
+            // Go to the next item
+            shridItem = shridNextItem;
+            pwtlnItem = pwtlnNextItem;
+        }
+
+        if (fDelegatedSignaling)
+        {
+            *pfDelegated = true;
+        }
+        else if (fWorkerThread)
+        {
+            // Reset 'delegated object signaling in progress' flags
+            CPalSynchronizationManager::UnmarkTWListForDelegatedObjectSignalingInProgress(
+                this);
+        }
+
+        if (fSharedSynchLock)
+        {
+            CPalSynchronizationManager::ReleaseSharedSynchLock(pthrCurrent);
+        }
+        return fThreadAwakened;
+    }
+
+    /*++
+    Method:
+      CSynchData::Signal
+
+    Releases all the threads waiting on this object and living in the current
+    process.
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    LONG CSynchData::ReleaseAllLocalWaiters(
+        CPalThread * pthrCurrent)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        LONG lAwakenedCount = 0;
+        bool fSharedSynchLock = false;
+        bool fSharedObject = (SharedObject == GetObjectDomain());
+        DWORD * pdwWaitState;
+        DWORD dwObjIdx;
+        SharedID shridItem = NULL, shridNextItem = NULL;
+        WaitingThreadsListNode * pwtlnItem, * pwtlnNextItem;
+        DWORD dwPid = gPID;
+        CPalSynchronizationManager * pSynchManager =
+            CPalSynchronizationManager::GetInstance();
+
+        VALIDATEOBJECT(this);
+
+        if (fSharedObject)
+        {
+            shridItem = GetWTLHeadShmPtr();
+            pwtlnItem = SharedIDToTypePointer(WaitingThreadsListNode, shridItem);
+        }
+        else
+        {
+            pwtlnItem = GetWTLHeadPtr();
+        }
+
+        while (pwtlnItem)
+        {
+            VALIDATEOBJECT(pwtlnItem);
+
+            bool fWaitAll = (0 != (WTLN_FLAG_WAIT_ALL & pwtlnItem->dwFlags));
+            pdwWaitState = SharedIDToTypePointer(DWORD,
+                pwtlnItem->shridWaitingState);
+
+            if (fSharedObject)
+            {
+                shridNextItem = pwtlnItem->ptrNext.shrid;
+                pwtlnNextItem = SharedIDToTypePointer(WaitingThreadsListNode,
+                                                  shridNextItem);
+            }
+            else
+            {
+                pwtlnNextItem = pwtlnItem->ptrNext.ptr;
+            }
+
+            // See note in similar spot in ReleaseFirstWaiter
+
+            _ASSERTE(fSharedObject || pwtlnItem->dwProcessId == gPID);
+
+            if (!fSharedSynchLock && !fSharedObject &&
+                LocalWait != pwtlnItem->ptwiWaitInfo->wdWaitDomain)
+            {
+                CPalSynchronizationManager::AcquireSharedSynchLock(pthrCurrent);
+                fSharedSynchLock = true;
+            }
+
+            if( dwPid == pwtlnItem->dwProcessId &&
+                (!fWaitAll || WaitIsSatisfied == IsRestOfWaitAllSatisfied(pwtlnItem)) )
+            {
+                //
+                // Target wait is satisfied
+                //
+                TRACE("Trying to switch wait state [%p] from WAIT/ALERTABLE "
+                      "to ACTIVE for thread=%u\n",
+                      pdwWaitState, pwtlnItem->dwThreadId);
+
+                if (CPalSynchronizationManager::InterlockedAwaken(pdwWaitState, FALSE))
+                {
+                    TRACE("Succeeded switching wait state [%p] from WAIT/ALERTABLE "
+                          "to TWS_ACTIVE for trhead=%u\n",
+                          pdwWaitState, pwtlnItem->dwThreadId);
+
+                    dwObjIdx = pwtlnItem->dwObjIndex;
+
+                    ThreadWaitInfo * ptwiWaitInfo = pwtlnItem->ptwiWaitInfo;
+                    bool fAbandoned = false;
+
+                    if (CObjectType::OwnershipTracked ==
+                        GetObjectType()->GetOwnershipSemantics())
+                    {
+                        // Get the abandoned status before resetting it by
+                        // assigning ownership to target thread
+                        fAbandoned = IsAbandoned();
+
+                        // Assign ownership to target thread
+                        palErr = AssignOwnershipToThread(pthrCurrent,
+                                                         ptwiWaitInfo->pthrOwner);
+                        if (NO_ERROR != palErr)
+                        {
+                            ERROR("Synch Worker: AssignOwnershipToThread "
+                                  "failed with error %u; ownership data on "
+                                  "object with SynchData %p may be "
+                                  "corrupted\n", palErr, this);
+                        }
+                    }
+
+                    if (fWaitAll)
+                    {
+                        // Wait all satisfied: unsignal other objects
+                        // involved in the wait
+                        CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll(
+                                                   pthrCurrent,
+                                                   ptwiWaitInfo->pthrOwner,
+                                                   pwtlnItem,
+                                                   this);
+                    }
+
+                    TRACE("Unregistering wait for thread %u and waking it up "
+                          "[pdwWaitState=%p]\n", pwtlnItem->dwThreadId,
+                          pdwWaitState);
+
+                    // Unregister the wait
+                    pSynchManager->UnRegisterWait(pthrCurrent,
+                                                  ptwiWaitInfo,
+                                                  fSharedObject || fSharedSynchLock);
+
+                    // After UnRegisterWait pwtlnItem is invalid
+                    pwtlnItem = NULL;
+
+                    palErr = CPalSynchronizationManager::WakeUpLocalThread(
+                        pthrCurrent,
+                        ptwiWaitInfo->pthrOwner,
+                        fAbandoned ? MutexAbondoned : WaitSucceeded,
+                        dwObjIdx);
+
+                    if (NO_ERROR != palErr)
+                    {
+                        ERROR("Failed to wakeup local thread %#x: "
+                              "object signaling may be "
+                              "lost\n", ptwiWaitInfo->pthrOwner->GetThreadId());
+                    }
+                    else
+                    {
+                        // A thread has been awakened
+                        lAwakenedCount++;
+                    }
+                }
+            }
+
+            // Go to the next item
+            shridItem = shridNextItem;
+            pwtlnItem = pwtlnNextItem;
+        }
+
+        if (fSharedSynchLock)
+        {
+            CPalSynchronizationManager::ReleaseSharedSynchLock(pthrCurrent);
+        }
+        return lAwakenedCount;
+    }
+
+    /*++
+    Method:
+      CSynchData::IsRestOfWaitAllSatisfied
+
+    Returns whether or not the current wait-all operation is fully satisfied,
+    assuming the current target object as signaled (i.e. whether or not all the
+    involved object, except the current one, are signaled).
+    It returns:
+     - WaitIsNotSatisfied if the wait-all is not fully satisfied.
+     - WaitIsSatisfied if the wait-all is fully satisfied.
+     - WaitMayBeSatisfied if the target thread lives in a different process and
+       therefore the wait may involve objects local to the remote process, and
+       as result is generally not possible to say whther or not the wait-all is
+       fully satisfied from the current process.
+
+    Note: this method must be called while holding the synchronization locks
+          appropriate to all the objects involved in the wait-all. If any
+          of the objects is shared, the caller must own both local and
+          shared synch locks; if no shared object is involved in the wait,
+          only the local synch lock is needed.
+    --*/
+    WaitCompletionState CSynchData::IsRestOfWaitAllSatisfied(
+        WaitingThreadsListNode * pwtlnNode)
+    {
+        int iSignaledOrOwnedObjCount = 0;
+        int iTgtCount = 0;
+        int i;
+        WaitCompletionState wcsWaitCompletionState = WaitIsNotSatisfied;
+        CSynchData * psdSynchDataItem = NULL;
+        ThreadWaitInfo * ptwiWaitInfo = NULL;
+
+        VALIDATEOBJECT(this);
+        VALIDATEOBJECT(pwtlnNode);
+
+        _ASSERT_MSG(0 != (WTLN_FLAG_WAIT_ALL & pwtlnNode->dwFlags),
+                    "IsRestOfWaitAllSatisfied() called on a normal "
+                    "(non wait all) wait");
+        _ASSERT_MSG((SharedObject == GetObjectDomain()) ==
+                    (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNode->dwFlags)),
+                    "WTLN_FLAG_OWNER_OBJECT_IS_SHARED in WaitingThreadsListNode "
+                    "not consistent with target object's domain\n");
+
+        if(gPID != pwtlnNode->dwProcessId)
+        {
+            ////////////////////////////
+            //
+            // Remote Thread Awakening
+            //
+            ////////////////////////////
+
+            // Cannot determine whether or not the wait all is satisfied from
+            // this process
+            wcsWaitCompletionState = WaitMayBeSatisfied;
+            goto IROWAS_exit;
+        }
+
+        ///////////////////////////
+        //
+        // Local Thread Awakening
+        //
+        ///////////////////////////
+
+        ptwiWaitInfo = pwtlnNode->ptwiWaitInfo;
+
+        iTgtCount = ptwiWaitInfo->lObjCount;
+        for (i=0; i < iTgtCount; i++)
+        {
+            WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i];
+            bool fRetVal;
+            bool fIsAbandoned;
+
+            VALIDATEOBJECT(pwtlnItem);
+
+            if (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnItem->dwFlags))
+            {
+                psdSynchDataItem = SharedIDToTypePointer(CSynchData,
+                    pwtlnItem->ptrOwnerObjSynchData.shrid);
+            }
+            else
+            {
+                psdSynchDataItem = pwtlnItem->ptrOwnerObjSynchData.ptr;
+            }
+
+            VALIDATEOBJECT(psdSynchDataItem);
+
+            if (pwtlnItem == pwtlnNode)
+            {
+                _ASSERT_MSG (this == psdSynchDataItem,
+                             "pwtlnNode and pwtlnItem match, but this "
+                             "and psdSynchDataItem don't\n");
+
+                // The target object (the one related to pwtlnNode) is counted as
+                // signaled/owned without checking it (also if it is not, as
+                // it normally happens when this method is called)
+                iSignaledOrOwnedObjCount++;
+                continue;
+            }
+
+            fRetVal = psdSynchDataItem->CanWaiterWaitWithoutBlocking(
+                ptwiWaitInfo->pthrOwner,
+                &fIsAbandoned);
+
+            if (fRetVal)
+            {
+                iSignaledOrOwnedObjCount++;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        if (iSignaledOrOwnedObjCount < iTgtCount)
+        {
+            wcsWaitCompletionState = WaitIsNotSatisfied;
+        }
+        else
+        {
+            wcsWaitCompletionState = WaitIsSatisfied;
+        }
+
+    IROWAS_exit:
+        TRACE("IsRestOfWaitAllSatisfied() returning %u \n", wcsWaitCompletionState);
+
+        return wcsWaitCompletionState;
+    }
+
+
+    /*++
+    Method:
+      CSynchData::SetOwner
+
+    Blindly sets the thread whose CPalThread is passed as argument, as the
+    owner of the current object.
+    WARNING: this method discards any previous ownership data and does not
+    update the list of the object owned by the owner thread.
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    void CSynchData::SetOwner(CPalThread * pOwnerThread)
+    {
+        VALIDATEOBJECT(this);
+
+        m_dwOwnerPid   = gPID;
+        m_dwOwnerTid   = pOwnerThread->GetThreadId();
+        m_pOwnerThread = pOwnerThread;
+    }
+
+    /*++
+    Method:
+      CSynchData::ResetOwnership
+
+    Resets current object's ownership data
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    void CSynchData::ResetOwnership()
+    {
+        VALIDATEOBJECT(this);
+
+        m_lOwnershipCount          = 0;
+        m_dwOwnerPid               = 0;
+        m_dwOwnerTid               = 0;
+        m_pOwnerThread             = NULL;
+        m_poolnOwnedObjectListNode = NULL;
+    }
+
+    /*++
+    Method:
+      CSynchData::AssignOwnershipToThread
+
+    Assigns thw ownership of the current object to the target thread, performing
+    all the operations neede to mantain the correct status of ownership data,
+    also handling recursive object ownership acquisition
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    PAL_ERROR CSynchData::AssignOwnershipToThread(
+        CPalThread * pthrCurrent,
+        CPalThread * pthrTarget)
+    {
+        // Note: when this method is called by ReleaseFirstWaiter there is
+        //       a small time window in which both SignalCount and
+        //       OwnershipCount can be greater than zero (which normally
+        //       is illegal). Anyway that is fine since ReleaseFirstWaiter
+        //       will restore the value right after, and such situation
+        //       takes place while holding synchroniztion locks, so no
+        //       other thread/process can access the object.
+
+        PAL_ERROR palErr = NO_ERROR;
+
+        _ASSERT_MSG(CObjectType::OwnershipTracked ==
+                    GetObjectType()->GetOwnershipSemantics(),
+                    "AssignOwnershipToThread called on a non-ownable "
+                    "CSynchData [this=%p OwnershipSemantics=%u]\n", this,
+                    GetObjectType()->GetOwnershipSemantics());
+
+
+        if (0 < m_lOwnershipCount)
+        {
+            //
+            // Object already owned, incrementing ownership count
+            //
+            _ASSERT_MSG(0 == GetSignalCount(),
+                        "Conflicting OwnershipCount and SignalCount values\n");
+
+            _ASSERT_MSG(pthrTarget == m_pOwnerThread && gPID == m_dwOwnerPid,
+                        "Attempting to assign ownership of CSynchData %p to "
+                        "thread {pid=%#x tid=%#x} while it is currently owned "
+                        "by thread {pid=%#x tid=%#x}\n", this,
+                        gPID, pthrTarget->GetThreadId(),
+                        m_dwOwnerPid, m_pOwnerThread->GetThreadId());
+
+            m_lOwnershipCount++;
+
+            TRACE("Incrementing ownership count for object with "
+                  "SynchData %p owned by thread %#x [new count=%d]\n",
+                  this, pthrTarget->GetThreadId(), m_lOwnershipCount);
+        }
+        else
+        {
+            //
+            // Acquiring currently not owned object
+            //
+            CPalSynchronizationManager * pSynchManager =
+                CPalSynchronizationManager::GetInstance();
+            OwnedObjectsListNode * pooln;
+
+            pooln = pSynchManager->CacheGetOwnedObjsListNode(pthrCurrent);
+            if (NULL == pooln)
+            {
+                ERROR("Out of memory while acquiring mutex ownership");
+                // In this case we bail out. It will result in no
+                // thread being awakend, which may cause deadlock,
+                // but it is anyway better than corrupting the
+                // ownership list
+                palErr = ERROR_NOT_ENOUGH_MEMORY;
+                goto AOTT_exit;
+            }
+
+            TRACE("Assigning ownable object with SynchData %p to "
+                  "thread %#x\n",
+                  this, pthrTarget->GetThreadId());
+
+            // Set ownership data
+            SetOwner(pthrTarget);
+            SetOwnershipListNode(pooln);
+            SetOwnershipCount(1);
+            SetAbandoned(false);
+
+            // Add object to list of owned objs for current thread
+            pooln->pPalObjSynchData = this;
+            AddRef();
+            pthrTarget->synchronizationInfo.AddObjectToOwnedList(pooln);
+        }
+
+    AOTT_exit:
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CSynchData::WaiterEnqueue
+
+    Adds the WaitingThreadsListNode passed as argument at the end of the
+    list of WaitingThreadsListNode for the current object, representing
+    the threads waiting on the current object. The target SynchData is
+    assumed to be local to the current process
+
+    Note: this method must be called while holding the local process
+          synchronization lock.
+    --*/
+    void CSynchData::WaiterEnqueue(WaitingThreadsListNode * pwtlnNewNode, bool fPrioritize)
+    {
+        VALIDATEOBJECT(this);
+        VALIDATEOBJECT(pwtlnNewNode);
+
+        _ASSERT_MSG(ProcessLocalObject == GetObjectDomain(),
+                    "Trying to enqueue a WaitingThreadsListNode as local "
+                    "on a shared object\n");
+        _ASSERT_MSG(0 == (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNewNode->dwFlags),
+                    "Trying to add a WaitingThreadsListNode marked as shared "
+                    "as it was a local one\n");
+
+        if (!fPrioritize)
+        {
+            // Enqueue normally to the end of the queue
+            WaitingThreadsListNode * pwtlnCurrLast = m_ptrWTLTail.ptr;
+
+            pwtlnNewNode->ptrNext.ptr = NULL;
+            if (NULL == pwtlnCurrLast)
+            {
+                _ASSERT_MSG(NULL == m_ptrWTLHead.ptr,
+                            "Corrupted waiting list on local CSynchData @ %p\n",
+                            this);
+
+                pwtlnNewNode->ptrPrev.ptr = NULL;
+                m_ptrWTLHead.ptr = pwtlnNewNode;
+                m_ptrWTLTail.ptr = pwtlnNewNode;
+            }
+            else
+            {
+                VALIDATEOBJECT(pwtlnCurrLast);
+
+                pwtlnNewNode->ptrPrev.ptr = pwtlnCurrLast;
+                pwtlnCurrLast->ptrNext.ptr = pwtlnNewNode;
+                m_ptrWTLTail.ptr = pwtlnNewNode;
+            }
+        }
+        else
+        {
+            // The wait is prioritized, enqueue to the beginning of the queue
+            WaitingThreadsListNode * pwtlnCurrFirst = m_ptrWTLHead.ptr;
+
+            pwtlnNewNode->ptrPrev.ptr = NULL;
+            if (NULL == pwtlnCurrFirst)
+            {
+                _ASSERT_MSG(NULL == m_ptrWTLTail.ptr,
+                            "Corrupted waiting list on local CSynchData @ %p\n",
+                            this);
+
+                pwtlnNewNode->ptrNext.ptr = NULL;
+                m_ptrWTLHead.ptr = pwtlnNewNode;
+                m_ptrWTLTail.ptr = pwtlnNewNode;
+            }
+            else
+            {
+                VALIDATEOBJECT(pwtlnCurrFirst);
+
+                pwtlnNewNode->ptrNext.ptr = pwtlnCurrFirst;
+                pwtlnCurrFirst->ptrPrev.ptr = pwtlnNewNode;
+                m_ptrWTLHead.ptr = pwtlnNewNode;
+            }
+        }
+
+        m_ulcWaitingThreads += 1;
+
+        return;
+    }
+
+    /*++
+    Method:
+      CSynchData::SharedWaiterEnqueue
+
+    Adds the WaitingThreadsListNode passed as argument at the end of the
+    list of WaitingThreadsListNode for the current object, representing
+    the threads waiting on the current object. The target SynchData is
+    assumed to be shared among processes
+
+    Note: this method must be called while holding both local and shared
+          synchronization locks.
+    --*/
+    void CSynchData::SharedWaiterEnqueue(SharedID shridNewNode, bool fPrioritize)
+    {
+        VALIDATEOBJECT(this);
+
+        _ASSERT_MSG(SharedObject == GetObjectDomain(),
+                    "Trying to enqueue a WaitingThreadsListNode as shared "
+                    "on a local object\n");
+
+        if (!fPrioritize)
+        {
+            // Enqueue normally to the end of the queue
+            SharedID shridCurrLast;
+            WaitingThreadsListNode * pwtlnCurrLast, * pwtlnNewNode;
+
+            shridCurrLast = m_ptrWTLTail.shrid;
+            pwtlnCurrLast = SharedIDToTypePointer(WaitingThreadsListNode, shridCurrLast);
+            pwtlnNewNode = SharedIDToTypePointer(WaitingThreadsListNode, shridNewNode);
+
+            _ASSERT_MSG(1 == (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNewNode->dwFlags),
+                        "Trying to add a WaitingThreadsListNode marked as local "
+                        "as it was a shared one\n");
+
+            VALIDATEOBJECT(pwtlnNewNode);
+
+            pwtlnNewNode->ptrNext.shrid = NULL;
+            if (NULL == pwtlnCurrLast)
+            {
+                _ASSERT_MSG(NULL == m_ptrWTLHead.shrid,
+                            "Corrupted waiting list on shared CSynchData at "
+                            "{shrid=%p, p=%p}\n", m_shridThis, this);
+
+                pwtlnNewNode->ptrPrev.shrid = NULL;
+                m_ptrWTLHead.shrid = shridNewNode;
+                m_ptrWTLTail.shrid = shridNewNode;
+            }
+            else
+            {
+                VALIDATEOBJECT(pwtlnCurrLast);
+
+                pwtlnNewNode->ptrPrev.shrid = shridCurrLast;
+                pwtlnCurrLast->ptrNext.shrid = shridNewNode;
+                m_ptrWTLTail.shrid = shridNewNode;
+            }
+        }
+        else
+        {
+            // The wait is prioritized, enqueue to the beginning of the queue
+            SharedID shridCurrFirst;
+            WaitingThreadsListNode * pwtlnCurrFirst, * pwtlnNewNode;
+
+            shridCurrFirst = m_ptrWTLHead.shrid;
+            pwtlnCurrFirst = SharedIDToTypePointer(WaitingThreadsListNode, shridCurrFirst);
+            pwtlnNewNode = SharedIDToTypePointer(WaitingThreadsListNode, shridNewNode);
+
+            _ASSERT_MSG(1 == (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNewNode->dwFlags),
+                        "Trying to add a WaitingThreadsListNode marked as local "
+                        "as it was a shared one\n");
+
+            VALIDATEOBJECT(pwtlnNewNode);
+
+            pwtlnNewNode->ptrPrev.shrid = NULL;
+            if (NULL == pwtlnCurrFirst)
+            {
+                _ASSERT_MSG(NULL == m_ptrWTLTail.shrid,
+                            "Corrupted waiting list on shared CSynchData at "
+                            "{shrid=%p, p=%p}\n", m_shridThis, this);
+
+                pwtlnNewNode->ptrNext.shrid = NULL;
+                m_ptrWTLHead.shrid = shridNewNode;
+                m_ptrWTLTail.shrid = shridNewNode;
+            }
+            else
+            {
+                VALIDATEOBJECT(pwtlnCurrFirst);
+
+                pwtlnNewNode->ptrNext.shrid = shridCurrFirst;
+                pwtlnCurrFirst->ptrPrev.shrid = shridNewNode;
+                m_ptrWTLHead.shrid = shridNewNode;
+            }
+        }
+
+        m_ulcWaitingThreads += 1;
+
+        return;
+    }
+
+#ifdef SYNCH_OBJECT_VALIDATION
+    CSynchData::~CSynchData()
+    {
+        ValidateObject(true);
+        InvalidateObject();
+    }
+    /*++
+    Method:
+      CSynchData::ValidateObject
+
+    Makes sure that the signature at the beginning and at the end of the
+    current object are those of a currently alive object (i.e. the object
+    has been constructed and does not appear to have been overwritten)
+    --*/
+    void CSynchData::ValidateObject(bool fDestructor)
+    {
+        TRACE("Verifying in-use CSynchData @ %p\n", this);
+        _ASSERT_MSG(HeadSignature == m_dwDebugHeadSignature,
+                    "CSynchData header signature corruption [p=%p]", this);
+        _ASSERT_MSG(TailSignature == m_dwDebugTailSignature,
+                    "CSynchData trailer signature corruption [p=%p]", this);
+        _ASSERT_MSG((fDestructor && 0 == m_lRefCount) ||
+                    (!fDestructor && 0 < m_lRefCount),
+                    "CSynchData %p with NULL reference count\n", this);
+    }
+    /*++
+    Method:
+      CSynchData::ValidateEmptyObject
+
+    Makes sure that the signature at the beginning and at the end of the
+    current object are not those of a currently alive object (i.e. the
+    object has not yet been constructed or it has alread been destructed)
+    --*/
+    void CSynchData::ValidateEmptyObject()
+    {
+        TRACE("Verifying empty CSynchData @ %p\n", this);
+        _ASSERT_MSG(HeadSignature != m_dwDebugHeadSignature,
+                    "CSynchData header previously signed [p=%p]", this);
+        _ASSERT_MSG(TailSignature != m_dwDebugTailSignature,
+                    "CSynchData trailer previously signed [p=%p]", this);
+    }
+    /*++
+    Method:
+      CSynchData::InvalidateObject
+
+    Turns signatures from alive object to destructed object
+    --*/
+    void CSynchData::InvalidateObject()
+    {
+        TRACE("Invalidating CSynchData @ %p\n", this);
+        m_dwDebugHeadSignature = EmptySignature;
+        m_dwDebugTailSignature = EmptySignature;
+    }
+#endif // SYNCH_OBJECT_VALIDATION
+}
+
diff --git a/src/pal/src/synchmgr/synchmanager.cpp b/src/pal/src/synchmgr/synchmanager.cpp
new file mode 100644 (file)
index 0000000..b359c2f
--- /dev/null
@@ -0,0 +1,4150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    synchmanager.cpp
+
+Abstract:
+    Implementation of Synchronization Manager and related objects
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do this first
+
+#include "synchmanager.hpp"
+#include "pal/file.hpp"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sched.h>
+#include <signal.h>
+#include <errno.h>
+#if HAVE_POLL
+#include <poll.h>
+#else
+#include "pal/fakepoll.h"
+#endif // HAVE_POLL
+
+#include <algorithm>
+
+const int CorUnix::CThreadSynchronizationInfo::PendingSignalingsArraySize;
+
+namespace CorUnix
+{
+    /////////////////////////////////
+    //                             //
+    //   WaitingThreadsListNode    //
+    //                             //
+    /////////////////////////////////
+#ifdef SYNCH_OBJECT_VALIDATION
+    _WaitingThreadsListNode::_WaitingThreadsListNode()
+    {
+        ValidateEmptyObject();
+        dwDebugHeadSignature = HeadSignature;
+        dwDebugTailSignature = TailSignature;
+    }
+    _WaitingThreadsListNode::~_WaitingThreadsListNode()
+    {
+        ValidateObject();
+        InvalidateObject();
+    }
+    void _WaitingThreadsListNode::ValidateObject()
+    {
+        TRACE("Verifying WaitingThreadsListNode @ %p\n", this);
+        _ASSERT_MSG(HeadSignature == dwDebugHeadSignature,
+                    "WaitingThreadsListNode header signature corruption [p=%p]",
+                    this);
+        _ASSERT_MSG(TailSignature == dwDebugTailSignature,
+                    "WaitingThreadsListNode trailer signature corruption [p=%p]",
+                    this);
+    }
+    void _WaitingThreadsListNode::ValidateEmptyObject()
+    {
+        _ASSERT_MSG(HeadSignature != dwDebugHeadSignature,
+                    "WaitingThreadsListNode header previously signed [p=%p]",
+                    this);
+        _ASSERT_MSG(TailSignature != dwDebugTailSignature,
+                    "WaitingThreadsListNode trailer previously signed [p=%p]",
+                    this);
+    }
+    void _WaitingThreadsListNode::InvalidateObject()
+    {
+        TRACE("Invalidating WaitingThreadsListNode @ %p\n", this);
+        dwDebugHeadSignature = EmptySignature;
+        dwDebugTailSignature = EmptySignature;
+    }
+#endif // SYNCH_OBJECT_VALIDATION
+
+    //////////////////////////////
+    //                          //
+    //  CPalSynchMgrController  //
+    //                          //
+    //////////////////////////////
+
+    /*++
+    Method:
+      CPalSynchMgrController::CreatePalSynchronizationManager
+
+    Creates the Synchronization Manager. It must be called once per process.
+    --*/
+    IPalSynchronizationManager * CPalSynchMgrController::CreatePalSynchronizationManager()
+    {
+        return CPalSynchronizationManager::CreatePalSynchronizationManager();
+    };
+
+    /*++
+    Method:
+      CPalSynchMgrController::StartWorker
+
+    Starts the Synchronization Manager's Worker Thread
+    --*/
+    PAL_ERROR CPalSynchMgrController::StartWorker(
+        CPalThread * pthrCurrent)
+    {
+        return CPalSynchronizationManager::StartWorker(pthrCurrent);
+    }
+
+    /*++
+    Method:
+      CPalSynchMgrController::PrepareForShutdown
+
+    This method performs the part of Synchronization Manager's shutdown that
+    needs to be carried out when core PAL subsystems are still active
+    --*/
+    PAL_ERROR CPalSynchMgrController::PrepareForShutdown()
+    {
+        return CPalSynchronizationManager::PrepareForShutdown();
+    }
+
+    //////////////////////////////////
+    //                              //
+    //  CPalSynchronizationManager  //
+    //                              //
+    //////////////////////////////////
+
+    IPalSynchronizationManager * g_pSynchronizationManager = NULL;
+
+    CPalSynchronizationManager * CPalSynchronizationManager::s_pObjSynchMgr = NULL;
+    Volatile<LONG> CPalSynchronizationManager::s_lInitStatus = SynchMgrStatusIdle;
+    CRITICAL_SECTION CPalSynchronizationManager::s_csSynchProcessLock;
+    CRITICAL_SECTION CPalSynchronizationManager::s_csMonitoredProcessesLock;
+
+    CPalSynchronizationManager::CPalSynchronizationManager()
+        : m_dwWorkerThreadTid(0),
+          m_pipoThread(NULL),
+          m_pthrWorker(NULL),
+          m_iProcessPipeRead(-1),
+          m_iProcessPipeWrite(-1),
+          m_pmplnMonitoredProcesses(NULL),
+          m_lMonitoredProcessesCount(0),
+          m_pmplnExitedNodes(NULL),
+          m_cacheWaitCtrlrs(CtrlrsCacheMaxSize),
+          m_cacheStateCtrlrs(CtrlrsCacheMaxSize),
+          m_cacheSynchData(SynchDataCacheMaxSize),
+          m_cacheSHRSynchData(SynchDataCacheMaxSize),
+          m_cacheWTListNodes(WTListNodeCacheMaxSize),
+          m_cacheSHRWTListNodes(WTListNodeCacheMaxSize),
+          m_cacheOwnedObjectsListNodes(OwnedObjectsListCacheMaxSize)
+    {
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+        m_iKQueue = -1;
+        // Initialize data to 0 and flags to EV_EOF
+        EV_SET(&m_keProcessPipeEvent, 0, 0, EV_EOF, 0, 0, 0);
+#endif // HAVE_KQUEUE
+    }
+
+    CPalSynchronizationManager::~CPalSynchronizationManager()
+    {
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::BlockThread
+
+    Called by a thread to go to sleep for a wait or a sleep
+
+    NOTE: This method must must be called without holding any
+          synchronization lock (as well as other locks)
+    --*/
+    PAL_ERROR CPalSynchronizationManager::BlockThread(
+        CPalThread *pthrCurrent,
+        DWORD dwTimeout,
+        bool fAlertable,
+        bool fIsSleep,
+        ThreadWakeupReason *ptwrWakeupReason,
+        DWORD * pdwSignaledObject)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        ThreadWakeupReason twrWakeupReason = WaitFailed;
+        DWORD * pdwWaitState;
+        DWORD dwWaitState = 0;
+        DWORD dwSigObjIdx = 0;
+        bool fEarlyDeath = false;
+
+        pdwWaitState = SharedIDToTypePointer(DWORD,
+                pthrCurrent->synchronizationInfo.m_shridWaitAwakened);
+
+        _ASSERT_MSG(NULL != pdwWaitState,
+                    "Got NULL pdwWaitState from m_shridWaitAwakened=%p\n",
+                    (VOID *)pthrCurrent->synchronizationInfo.m_shridWaitAwakened);
+
+        if (fIsSleep || fAlertable)
+        {
+            palErr = ERROR_INTERNAL_ERROR;
+            goto BT_exit;
+        }
+
+        {
+            TRACE("Current thread is about to block for waiting\n");
+
+            palErr = ThreadNativeWait(
+                &pthrCurrent->synchronizationInfo.m_tnwdNativeData,
+                dwTimeout,
+                &twrWakeupReason,
+                &dwSigObjIdx);
+
+            if (NO_ERROR != palErr)
+            {
+                ERROR("ThreadNativeWait() failed [palErr=%d]\n", palErr);
+                twrWakeupReason = WaitFailed;
+                goto BT_exit;
+            }
+
+            TRACE("ThreadNativeWait returned {WakeupReason=%u "
+                  "dwSigObjIdx=%u}\n", twrWakeupReason, dwSigObjIdx);
+        }
+
+        if (WaitTimeout == twrWakeupReason)
+        {
+            // timeout reached. set wait state back to 'active'
+            dwWaitState = (DWORD)(fAlertable ? TWS_ALERTABLE : TWS_WAITING);
+
+            TRACE("Current thread awakened for timeout: switching wait "
+                  "state [%p] from %u to TWS_ACTIVE [current *pdwWaitState=%u]\n",
+                   pdwWaitState, dwWaitState, *pdwWaitState);
+
+            DWORD dwOldWaitState = InterlockedCompareExchange(
+                                        (LONG *)pdwWaitState,
+                                        TWS_ACTIVE, (LONG)dwWaitState);
+
+            switch (dwOldWaitState)
+            {
+                case TWS_ACTIVE:
+                    // We were already ACTIVE; someone decided to wake up this
+                    // thread sometime between the moment the native wait
+                    // timed out and here. Since the signaling side succeeded
+                    // its InterlockedCompareExchange, it will signal the
+                    // condition/predicate pair (we just raced overtaking it);
+                    // therefore we need to clear the condition/predicate
+                    // by waiting on it one more time.
+                    // That will also cause this method to report a signal
+                    // rather than a timeout.
+                    // In the remote signaling scenario, this second wait
+                    // also makes sure that the shared id passed over the
+                    // process pipe is valid for the entire duration of time
+                    // in which the worker thread deals with it
+                    TRACE("Current thread already ACTIVE: a signaling raced "
+                          "with the timeout: re-waiting natively to clear the "
+                          "predicate\n");
+
+                    palErr = ThreadNativeWait(
+                        &pthrCurrent->synchronizationInfo.m_tnwdNativeData,
+                        SecondNativeWaitTimeout,
+                        &twrWakeupReason,
+                        &dwSigObjIdx);
+
+                    if (NO_ERROR != palErr)
+                    {
+                        ERROR("ThreadNativeWait() failed [palErr=%d]\n",
+                              palErr);
+                        twrWakeupReason = WaitFailed;
+                    }
+
+                    if (WaitTimeout == twrWakeupReason)
+                    {
+                        ERROR("Second native wait timed out\n");
+                    }
+
+                    break;
+                case TWS_EARLYDEATH:
+                    // Thread is about to be suspended by TerminateProcess.
+                    // Anyway, if the wait timed out, we still want to
+                    // (try to) unregister the wait (especially if it
+                    // involves shared objects)
+                    WARN("Thread is about to be suspended by TerminateProcess\n");
+                    fEarlyDeath = true;
+                    palErr = WAIT_FAILED;
+                    break;
+                case TWS_WAITING:
+                case TWS_ALERTABLE:
+                default:
+                    _ASSERT_MSG(dwOldWaitState == dwWaitState,
+                                "Unexpected wait status: actual=%u, expected=%u\n",
+                               dwOldWaitState, dwWaitState);
+                    break;
+            }
+        }
+
+        switch (twrWakeupReason)
+        {
+            case WaitTimeout:
+            {
+                // Awakened for timeout: we need to unregister the wait
+                ThreadWaitInfo * ptwiWaitInfo;
+
+                TRACE("Current thread awakened for timeout: unregistering the wait\n");
+
+                // Local lock
+                AcquireLocalSynchLock(pthrCurrent);
+
+                ptwiWaitInfo = GetThreadWaitInfo(pthrCurrent);
+
+                // Unregister the wait
+                // Note: UnRegisterWait will take care of grabbing the shared synch lock, if needed.
+                UnRegisterWait(pthrCurrent, ptwiWaitInfo, false);
+
+                // Unlock
+                ReleaseLocalSynchLock(pthrCurrent);
+
+                break;
+            }
+            case WaitSucceeded:
+            case MutexAbondoned:
+                *pdwSignaledObject = dwSigObjIdx;
+                break;
+            default:
+                // 'Alerted' and 'WaitFailed' go through this case
+                break;
+        }
+
+        // Set the returned wakeup reason
+        *ptwrWakeupReason = twrWakeupReason;
+
+        TRACE("Current thread is now active [WakeupReason=%u SigObjIdx=%u]\n",
+              twrWakeupReason, dwSigObjIdx);
+
+        _ASSERT_MSG(TWS_ACTIVE == VolatileLoad(pdwWaitState) ||
+                    TWS_EARLYDEATH == VolatileLoad(pdwWaitState),
+                    "Unexpected thread wait state %u\n", VolatileLoad(pdwWaitState));
+
+    BT_exit:
+        if (fEarlyDeath)
+        {
+            ThreadPrepareForShutdown();
+        }
+
+        return palErr;
+    }
+
+    PAL_ERROR CPalSynchronizationManager::ThreadNativeWait(
+        ThreadNativeWaitData * ptnwdNativeWaitData,
+        DWORD dwTimeout,
+        ThreadWakeupReason * ptwrWakeupReason,
+        DWORD * pdwSignaledObject)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        int iRet, iWaitRet = 0;
+        struct timespec tsAbsTmo;
+
+        TRACE("ThreadNativeWait(ptnwdNativeWaitData=%p, dwTimeout=%u, ...)\n",
+              ptnwdNativeWaitData, dwTimeout);
+
+        if (dwTimeout != INFINITE)
+        {
+            // Calculate absolute timeout
+            palErr = GetAbsoluteTimeout(dwTimeout, &tsAbsTmo, /*fPreferMonotonicClock*/ TRUE);
+            if (NO_ERROR != palErr)
+            {
+                ERROR("Failed to convert timeout to absolute timeout\n");
+                goto TNW_exit;
+            }
+        }
+
+        // Lock the mutex
+        iRet = pthread_mutex_lock(&ptnwdNativeWaitData->mutex);
+        if (0 != iRet)
+        {
+            ERROR("Internal Error: cannot lock mutex\n");
+            palErr = ERROR_INTERNAL_ERROR;
+            *ptwrWakeupReason = WaitFailed;
+            goto TNW_exit;
+        }
+
+        while (FALSE == ptnwdNativeWaitData->iPred)
+        {
+            if (INFINITE == dwTimeout)
+            {
+                iWaitRet = pthread_cond_wait(&ptnwdNativeWaitData->cond,
+                                             &ptnwdNativeWaitData->mutex);
+            }
+            else
+            {
+                iWaitRet = pthread_cond_timedwait(&ptnwdNativeWaitData->cond,
+                                                  &ptnwdNativeWaitData->mutex,
+                                                  &tsAbsTmo);
+            }
+
+            if (ETIMEDOUT == iWaitRet)
+            {
+                _ASSERT_MSG(INFINITE != dwTimeout,
+                            "Got ETIMEDOUT despite timeout being INFINITE\n");
+                break;
+            }
+            else if (0 != iWaitRet)
+            {
+                ERROR("pthread_cond_%swait returned %d [errno=%d (%s)]\n",
+                       (INFINITE == dwTimeout) ? "" : "timed",
+                       iWaitRet, errno, strerror(errno));
+                palErr = ERROR_INTERNAL_ERROR;
+                break;
+            }
+        }
+
+        // Reset the predicate
+        if (0 == iWaitRet)
+        {
+            // We don't want to reset the predicate if pthread_cond_timedwait
+            // timed out racing with a pthread_cond_signal. When
+            // pthread_cond_timedwait times out, it needs to grab the mutex
+            // before returning. At timeout time, it may happen that the
+            // signaling thread just grabbed the mutex, but it hasn't called
+            // pthread_cond_signal yet. In this scenario pthread_cond_timedwait
+            // will have to wait for the signaling side to release the mutex.
+            // As a result it will return with error timeout, but the predicate
+            // will be set. Since pthread_cond_timedwait timed out, the
+            // predicate value is intended for the next signal. In case of a
+            // object signaling racing with a wait timeout this predicate value
+            // will be picked up by the 'second native wait' (see comments in
+            // BlockThread).
+
+            ptnwdNativeWaitData->iPred = FALSE;
+        }
+
+        // Unlock the mutex
+        iRet = pthread_mutex_unlock(&ptnwdNativeWaitData->mutex);
+        if (0 != iRet)
+        {
+            ERROR("Cannot unlock mutex [err=%d]\n", iRet);
+            palErr = ERROR_INTERNAL_ERROR;
+            goto TNW_exit;
+        }
+
+        _ASSERT_MSG(ETIMEDOUT != iRet || INFINITE != dwTimeout, "Got timeout return code with INFINITE timeout\n");
+
+        if (0 == iWaitRet)
+        {
+            *ptwrWakeupReason  = ptnwdNativeWaitData->twrWakeupReason;
+            *pdwSignaledObject = ptnwdNativeWaitData->dwObjectIndex;
+        }
+        else if (ETIMEDOUT == iWaitRet)
+        {
+            *ptwrWakeupReason = WaitTimeout;
+        }
+
+    TNW_exit:
+        TRACE("ThreadNativeWait: returning %u [WakeupReason=%u]\n", palErr, *ptwrWakeupReason);
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::AbandonObjectsOwnedByThread
+
+    This method is called by a thread at thread-exit time to abandon
+    any currently owned waitable object (mutexes). If pthrTarget is
+    different from pthrCurrent, AbandonObjectsOwnedByThread assumes
+    to be called whether by TerminateThread or at shutdown time. See
+    comments below for more details
+    --*/
+    PAL_ERROR CPalSynchronizationManager::AbandonObjectsOwnedByThread(
+        CPalThread * pthrCurrent,
+        CPalThread * pthrTarget)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        OwnedObjectsListNode * poolnItem;
+        bool fSharedSynchLock = false;
+        CThreadSynchronizationInfo * pSynchInfo = &pthrTarget->synchronizationInfo;
+        CPalSynchronizationManager * pSynchManager = GetInstance();
+
+        // Local lock
+        AcquireLocalSynchLock(pthrCurrent);
+
+        // Abandon owned objects
+        while (NULL != (poolnItem = pSynchInfo->RemoveFirstObjectFromOwnedList()))
+        {
+            CSynchData * psdSynchData = poolnItem->pPalObjSynchData;
+
+            _ASSERT_MSG(NULL != psdSynchData,
+                        "NULL psdSynchData pointer in ownership list node\n");
+
+            VALIDATEOBJECT(psdSynchData);
+
+            TRACE("Abandoning object with SynchData at %p\n", psdSynchData);
+
+            if (!fSharedSynchLock &&
+                (SharedObject == psdSynchData->GetObjectDomain()))
+            {
+                AcquireSharedSynchLock(pthrCurrent);
+                fSharedSynchLock = true;
+            }
+
+            // Reset ownership data
+            psdSynchData->ResetOwnership();
+
+            // Set abandoned status; in case there is a thread to be released:
+            //  - if the thread is local, ReleaseFirstWaiter will reset the
+            //    abandoned status
+            //  - if the thread is remote, the remote worker thread will use
+            //    the value and reset it
+            psdSynchData->SetAbandoned(true);
+
+            // Signal the object and trigger thread awakening
+            psdSynchData->Signal(pthrCurrent, 1, false);
+
+            // Release reference to to SynchData
+            psdSynchData->Release(pthrCurrent);
+
+            // Return node to the cache
+            pSynchManager->m_cacheOwnedObjectsListNodes.Add(pthrCurrent, poolnItem);
+        }
+
+        if (pthrTarget != pthrCurrent)
+        {
+            // If the target thead is not the current one, we are being called
+            // at shutdown time, right before the target thread is suspended,
+            // or anyway the target thread is being terminated.
+            // In this case we switch its wait state to TWS_EARLYDEATH so that,
+            // if the thread is currently waiting/sleeping and it wakes up
+            // before shutdown code manage to suspend it, it will be rerouted
+            // to ThreadPrepareForShutdown (that will be done without holding
+            // any internal lock, in a way to accomodate shutdown time thread
+            // suspension).
+            // At this time we also unregister the wait, so no dummy nodes are
+            // left around on waiting objects.
+            // The TWS_EARLYDEATH wait-state will also prevent the thread from
+            // successfully registering for a possible new wait in the same
+            // time window.
+            LONG lTWState;
+            DWORD * pdwWaitState;
+
+            pdwWaitState = SharedIDToTypePointer(DWORD, pthrTarget->synchronizationInfo.m_shridWaitAwakened);
+            lTWState = InterlockedExchange((LONG *)pdwWaitState, TWS_EARLYDEATH);
+
+            if (( ((LONG)TWS_WAITING == lTWState) || ((LONG)TWS_ALERTABLE == lTWState) ) &&
+                (0 < pSynchInfo->m_twiWaitInfo.lObjCount))
+            {
+                // Unregister the wait
+                // Note: UnRegisterWait will take care of grabbing the shared synch lock, if needed.
+                UnRegisterWait(pthrCurrent, &pSynchInfo->m_twiWaitInfo, fSharedSynchLock);
+            }
+        }
+
+        // Unlock
+        if (fSharedSynchLock)
+        {
+            ReleaseSharedSynchLock(pthrCurrent);
+            fSharedSynchLock = false;
+        }
+
+        ReleaseLocalSynchLock(pthrCurrent);
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::GetSynchWaitControllersForObjects
+
+    Returns an array of wait controllers, one for each of the objects
+    in rgObjects
+    --*/
+    PAL_ERROR CPalSynchronizationManager::GetSynchWaitControllersForObjects(
+        CPalThread *pthrCurrent,
+        IPalObject *rgObjects[],
+        DWORD dwObjectCount,
+        ISynchWaitController * rgControllers[])
+    {
+        return GetSynchControllersForObjects(pthrCurrent,
+                                             rgObjects,
+                                             dwObjectCount,
+                                             (void **)rgControllers,
+                                             CSynchControllerBase::WaitController);
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::GetSynchStateControllersForObjects
+
+    Returns an array of state controllers, one for each of the objects
+    in rgObjects
+    --*/
+    PAL_ERROR CPalSynchronizationManager::GetSynchStateControllersForObjects(
+        CPalThread *pthrCurrent,
+        IPalObject *rgObjects[],
+        DWORD dwObjectCount,
+        ISynchStateController *rgControllers[])
+    {
+        return GetSynchControllersForObjects(pthrCurrent,
+                                             rgObjects,
+                                             dwObjectCount,
+                                             (void **)rgControllers,
+                                             CSynchControllerBase::StateController);
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::GetSynchControllersForObjects
+
+    Internal common implementation for GetSynchWaitControllersForObjects and
+    GetSynchStateControllersForObjects
+    --*/
+    PAL_ERROR CPalSynchronizationManager::GetSynchControllersForObjects(
+        CPalThread *pthrCurrent,
+        IPalObject *rgObjects[],
+        DWORD dwObjectCount,
+        void ** ppvControllers,
+        CSynchControllerBase::ControllerType ctCtrlrType)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        unsigned int uIdx, uCount = 0, uSharedObjectCount = 0;
+        WaitDomain wdWaitDomain = LocalWait;
+        CObjectType * potObjectType = NULL;
+        unsigned int uErrCleanupIdxFirstNotInitializedCtrlr = 0;
+        unsigned int uErrCleanupIdxLastCtrlr = 0;
+        bool fLocalSynchLock = false;
+
+        union
+        {
+            CSynchWaitController * pWaitCtrlrs[MAXIMUM_WAIT_OBJECTS];
+            CSynchStateController * pStateCtrlrs[MAXIMUM_WAIT_OBJECTS];
+        } Ctrlrs;
+
+        if ((dwObjectCount <= 0) || (dwObjectCount > MAXIMUM_WAIT_OBJECTS))
+        {
+            palErr = ERROR_INVALID_PARAMETER;
+            goto GSCFO_exit;
+        }
+
+        if (CSynchControllerBase::WaitController == ctCtrlrType)
+        {
+            uCount = (unsigned int)m_cacheWaitCtrlrs.Get(pthrCurrent,
+                                                         dwObjectCount,
+                                                         Ctrlrs.pWaitCtrlrs);
+        }
+        else
+        {
+            uCount = (unsigned int)m_cacheStateCtrlrs.Get(pthrCurrent,
+                                                          dwObjectCount,
+                                                          Ctrlrs.pStateCtrlrs);
+        }
+
+        if (uCount < dwObjectCount)
+        {
+            // We got less controllers (uCount) than we asked for (dwObjectCount),
+            // probably because of low memory.
+            // None of these controllers is initialized, so they must be all
+            // returned directly to the cache
+            uErrCleanupIdxLastCtrlr = uCount;
+
+            palErr = ERROR_NOT_ENOUGH_MEMORY;
+            goto GSCFO_error_cleanup;
+        }
+
+        //
+        // We need to acquire the local synch lock before evaluating object domains
+        //
+        AcquireLocalSynchLock(pthrCurrent);
+        fLocalSynchLock = true;
+
+        for (uIdx=0; uIdx<dwObjectCount; uIdx++)
+        {
+            if (SharedObject == rgObjects[uIdx]->GetObjectDomain())
+            {
+                ++uSharedObjectCount;
+            }
+
+            if (uSharedObjectCount > 0 && uSharedObjectCount <= uIdx)
+            {
+                wdWaitDomain = MixedWait;
+                break;
+            }
+        }
+
+        if (dwObjectCount == uSharedObjectCount)
+        {
+            wdWaitDomain = SharedWait;
+        }
+
+        for (uIdx=0;uIdx<dwObjectCount;uIdx++)
+        {
+            void * pvSData;
+            CSynchData * psdSynchData;
+            ObjectDomain odObjectDomain = rgObjects[uIdx]->GetObjectDomain();
+
+            palErr = rgObjects[uIdx]->GetObjectSynchData((void **)&pvSData);
+            if (NO_ERROR != palErr)
+            {
+                break;
+            }
+
+            psdSynchData = (SharedObject == odObjectDomain) ? SharedIDToTypePointer(
+                CSynchData, reinterpret_cast<SharedID>(pvSData)) :
+                static_cast<CSynchData *>(pvSData);
+
+            VALIDATEOBJECT(psdSynchData);
+
+            potObjectType = rgObjects[uIdx]->GetObjectType();
+
+            if (CSynchControllerBase::WaitController == ctCtrlrType)
+            {
+                Ctrlrs.pWaitCtrlrs[uIdx]->Init(pthrCurrent,
+                                            ctCtrlrType,
+                                            odObjectDomain,
+                                            potObjectType,
+                                            psdSynchData,
+                                            wdWaitDomain);
+            }
+            else
+            {
+                Ctrlrs.pStateCtrlrs[uIdx]->Init(pthrCurrent,
+                                             ctCtrlrType,
+                                             odObjectDomain,
+                                             potObjectType,
+                                             psdSynchData,
+                                             wdWaitDomain);
+            }
+
+            if (CSynchControllerBase::WaitController == ctCtrlrType &&
+                otiProcess == potObjectType->GetId())
+            {
+                CProcProcessLocalData * pProcLocData;
+                IDataLock * pDataLock;
+
+                palErr = rgObjects[uIdx]->GetProcessLocalData(
+                    pthrCurrent,
+                    ReadLock,
+                    &pDataLock,
+                    (void **)&pProcLocData);
+
+                if (NO_ERROR != palErr)
+                {
+                    // In case of failure here, bail out of the loop, but
+                    // keep track (by incrementing the counter 'uIdx') of the
+                    // fact that this controller has already being initialized
+                    // and therefore need to be Release'd rather than just
+                    // returned to the cache
+                    uIdx++;
+                    break;
+                }
+
+                Ctrlrs.pWaitCtrlrs[uIdx]->SetProcessData(rgObjects[uIdx], pProcLocData);
+                pDataLock->ReleaseLock(pthrCurrent, false);
+            }
+        }
+        if (NO_ERROR != palErr)
+        {
+            // An error occurred while initializing the (uIdx+1)-th controller,
+            // i.e. the one at index uIdx; therefore the first uIdx controllers
+            // must be Release'd, while the remaining uCount-uIdx must be returned
+            // directly to the cache.
+            uErrCleanupIdxFirstNotInitializedCtrlr = uIdx;
+            uErrCleanupIdxLastCtrlr = dwObjectCount;
+
+            goto GSCFO_error_cleanup;
+        }
+
+        // Succeeded
+        if (CSynchControllerBase::WaitController == ctCtrlrType)
+        {
+            for (uIdx=0;uIdx<dwObjectCount;uIdx++)
+            {
+                // The multiple cast is NEEDED, though currently it does not
+                // change the value ot the pointer. Anyway, if in the future
+                // a virtual method should be added to the base class
+                // CSynchControllerBase, both derived classes would have two
+                // virtual tables, therefore a static cast from, for instance,
+                // a CSynchWaitController* to a ISynchWaitController* would
+                // return the given pointer incremented by the size of a
+                // generic pointer on the specific platform
+                ppvControllers[uIdx] = reinterpret_cast<void *>(
+                    static_cast<ISynchWaitController *>(Ctrlrs.pWaitCtrlrs[uIdx]));
+            }
+        }
+        else
+        {
+            for (uIdx=0;uIdx<dwObjectCount;uIdx++)
+            {
+                // See comment above
+                ppvControllers[uIdx] = reinterpret_cast<void *>(
+                    static_cast<ISynchStateController *>(Ctrlrs.pStateCtrlrs[uIdx]));
+            }
+        }
+
+        // Succeeded: skip error cleanup
+        goto GSCFO_exit;
+
+    GSCFO_error_cleanup:
+        if (CSynchControllerBase::WaitController == ctCtrlrType)
+        {
+            // Release already initialized wait controllers
+            for (uIdx=0; uIdx<uErrCleanupIdxFirstNotInitializedCtrlr; uIdx++)
+            {
+                Ctrlrs.pWaitCtrlrs[uIdx]->Release();
+            }
+
+            // Return to the cache not yet initialized wait controllers
+            for (uIdx=uErrCleanupIdxFirstNotInitializedCtrlr; uIdx<uErrCleanupIdxLastCtrlr; uIdx++)
+            {
+                m_cacheWaitCtrlrs.Add(pthrCurrent, Ctrlrs.pWaitCtrlrs[uIdx]);
+            }
+        }
+        else
+        {
+            // Release already initialized state controllers
+            for (uIdx=0; uIdx<uErrCleanupIdxFirstNotInitializedCtrlr; uIdx++)
+            {
+                Ctrlrs.pStateCtrlrs[uIdx]->Release();
+            }
+
+            // Return to the cache not yet initialized state controllers
+            for (uIdx=uErrCleanupIdxFirstNotInitializedCtrlr; uIdx<uErrCleanupIdxLastCtrlr; uIdx++)
+            {
+                m_cacheStateCtrlrs.Add(pthrCurrent, Ctrlrs.pStateCtrlrs[uIdx]);
+            }
+        }
+
+    GSCFO_exit:
+        if (fLocalSynchLock)
+        {
+            ReleaseLocalSynchLock(pthrCurrent);
+        }
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::AllocateObjectSynchData
+
+    Returns a new SynchData for an object of given type and domain
+    --*/
+    PAL_ERROR CPalSynchronizationManager::AllocateObjectSynchData(
+        CObjectType *potObjectType,
+        ObjectDomain odObjectDomain,
+        VOID **ppvSynchData)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        CSynchData * psdSynchData = NULL;
+        CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+        if (SharedObject == odObjectDomain)
+        {
+            SharedID shridSynchData = m_cacheSHRSynchData.Get(pthrCurrent);
+            if (NULL == shridSynchData)
+            {
+                ERROR("Unable to allocate shared memory\n");
+                return ERROR_NOT_ENOUGH_MEMORY;
+            }
+
+            psdSynchData = SharedIDToTypePointer(CSynchData, shridSynchData);
+
+            VALIDATEOBJECT(psdSynchData);
+
+            _ASSERT_MSG(NULL != psdSynchData, "Bad shared memory pointer\n");
+
+            // Initialize waiting list pointers
+            psdSynchData->SetWTLHeadShrPtr(NULL);
+            psdSynchData->SetWTLTailShrPtr(NULL);
+
+            // Store shared pointer to this object
+            psdSynchData->SetSharedThis(shridSynchData);
+
+            *ppvSynchData = reinterpret_cast<void *>(shridSynchData);
+        }
+        else
+        {
+            psdSynchData = m_cacheSynchData.Get(pthrCurrent);
+            if (NULL == psdSynchData)
+            {
+                ERROR("Unable to allocate memory\n");
+                return ERROR_NOT_ENOUGH_MEMORY;
+            }
+
+            // Initialize waiting list pointers
+            psdSynchData->SetWTLHeadPtr(NULL);
+            psdSynchData->SetWTLTailPtr(NULL);
+
+            // Set shared this pointer to NULL
+            psdSynchData->SetSharedThis(NULL);
+
+            *ppvSynchData = static_cast<void *>(psdSynchData);
+        }
+
+        // Initialize object domain and object type;
+        psdSynchData->SetObjectDomain(odObjectDomain);
+        psdSynchData->SetObjectType(potObjectType);
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::FreeObjectSynchData
+
+    Called to return a no longer used SynchData to the Synchronization Manager.
+    The SynchData may actually survive this call, since it is a ref-counted
+    object and at FreeObjectSynchData time it may still be used from within
+    the Synchronization Manager itself (e.g. the worker thread).
+    --*/
+    void CPalSynchronizationManager::FreeObjectSynchData(
+        CObjectType *potObjectType,
+        ObjectDomain odObjectDomain,
+        VOID *pvSynchData)
+    {
+        CSynchData * psdSynchData;
+        CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+        if (odObjectDomain == SharedObject)
+        {
+            psdSynchData = SharedIDToTypePointer(CSynchData,
+                reinterpret_cast<SharedID>(pvSynchData));
+
+            if (NULL == psdSynchData)
+            {
+                ASSERT("Bad shared memory pointer\n");
+                return;
+            }
+        }
+        else
+        {
+            psdSynchData = static_cast<CSynchData *>(pvSynchData);
+        }
+
+        psdSynchData->Release(pthrCurrent);
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::CreateSynchStateController
+
+    Creates a state controller for the given object
+    --*/
+    PAL_ERROR CPalSynchronizationManager::CreateSynchStateController(
+        CPalThread *pthrCurrent,
+        CObjectType *potObjectType,
+        VOID *pvSynchData,
+        ObjectDomain odObjectDomain,
+        ISynchStateController **ppStateController)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        CSynchStateController * pCtrlr =  NULL;
+        WaitDomain wdWaitDomain = (SharedObject == odObjectDomain) ? SharedWait : LocalWait;
+        CSynchData * psdSynchData;
+
+        psdSynchData = (SharedObject == odObjectDomain) ? SharedIDToTypePointer(CSynchData, reinterpret_cast<SharedID>(pvSynchData))
+                                                        : static_cast<CSynchData *>(pvSynchData);
+
+        VALIDATEOBJECT(psdSynchData);
+
+        pCtrlr = m_cacheStateCtrlrs.Get(pthrCurrent);
+        if (NULL == pCtrlr)
+        {
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+
+        pCtrlr->Init(pthrCurrent,
+                     CSynchControllerBase::StateController,
+                     odObjectDomain,
+                     potObjectType,
+                     psdSynchData,
+                     wdWaitDomain);
+
+        // Succeeded
+        *ppStateController = (ISynchStateController *)pCtrlr;
+
+        if (NO_ERROR != palErr)
+        {
+            m_cacheStateCtrlrs.Add(pthrCurrent, pCtrlr);
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::CreateSynchWaitController
+
+    Creates a wait controller for the given object
+    --*/
+    PAL_ERROR CPalSynchronizationManager::CreateSynchWaitController(
+        CPalThread *pthrCurrent,
+        CObjectType *potObjectType,
+        VOID *pvSynchData,
+        ObjectDomain odObjectDomain,
+        ISynchWaitController **ppWaitController)
+    {
+        CSynchWaitController * pCtrlr =  NULL;
+        WaitDomain wdWaitDomain = (SharedObject == odObjectDomain) ? SharedWait : LocalWait;
+        CSynchData * psdSynchData;
+
+        psdSynchData = (SharedObject == odObjectDomain) ? SharedIDToTypePointer(
+            CSynchData, reinterpret_cast<SharedID>(pvSynchData)) :
+            static_cast<CSynchData *>(pvSynchData);
+
+        VALIDATEOBJECT(psdSynchData);
+
+        pCtrlr = m_cacheWaitCtrlrs.Get(pthrCurrent);
+        if (NULL == pCtrlr)
+        {
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+
+        pCtrlr->Init(pthrCurrent,
+                     CSynchControllerBase::WaitController,
+                     odObjectDomain,
+                     potObjectType,
+                     psdSynchData,
+                     wdWaitDomain);
+
+        // Succeeded
+        *ppWaitController = (ISynchWaitController *)pCtrlr;
+
+        return NO_ERROR;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::CreatePalSynchronizationManager
+
+    Creates the Synchronization Manager.
+    Private method, it is called only by CPalSynchMgrController.
+    --*/
+    IPalSynchronizationManager * CPalSynchronizationManager::CreatePalSynchronizationManager()
+    {
+        if (s_pObjSynchMgr != NULL)
+        {
+            ASSERT("Multiple PAL Synchronization manager initializations\n");
+            return NULL;
+        }
+
+        Initialize();
+        return static_cast<IPalSynchronizationManager *>(s_pObjSynchMgr);
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::Initialize
+
+    Internal Synchronization Manager initialization
+    --*/
+    PAL_ERROR CPalSynchronizationManager::Initialize()
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        LONG lInit;
+        CPalSynchronizationManager * pSynchManager = NULL;
+
+        lInit = InterlockedCompareExchange(&s_lInitStatus,
+                                           (LONG)SynchMgrStatusInitializing,
+                                           (LONG)SynchMgrStatusIdle);
+
+        if ((LONG)SynchMgrStatusIdle != lInit)
+        {
+            ASSERT("Synchronization Manager already being initialized");
+            palErr = ERROR_INTERNAL_ERROR;
+            goto I_exit;
+        }
+
+        InternalInitializeCriticalSection(&s_csSynchProcessLock);
+        InternalInitializeCriticalSection(&s_csMonitoredProcessesLock);
+
+        pSynchManager = InternalNew<CPalSynchronizationManager>();
+        if (NULL == pSynchManager)
+        {
+            ERROR("Failed to allocate memory for Synchronization Manager");
+            palErr = ERROR_NOT_ENOUGH_MEMORY;
+            goto I_exit;
+        }
+
+        if (!pSynchManager->CreateProcessPipe())
+        {
+            ERROR("Unable to create process pipe \n");
+            palErr = ERROR_OPEN_FAILED;
+            goto I_exit;
+        }
+
+        s_pObjSynchMgr = pSynchManager;
+
+        // Initialization was successful
+        g_pSynchronizationManager =
+            static_cast<IPalSynchronizationManager *>(pSynchManager);
+        s_lInitStatus = (LONG)SynchMgrStatusRunning;
+
+    I_exit:
+        if (NO_ERROR != palErr)
+        {
+            s_lInitStatus = (LONG)SynchMgrStatusError;
+            if (NULL != pSynchManager)
+            {
+                pSynchManager->ShutdownProcessPipe();
+            }
+
+            s_pObjSynchMgr = NULL;
+            g_pSynchronizationManager = NULL;
+            InternalDelete(pSynchManager);
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::StartWorker
+
+    Starts the Synchronization Manager's Worker Thread.
+    Private method, it is called only by CPalSynchMgrController.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::StartWorker(
+        CPalThread * pthrCurrent)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        CPalSynchronizationManager * pSynchManager = GetInstance();
+
+        if ((NULL == pSynchManager) || ((LONG)SynchMgrStatusRunning != s_lInitStatus))
+        {
+            ERROR("Trying to to create worker thread in invalid state\n");
+            return ERROR_INTERNAL_ERROR;
+        }
+
+        HANDLE hWorkerThread = NULL;
+        SIZE_T osThreadId = 0;
+        palErr = InternalCreateThread(pthrCurrent,
+                                      NULL,
+                                      0,
+                                      &WorkerThread,
+                                      (PVOID)pSynchManager,
+                                      0,
+                                      PalWorkerThread,
+                                      &osThreadId,
+                                      &hWorkerThread);
+
+        if (NO_ERROR == palErr)
+        {
+            pSynchManager->m_dwWorkerThreadTid = (DWORD)osThreadId;
+            palErr = InternalGetThreadDataFromHandle(pthrCurrent,
+                                                     hWorkerThread,
+                                                     &pSynchManager->m_pthrWorker,
+                                                     &pSynchManager->m_pipoThread);
+            if (NO_ERROR != palErr)
+            {
+                ERROR("Unable to get worker thread data\n");
+            }
+        }
+        else
+        {
+            ERROR("Unable to create worker thread\n");
+        }
+
+        if (NULL != hWorkerThread)
+        {
+            CloseHandle(hWorkerThread);
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::PrepareForShutdown
+
+    This method performs the part of Synchronization Manager's shutdown that
+    needs to be carried out when core PAL subsystems are still active.
+    Private method, it is called only by CPalSynchMgrController.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::PrepareForShutdown()
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        CPalSynchronizationManager * pSynchManager = GetInstance();
+        CPalThread * pthrCurrent = InternalGetCurrentThread();
+        int iRet;
+        ThreadNativeWaitData * ptnwdWorkerThreadNativeData;
+        struct timespec tsAbsTmo = { 0, 0 };
+
+        LONG lInit = InterlockedCompareExchange(&s_lInitStatus,
+            (LONG)SynchMgrStatusShuttingDown, (LONG)SynchMgrStatusRunning);
+
+        if ((LONG)SynchMgrStatusRunning != lInit)
+        {
+            ASSERT("Unexpected initialization status found "
+                   "in PrepareForShutdown [expected=%d current=%d]\n",
+                   SynchMgrStatusRunning, lInit);
+            // We intentionally not set s_lInitStatus to SynchMgrStatusError
+            // cause this could interfere with a previous thread already
+            // executing shutdown
+            palErr = ERROR_INTERNAL_ERROR;
+            goto PFS_exit;
+        }
+
+        // Discard process monitoring for process waits
+        pSynchManager->DiscardMonitoredProcesses(pthrCurrent);
+
+        if (NULL == pSynchManager->m_pipoThread)
+        {
+            // If m_pipoThread is NULL here, that means that StartWorker has
+            // never been called. That may happen if PAL_Initialize fails
+            // sometime after having called CreatePalSynchronizationManager,
+            // but before calling StartWorker. Nothing else to do here.
+            goto PFS_exit;
+        }
+
+        palErr = pSynchManager->WakeUpLocalWorkerThread(SynchWorkerCmdShutdown);
+        if (NO_ERROR != palErr)
+        {
+            ERROR("Failed stopping worker thread [palErr=%u]\n", palErr);
+            s_lInitStatus = SynchMgrStatusError;
+            goto PFS_exit;
+        }
+
+        ptnwdWorkerThreadNativeData =
+            &pSynchManager->m_pthrWorker->synchronizationInfo.m_tnwdNativeData;
+
+        palErr = GetAbsoluteTimeout(WorkerThreadTerminationTimeout, &tsAbsTmo, /*fPreferMonotonicClock*/ TRUE);
+        if (NO_ERROR != palErr)
+        {
+            ERROR("Failed to convert timeout to absolute timeout\n");
+            s_lInitStatus = SynchMgrStatusError;
+            goto PFS_exit;
+        }
+
+        // Using the worker thread's predicate/condition/mutex
+        // to wait for worker thread to be done
+        iRet = pthread_mutex_lock(&ptnwdWorkerThreadNativeData->mutex);
+        if (0 != iRet)
+        {
+            // pthread calls might fail if the shutdown is called
+            // from a signal handler. In this case just don't wait
+            // for the worker thread
+            ERROR("Cannot lock mutex [err=%d]\n", iRet);
+            palErr = ERROR_INTERNAL_ERROR;
+            s_lInitStatus = SynchMgrStatusError;
+            goto PFS_exit;
+        }
+
+        while (FALSE == ptnwdWorkerThreadNativeData->iPred)
+        {
+            iRet = pthread_cond_timedwait(&ptnwdWorkerThreadNativeData->cond,
+                                          &ptnwdWorkerThreadNativeData->mutex,
+                                          &tsAbsTmo);
+            if (0 != iRet)
+            {
+                if (ETIMEDOUT == iRet)
+                {
+                    WARN("Timed out waiting for worker thread to exit "
+                         "(tmo=%u ms)\n", WorkerThreadTerminationTimeout);
+                }
+                else
+                {
+                    ERROR("pthread_cond_timedwait returned %d [errno=%d (%s)]\n",
+                          iRet, errno, strerror(errno));
+                }
+                break;
+            }
+        }
+        if (0 == iRet)
+        {
+            ptnwdWorkerThreadNativeData->iPred = FALSE;
+        }
+        iRet = pthread_mutex_unlock(&ptnwdWorkerThreadNativeData->mutex);
+        if (0 != iRet)
+        {
+            ERROR("Cannot unlock mutex [err=%d]\n", iRet);
+            palErr = ERROR_INTERNAL_ERROR;
+            s_lInitStatus = SynchMgrStatusError;
+            goto PFS_exit;
+        }
+
+    PFS_exit:
+        if (NO_ERROR == palErr)
+        {
+            if (NULL != pSynchManager->m_pipoThread)
+            {
+                pSynchManager->m_pipoThread->ReleaseReference(pthrCurrent);
+
+                // After this release both m_pipoThread and m_pthrWorker
+                // are no longer valid
+                pSynchManager->m_pipoThread = NULL;
+                pSynchManager->m_pthrWorker = NULL;
+            }
+
+            // Ready for process shutdown
+            s_lInitStatus = SynchMgrStatusReadyForProcessShutDown;
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::WorkerThread
+
+    Synchronization Manager's Worker Thread
+    --*/
+    DWORD PALAPI CPalSynchronizationManager::WorkerThread(LPVOID pArg)
+    {
+        PAL_ERROR palErr;
+        bool fShuttingDown = false;
+        bool fWorkerIsDone = false;
+        int iPollTimeout = INFTIM;
+        SynchWorkerCmd swcCmd;
+        ThreadWakeupReason twrWakeUpReason;
+        SharedID shridMarshaledData;
+        DWORD dwData;
+        CPalSynchronizationManager * pSynchManager =
+            reinterpret_cast<CPalSynchronizationManager*>(pArg);
+        CPalThread * pthrWorker = InternalGetCurrentThread();
+
+        while (!fWorkerIsDone)
+        {
+            LONG lProcessCount;
+
+            palErr = pSynchManager->ReadCmdFromProcessPipe(iPollTimeout,
+                                                           &swcCmd,
+                                                           &shridMarshaledData,
+                                                           &dwData);
+            if (NO_ERROR != palErr)
+            {
+                ERROR("Received error %x from ReadCmdFromProcessPipe()\n",
+                      palErr);
+                continue;
+            }
+            switch (swcCmd)
+            {
+                case SynchWorkerCmdNop:
+                    TRACE("Synch Worker: received SynchWorkerCmdNop\n");
+                    if (fShuttingDown)
+                    {
+                        TRACE("Synch Worker: received a timeout when "
+                              "fShuttingDown==true: worker is done, bailing "
+                              "out from the loop\n");
+
+                        // Whether WorkerThreadShuttingDownTimeout has elapsed
+                        // or the last process with a descriptor opened for
+                        // write on our process pipe, has just closed it,
+                        // causing an EOF on the read fd (that can happen only
+                        // at shutdown time since during normal run time we
+                        // hold a fd opened for write within this process).
+                        // In both the case it is time to go for the worker
+                        // thread.
+                        fWorkerIsDone = true;
+                    }
+                    else
+                    {
+                        lProcessCount = pSynchManager->DoMonitorProcesses(pthrWorker);
+                        if (lProcessCount > 0)
+                        {
+                            iPollTimeout = WorkerThreadProcMonitoringTimeout;
+                        }
+                        else
+                        {
+                            iPollTimeout = INFTIM;
+                        }
+                    }
+                    break;
+                case SynchWorkerCmdRemoteSignal:
+                {
+                    // Note: this cannot be a wait all
+                    WaitingThreadsListNode * pWLNode;
+                    ThreadWaitInfo * ptwiWaitInfo;
+                    DWORD dwObjIndex;
+                    bool fSharedSynchLock = false;
+
+                    // Lock
+                    AcquireLocalSynchLock(pthrWorker);
+                    AcquireSharedSynchLock(pthrWorker);
+                    fSharedSynchLock = true;
+
+                    pWLNode = SharedIDToTypePointer(WaitingThreadsListNode,
+                                                    shridMarshaledData);
+
+                    _ASSERT_MSG(NULL != pWLNode, "Received bad Shared ID %p\n",
+                                shridMarshaledData);
+                    _ASSERT_MSG(gPID == pWLNode->dwProcessId,
+                                "Remote signal apparently sent to the wrong "
+                                "process [target pid=%u current pid=%u]\n",
+                                pWLNode->dwProcessId, gPID);
+                    _ASSERT_MSG(0 == (WTLN_FLAG_WAIT_ALL & pWLNode->dwFlags),
+                                "Wait all with remote awakening delegated "
+                                "through SynchWorkerCmdRemoteSignal rather than "
+                                "SynchWorkerCmdDelegatedObjectSignaling\n");
+
+
+                    // Get the object index
+                    dwObjIndex = pWLNode->dwObjIndex;
+
+                    // Get the WaitInfo
+                    ptwiWaitInfo = pWLNode->ptwiWaitInfo;
+
+                    // Initialize the WakeUpReason to WaitSucceeded
+                    twrWakeUpReason = WaitSucceeded;
+
+                    CSynchData * psdSynchData =
+                        SharedIDToTypePointer(CSynchData,
+                                              pWLNode->ptrOwnerObjSynchData.shrid);
+
+                    TRACE("Synch Worker: received REMOTE SIGNAL cmd "
+                        "[WInfo=%p {Type=%u Domain=%u ObjCount=%d TgtThread=%x} "
+                        "SynchData={shriId=%p p=%p} {SigCount=%d IsAbandoned=%d}\n",
+                        ptwiWaitInfo, ptwiWaitInfo->wtWaitType, ptwiWaitInfo->wdWaitDomain,
+                        ptwiWaitInfo->lObjCount, ptwiWaitInfo->pthrOwner->GetThreadId(),
+                        (VOID *)pWLNode->ptrOwnerObjSynchData.shrid, psdSynchData,
+                        psdSynchData->GetSignalCount(), psdSynchData->IsAbandoned());
+
+                    if (CObjectType::OwnershipTracked ==
+                        psdSynchData->GetObjectType()->GetOwnershipSemantics())
+                    {
+                        // Abandoned status is not propagated through process
+                        // pipe: need to get it from the object itself before
+                        // resetting the data by acquiring the object ownership
+                        if (psdSynchData->IsAbandoned())
+                        {
+                            twrWakeUpReason = MutexAbondoned;
+                        }
+
+                        // Acquire ownership
+                        palErr = psdSynchData->AssignOwnershipToThread(
+                                    pthrWorker,
+                                    ptwiWaitInfo->pthrOwner);
+                        if (NO_ERROR != palErr)
+                        {
+                            ERROR("Synch Worker: AssignOwnershipToThread "
+                                  "failed with error %u; ownership data on "
+                                  "object with SynchData %p may be "
+                                  "corrupted\n", palErr, psdSynchData);
+                        }
+                    }
+
+                    // Unregister the wait
+                    pSynchManager->UnRegisterWait(pthrWorker,
+                                                  ptwiWaitInfo,
+                                                  fSharedSynchLock);
+
+                    // pWLNode is no longer valid after UnRegisterWait
+                    pWLNode = NULL;
+
+                    TRACE("Synch Worker: Waking up local thread %x "
+                          "{WakeUpReason=%u ObjIndex=%u}\n",
+                          ptwiWaitInfo->pthrOwner->GetThreadId(),
+                          twrWakeUpReason, dwObjIndex);
+
+                    // Wake up the target thread
+                    palErr = WakeUpLocalThread(
+                        pthrWorker,
+                        ptwiWaitInfo->pthrOwner,
+                        twrWakeUpReason,
+                        dwObjIndex);
+                    if (NO_ERROR != palErr)
+                    {
+                        ERROR("Synch Worker: Failed to wake up local thread "
+                              "%#x while propagating remote signaling: "
+                              "object signaling may be lost\n",
+                              ptwiWaitInfo->pthrOwner->GetThreadId());
+                    }
+
+                    // Unlock
+                    ReleaseSharedSynchLock(pthrWorker);
+                    fSharedSynchLock = false;
+                    ReleaseLocalSynchLock(pthrWorker);
+
+                    break;
+                }
+                case SynchWorkerCmdDelegatedObjectSignaling:
+                {
+                    CSynchData * psdSynchData;
+
+                    TRACE("Synch Worker: received "
+                          "SynchWorkerCmdDelegatedObjectSignaling\n");
+
+                    psdSynchData = SharedIDToTypePointer(CSynchData,
+                                                       shridMarshaledData);
+
+                    _ASSERT_MSG(NULL != psdSynchData, "Received bad Shared ID %p\n",
+                                shridMarshaledData);
+                    _ASSERT_MSG(0 < dwData && (DWORD)INT_MAX > dwData,
+                                "Received remote signaling with invalid signal "
+                                "count\n");
+
+                    // Lock
+                    AcquireLocalSynchLock(pthrWorker);
+                    AcquireSharedSynchLock(pthrWorker);
+
+                    TRACE("Synch Worker: received DELEGATED OBJECT SIGNALING "
+                        "cmd [SynchData={shriId=%p p=%p} SigCount=%u] [Current obj SigCount=%d "
+                        "IsAbandoned=%d]\n", (VOID *)shridMarshaledData,
+                        psdSynchData, dwData, psdSynchData->GetSignalCount(),
+                        psdSynchData->IsAbandoned());
+
+                    psdSynchData->Signal(pthrWorker,
+                                       psdSynchData->GetSignalCount() + dwData,
+                                       true);
+
+                    // Current SynchData has been AddRef'd by remote process in
+                    // order to be marshaled to the current one, therefore at
+                    // this point we need to release it
+                    psdSynchData->Release(pthrWorker);
+
+                    // Unlock
+                    ReleaseSharedSynchLock(pthrWorker);
+                    ReleaseLocalSynchLock(pthrWorker);
+
+                    break;
+                }
+                case SynchWorkerCmdShutdown:
+                    TRACE("Synch Worker: received SynchWorkerCmdShutdown\n");
+
+                    // Shutdown the process pipe: this will cause the process
+                    // pipe to be unlinked and its write-only file descriptor
+                    // to be closed, so that when the last fd opened for write
+                    // on the fifo (from another process) will be closed, we
+                    // will receive an EOF on the read end (i.e. poll in
+                    // ReadBytesFromProcessPipe will return 1 with no data to
+                    // be read). That will allow the worker thread to process
+                    // possible commands already successfully written to the
+                    // pipe by some other process, before shutting down.
+                    pSynchManager->ShutdownProcessPipe();
+
+                    // Shutting down: this will cause the worker thread to
+                    // fetch residual cmds from the process pipe until an
+                    // EOF is converted to a SynchWorkerCmdNop or the
+                    // WorkerThreadShuttingDownTimeout has elapsed without
+                    // receiving any cmd.
+                    fShuttingDown = true;
+
+                    // Set the timeout to WorkerThreadShuttingDownTimeout
+                    iPollTimeout = WorkerThreadShuttingDownTimeout;
+                    break;
+                default:
+                    ASSERT("Synch Worker: Unknown worker cmd [swcWorkerCmd=%d]\n",
+                           swcCmd);
+                    break;
+            }
+        }
+
+        int iRet;
+        ThreadNativeWaitData * ptnwdWorkerThreadNativeData =
+            &pthrWorker->synchronizationInfo.m_tnwdNativeData;
+
+        // Using the worker thread's predicate/condition/mutex
+        // (that normally are never used) to signal the shutting
+        // down thread that the worker thread is done
+        iRet = pthread_mutex_lock(&ptnwdWorkerThreadNativeData->mutex);
+        _ASSERT_MSG(0 == iRet, "Cannot lock mutex [err=%d]\n", iRet);
+
+        ptnwdWorkerThreadNativeData->iPred = TRUE;
+
+        iRet = pthread_cond_signal(&ptnwdWorkerThreadNativeData->cond);
+        if (0 != iRet)
+        {
+            ERROR ("pthread_cond_signal returned %d [errno=%d (%s)]\n",
+                   iRet, errno, strerror(errno));
+        }
+
+        iRet = pthread_mutex_unlock(&ptnwdWorkerThreadNativeData->mutex);
+        _ASSERT_MSG(0 == iRet, "Cannot lock mutex [err=%d]\n", iRet);
+
+        // Sleep forever
+        ThreadPrepareForShutdown();
+
+        return 0;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::ReadCmdFromProcessPipe
+
+    Reads a worker thread cmd from the process pipe. If there is no data
+    to be read on the pipe, it blocks until there is data available or the
+    timeout expires.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::ReadCmdFromProcessPipe(
+        int iPollTimeout,
+        SynchWorkerCmd * pswcWorkerCmd,
+        SharedID * pshridMarshaledData,
+        DWORD * pdwData)
+    {
+        int iRet;
+        BYTE byVal;
+        SynchWorkerCmd swcWorkerCmd = SynchWorkerCmdNop;
+
+        _ASSERTE(NULL != pswcWorkerCmd);
+        _ASSERTE(NULL != pshridMarshaledData);
+        _ASSERTE(NULL != pdwData);
+
+        iRet = ReadBytesFromProcessPipe(iPollTimeout, &byVal, sizeof(BYTE));
+
+        if (0 > iRet)
+        {
+            ERROR("Failed polling the process pipe [ret=%d errno=%d (%s)]\n",
+                  iRet, errno, strerror(errno));
+
+            return ERROR_INTERNAL_ERROR;
+        }
+
+        if (iRet != 0)
+        {
+            _ASSERT_MSG(sizeof(BYTE) == iRet,
+                        "Got %d bytes from process pipe while expecting for %d\n",
+                        iRet, sizeof(BYTE));
+
+            swcWorkerCmd = (SynchWorkerCmd)byVal;
+
+            if (SynchWorkerCmdLast <= swcWorkerCmd)
+            {
+                ERROR("Got unknown worker command code %d from the process "
+                       "pipe!\n", swcWorkerCmd);
+
+                return ERROR_INTERNAL_ERROR;
+            }
+
+            _ASSERT_MSG(SynchWorkerCmdNop == swcWorkerCmd ||
+                        SynchWorkerCmdRemoteSignal == swcWorkerCmd ||
+                        SynchWorkerCmdDelegatedObjectSignaling == swcWorkerCmd ||
+                        SynchWorkerCmdShutdown == swcWorkerCmd,
+                        "Unknown worker command code %u\n", swcWorkerCmd);
+
+            TRACE("Got cmd %u from process pipe\n", swcWorkerCmd);
+        }
+
+        if (SynchWorkerCmdRemoteSignal == swcWorkerCmd ||
+            SynchWorkerCmdDelegatedObjectSignaling == swcWorkerCmd)
+        {
+            SharedID shridMarshaledId = NULL;
+
+            TRACE("Received %s cmd\n",
+                  (swcWorkerCmd == SynchWorkerCmdRemoteSignal) ?
+                  "REMOTE SIGNAL" : "DELEGATED OBJECT SIGNALING" );
+
+            iRet = ReadBytesFromProcessPipe(WorkerCmdCompletionTimeout,
+                                            (BYTE *)&shridMarshaledId,
+                                            sizeof(shridMarshaledId));
+            if (sizeof(shridMarshaledId) != iRet)
+            {
+                ERROR("Unable to read marshaled Shared ID from the "
+                      "process pipe [pipe=%d ret=%d errno=%d (%s)]\n",
+                      m_iProcessPipeRead, iRet, errno, strerror(errno));
+
+                return ERROR_INTERNAL_ERROR;
+            }
+
+            TRACE("Received marshaled shrid=%p\n", (VOID *)shridMarshaledId);
+
+            *pshridMarshaledData = shridMarshaledId;
+        }
+
+        if (SynchWorkerCmdDelegatedObjectSignaling == swcWorkerCmd)
+        {
+            DWORD dwData;
+
+            iRet = ReadBytesFromProcessPipe(WorkerCmdCompletionTimeout,
+                                            (BYTE *)&dwData,
+                                            sizeof(dwData));
+            if (sizeof(dwData) != iRet)
+            {
+                ERROR("Unable to read signal count from the "
+                      "process pipe [pipe=%d ret=%d errno=%d (%s)]\n",
+                      m_iProcessPipeRead, iRet, errno, strerror(errno));
+
+                return ERROR_INTERNAL_ERROR;
+            }
+
+            TRACE("Received signal count %u\n", dwData);
+
+            *pdwData = dwData;
+        }
+
+        *pswcWorkerCmd = swcWorkerCmd;
+        return NO_ERROR;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::ReadBytesFromProcessPipe
+
+    Reads the specified number of bytes from the process pipe. If there is
+    no data to be read on the pipe, it blocks until there is data available
+    or the timeout expires.
+    --*/
+    int CPalSynchronizationManager::ReadBytesFromProcessPipe(
+        int iTimeout,
+        BYTE * pRecvBuf,
+        LONG iBytes)
+    {
+#if !HAVE_KQUEUE
+        struct pollfd Poll;
+#endif // !HAVE_KQUEUE
+        int iRet = -1;
+        int iConsecutiveEintrs = 0;
+        LONG iBytesRead = 0;
+        BYTE * pPos = pRecvBuf;
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+        struct kevent keChanges;
+        struct timespec ts, *pts;
+        int iNChanges;
+#endif // HAVE_KQUEUE
+
+        _ASSERTE(0 <= iBytes);
+
+        do
+        {
+            while (TRUE)
+            {
+                int iErrno = 0;
+#if HAVE_KQUEUE
+#if HAVE_BROKEN_FIFO_KEVENT
+#if HAVE_BROKEN_FIFO_SELECT
+#error Found no way to wait on a FIFO.
+#endif
+
+                timeval *ptv;
+                timeval tv;
+
+                if (INFTIM == iTimeout)
+                {
+                    ptv = NULL;
+                }
+                else
+                {
+                    tv.tv_usec = (iTimeout % tccSecondsToMillieSeconds) *
+                        tccMillieSecondsToMicroSeconds;
+                    tv.tv_sec = iTimeout / tccSecondsToMillieSeconds;
+                    ptv = &tv;
+                }
+
+                fd_set readfds;
+                FD_ZERO(&readfds);
+                FD_SET(m_iProcessPipeRead, &readfds);
+                iRet = select(m_iProcessPipeRead + 1, &readfds, NULL, NULL, ptv);
+
+#else // HAVE_BROKEN_FIFO_KEVENT
+
+                // Note: FreeBSD needs to use kqueue/kevent support here, since on this
+                // platform the EOF notification on FIFOs is not surfaced through poll,
+                // and process pipe shutdown relies on this feature.
+                // If a thread is polling a FIFO or a pipe for POLLIN, when the last
+                // write descriptor for that pipe is closed, poll() is supposed to
+                // return with a POLLIN event but no data to be read on the FIFO/pipe,
+                // which means EOF.
+                // On FreeBSD such feature works for pipes but it doesn't for FIFOs.
+                // Using kevent the EOF is instead surfaced correctly.
+
+                if (iBytes > m_keProcessPipeEvent.data)
+                {
+                    if (INFTIM == iTimeout)
+                    {
+                        pts = NULL;
+                    }
+                    else
+                    {
+                        ts.tv_nsec = (iTimeout % tccSecondsToMillieSeconds) *
+                            tccMillieSecondsToNanoSeconds;
+                        ts.tv_sec = iTimeout / tccSecondsToMillieSeconds;
+                        pts = &ts;
+                    }
+
+                    if (0 != (EV_EOF & m_keProcessPipeEvent.flags))
+                    {
+                        TRACE("Refreshing kevent settings\n");
+                        EV_SET(&keChanges, m_iProcessPipeRead, EVFILT_READ,
+                               EV_ADD | EV_CLEAR, 0, 0, 0);
+                        iNChanges = 1;
+                    }
+                    else
+                    {
+                        iNChanges = 0;
+                    }
+
+                    iRet = kevent(m_iKQueue, &keChanges, iNChanges,
+                                  &m_keProcessPipeEvent, 1, pts);
+
+                    if (0 < iRet)
+                    {
+                        _ASSERTE(1 == iRet);
+                        _ASSERTE(EVFILT_READ == m_keProcessPipeEvent.filter);
+
+                        if (EV_ERROR & m_keProcessPipeEvent.flags)
+                        {
+                            ERROR("EV_ERROR from kevent [ident=%d filter=%d flags=%x]\n", m_keProcessPipeEvent.ident, m_keProcessPipeEvent.filter, m_keProcessPipeEvent.flags);
+                            iRet = -1;
+                            iErrno = m_keProcessPipeEvent.data;
+                            m_keProcessPipeEvent.data = 0;
+                        }
+                    }
+                    else if (0 > iRet)
+                    {
+                        iErrno = errno;
+                    }
+
+                    TRACE("Woken up from kevent() with ret=%d flags=%#x data=%d "
+                          "[iTimeout=%d]\n", iRet, m_keProcessPipeEvent.flags,
+                          m_keProcessPipeEvent.data, iTimeout);
+                }
+                else
+                {
+                    // There is enough data already available in the buffer, just use that.
+                    iRet = 1;
+                }
+
+#endif // HAVE_BROKEN_FIFO_KEVENT
+#else // HAVE_KQUEUE
+
+                Poll.fd = m_iProcessPipeRead;
+                Poll.events = POLLIN;
+                Poll.revents = 0;
+
+                iRet = poll(&Poll, 1, iTimeout);
+
+                TRACE("Woken up from poll() with ret=%d [iTimeout=%d]\n",
+                       iRet, iTimeout);
+
+                if (1 == iRet &&
+                    ((POLLERR | POLLHUP | POLLNVAL) & Poll.revents))
+                {
+                    // During PAL shutdown the pipe gets closed and Poll.revents is set to POLLHUP
+                    // (note: no other flags are set). We will also receive an EOF on from the read call.
+                    // Please see the comment for SynchWorkerCmdShutdown in CPalSynchronizationManager::WorkerThread.
+                    if (!PALIsShuttingDown() || (Poll.revents != POLLHUP))
+                    {
+                        ERROR("Unexpected revents=%x while polling pipe %d\n",
+                            Poll.revents, Poll.fd);
+                        iErrno = EINVAL;
+                        iRet = -1;
+                    }
+                }
+                else if (0 > iRet)
+                {
+                    iErrno = errno;
+                }
+
+#endif // HAVE_KQUEUE
+
+                if (0 == iRet || 1 == iRet)
+                {
+                    // 0 == wait timed out
+                    // 1 == FIFO has data available
+                    break;
+                }
+                else
+                {
+                    if (1 < iRet)
+                    {
+                        // Unexpected iRet > 1
+                        ASSERT("Unexpected return code %d from blocking poll/kevent call\n",
+                                iRet);
+                        goto RBFPP_exit;
+                    }
+
+                    if (EINTR != iErrno)
+                    {
+                        // Unexpected error
+                        ASSERT("Unexpected error from blocking poll/kevent call: %d (%s)\n",
+                               iErrno, strerror(iErrno));
+                        goto RBFPP_exit;
+                    }
+
+                    iConsecutiveEintrs++;
+                    TRACE("poll() failed with EINTR; re-polling\n");
+
+                    if (iConsecutiveEintrs >= MaxWorkerConsecutiveEintrs)
+                    {
+                        if (iTimeout != INFTIM)
+                        {
+                            WARN("Receiving too many EINTRs; converting one of them "
+                                 "to a timeout");
+                            iRet = 0;
+                            break;
+                        }
+                        else if (0 == (iConsecutiveEintrs % MaxWorkerConsecutiveEintrs))
+                        {
+                            WARN("Receiving too many EINTRs [%d so far]",
+                                 iConsecutiveEintrs);
+                        }
+                    }
+                }
+            }
+
+            if (0 == iRet)
+            {
+                // Time out
+                break;
+            }
+            else
+            {
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+                if (0 != (EV_EOF & m_keProcessPipeEvent.flags) && 0 == m_keProcessPipeEvent.data)
+                {
+                    // EOF
+                    TRACE("Received an EOF on process pipe via kevent\n");
+                    goto RBFPP_exit;
+                }
+#endif // HAVE_KQUEUE
+
+                iRet = read(m_iProcessPipeRead, pPos, iBytes - iBytesRead);
+
+                if (0 == iRet)
+                {
+                    // Poll returned 1 and read returned zero: this is an EOF,
+                    // i.e. no other process has the pipe still open for write
+                    TRACE("Received an EOF on process pipe via poll\n");
+                    goto RBFPP_exit;
+                }
+                else if (0 > iRet)
+                {
+                    ERROR("Unable to read %d bytes from the the process pipe "
+                          "[pipe=%d ret=%d errno=%d (%s)]\n", iBytes - iBytesRead,
+                          m_iProcessPipeRead, iRet, errno, strerror(errno));
+                    goto RBFPP_exit;
+                }
+
+                TRACE("Read %d bytes from process pipe\n", iRet);
+
+                iBytesRead += iRet;
+                pPos += iRet;
+
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+                // Update available data count
+                m_keProcessPipeEvent.data -= iRet;
+                _ASSERTE(0 <= m_keProcessPipeEvent.data);
+#endif // HAVE_KQUEUE
+            }
+        } while(iBytesRead < iBytes);
+
+    RBFPP_exit:
+        return (iRet < 0) ? iRet : iBytesRead;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::WakeUpLocalThread
+
+    Wakes up a local thead currently sleeping for a wait or a sleep
+    --*/
+    PAL_ERROR CPalSynchronizationManager::WakeUpLocalThread(
+        CPalThread * pthrCurrent,
+        CPalThread * pthrTarget,
+        ThreadWakeupReason twrWakeupReason,
+        DWORD dwObjectIndex)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        ThreadNativeWaitData * ptnwdNativeWaitData =
+            pthrTarget->synchronizationInfo.GetNativeData();
+
+        TRACE("Waking up a local thread [WakeUpReason=%u ObjectIndex=%u "
+              "ptnwdNativeWaitData=%p]\n", twrWakeupReason, dwObjectIndex,
+              ptnwdNativeWaitData);
+
+        // Set wakeup reason and signaled object index
+        ptnwdNativeWaitData->twrWakeupReason = twrWakeupReason;
+        ptnwdNativeWaitData->dwObjectIndex   = dwObjectIndex;
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        if (0 < GetLocalSynchLockCount(pthrCurrent))
+        {
+            // Defer the actual thread signaling to right after
+            // releasing the synch lock(s), so that signaling
+            // can happen from a thread-suspension safe area
+            palErr = DeferThreadConditionSignaling(pthrCurrent, pthrTarget);
+        }
+        else
+        {
+            // Signal the target thread's condition
+            palErr = SignalThreadCondition(ptnwdNativeWaitData);
+        }
+#else // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        // Signal the target thread's condition
+        palErr = SignalThreadCondition(ptnwdNativeWaitData);
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+        return palErr;
+    }
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+    /*++
+    Method:
+      CPalSynchronizationManager::DeferThreadConditionSignaling
+
+    Defers thread signaling to the final release of synchronization
+    lock(s), so that condition signaling can happen when the signaling
+    thread is marked as safe for thread suspension.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::DeferThreadConditionSignaling(
+        CPalThread * pthrCurrent,
+        CPalThread * pthrTarget)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        LONG lCount = pthrCurrent->synchronizationInfo.m_lPendingSignalingCount;
+
+        _ASSERTE(pthrTarget != pthrCurrent);
+
+        if (CThreadSynchronizationInfo::PendingSignalingsArraySize > lCount)
+        {
+            // If there is available room, add the target thread object to
+            // the array of pending thread signalings.
+            pthrCurrent->synchronizationInfo.m_rgpthrPendingSignalings[lCount] = pthrTarget;
+        }
+        else
+        {
+            // If the array is full, add the target thread object at the end
+            // of the overflow list
+            DeferredSignalingListNode * pdsln =
+                InternalNew<DeferredSignalingListNode>();
+
+            if (pdsln)
+            {
+                pdsln->pthrTarget = pthrTarget;
+
+                // Add the note to the end of the list.
+                // Note: no need to synchronize the access to this list since
+                // it is meant to be accessed only by the owner thread.
+                InsertTailList(&pthrCurrent->synchronizationInfo.m_lePendingSignalingsOverflowList,
+                               &pdsln->Link);
+            }
+            else
+            {
+                palErr = ERROR_NOT_ENOUGH_MEMORY;
+            }
+        }
+
+        if (NO_ERROR == palErr)
+        {
+            // Increment the count of pending signalings
+            pthrCurrent->synchronizationInfo.m_lPendingSignalingCount += 1;
+
+            // Add a reference to the target CPalThread object; this is
+            // needed since deferring signaling after releasing the synch
+            // locks implies accessing the target thread object without
+            // holding the local synch lock. In rare circumstances, the
+            // target thread may have already exited while deferred signaling
+            // takes place, therefore invalidating the thread object. The
+            // reference added here ensures that the thread object is still
+            // good, even if the target thread has exited.
+            pthrTarget->AddThreadReference();
+        }
+
+        return palErr;
+    }
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+    /*++
+    Method:
+      CPalSynchronizationManager::SignalThreadCondition
+
+    Performs the actual condition signaling in to wake up the target thread
+    --*/
+    PAL_ERROR CPalSynchronizationManager::SignalThreadCondition(
+        ThreadNativeWaitData * ptnwdNativeWaitData)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        int iRet;
+
+        // Lock the mutex
+        iRet = pthread_mutex_lock(&ptnwdNativeWaitData->mutex);
+        if (0 != iRet)
+        {
+            ERROR("Cannot lock mutex [err=%d]\n", iRet);
+            return ERROR_INTERNAL_ERROR;
+        }
+
+        // Set the predicate
+        ptnwdNativeWaitData->iPred = TRUE;
+
+        // Signal the condition
+        iRet = pthread_cond_signal(&ptnwdNativeWaitData->cond);
+        if (0 != iRet)
+        {
+            ERROR("Failed to signal condition: pthread_cond_signal "
+                  "returned %d [errno=%d (%s)]\n", iRet, errno,
+                  strerror(errno));
+            palErr = ERROR_INTERNAL_ERROR;
+            // Continue in order to unlock the mutex anyway
+        }
+
+        // Unlock the mutex
+        iRet = pthread_mutex_unlock(&ptnwdNativeWaitData->mutex);
+        if (0 != iRet)
+        {
+            ERROR("Cannot unlock mutex [err=%d]\n", iRet);
+            return ERROR_INTERNAL_ERROR;
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::ReadBytesFromProcessPipe
+
+    Wakes up a remote thead currently sleeping for a wait or a sleep
+    by sending the appropriate cmd to the remote process' worker
+    thread, which will take care to convert this command into a
+    WakeUpLocalThread in the remote process
+    --*/
+    PAL_ERROR CPalSynchronizationManager::WakeUpRemoteThread(
+        SharedID shridWLNode)
+    {
+        const int MsgSize = sizeof(BYTE) + sizeof(SharedID);
+        PAL_ERROR palErr = NO_ERROR;
+        BYTE rgSendBuf[MsgSize];
+        BYTE * pbySrc, * pbyDst = rgSendBuf;
+        WaitingThreadsListNode * pWLNode = SharedIDToTypePointer(WaitingThreadsListNode, shridWLNode);
+
+
+        _ASSERT_MSG(NULL != pWLNode, "Bad shared wait list node identifier (%p)\n", (VOID*)shridWLNode);
+        _ASSERT_MSG(gPID != pWLNode->dwProcessId, "WakeUpRemoteThread called on local thread\n");
+        _ASSERT_MSG(NULL != shridWLNode, "NULL shared identifier\n");
+        _ASSERT_MSG(MsgSize <= PIPE_BUF, "Message too long [MsgSize=%d PIPE_BUF=%d]\n", MsgSize, (int)PIPE_BUF);
+
+        TRACE("Waking up remote thread {pid=%x, tid=%x} by sending cmd=%u and shridWLNode=%p over process pipe\n",
+              pWLNode->dwProcessId, pWLNode->dwThreadId, SynchWorkerCmdRemoteSignal, (VOID *)shridWLNode);
+
+        // Prepare the message
+        // Cmd
+        *pbyDst++ = (BYTE)(SynchWorkerCmdRemoteSignal & 0xFF);
+
+        // WaitingThreadsListNode (not aligned, copy byte by byte)
+        pbySrc = (BYTE *)&shridWLNode;
+        for (int i = 0; i < (int)sizeof(SharedID); i++)
+        {
+            *pbyDst++ = *pbySrc++;
+        }
+
+        _ASSERT_MSG(pbyDst <= rgSendBuf + MsgSize + 1, "Buffer overrun");
+
+        // Send the message
+        palErr = SendMsgToRemoteWorker(pWLNode->dwProcessId, rgSendBuf, MsgSize);
+        if (NO_ERROR != palErr)
+        {
+            ERROR("Failed sending message to remote worker in process %u\n", pWLNode->dwProcessId);
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::DelegateSignalingToRemoteProcess
+
+    This method transfers an object signaling operation to a remote process,
+    where it will be performed by the worker thread. Such delegation takes
+    place when the currently processed thread (among those waiting on the
+    signald object) lives in a different process as the signaling thread,
+    and it is performing a wait all. In this case generally is not possible
+    to find out whether or not the wait all is satisfied, therefore the
+    signaling operation must be continued in the target process.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::DelegateSignalingToRemoteProcess(
+        CPalThread * pthrCurrent,
+        DWORD dwTargetProcessId,
+        SharedID shridSynchData)
+    {
+        const int MsgSize = sizeof(BYTE) + sizeof(SharedID) + sizeof(DWORD);
+        int i;
+        PAL_ERROR palErr = NO_ERROR;
+        BYTE rgSendBuf[MsgSize];
+        BYTE * pbySrc, * pbyDst = rgSendBuf;
+        DWORD dwSigCount;
+        CSynchData * psdSynchData =
+            SharedIDToTypePointer(CSynchData, shridSynchData);
+
+        _ASSERT_MSG(gPID != dwTargetProcessId, " called on local thread\n");
+        _ASSERT_MSG(NULL != shridSynchData, "NULL shared identifier\n");
+        _ASSERT_MSG(NULL != psdSynchData, "Bad shared SynchData identifier (%p)\n", (VOID*)shridSynchData);
+        _ASSERT_MSG(MsgSize <= PIPE_BUF, "Message too long [MsgSize=%d PIPE_BUF=%d]\n", MsgSize, (int)PIPE_BUF);
+
+        TRACE("Transfering wait all signaling to remote process pid=%x by sending cmd=%u and shridSynchData=%p over process pipe\n",
+              dwTargetProcessId, SynchWorkerCmdDelegatedObjectSignaling, (VOID *)shridSynchData);
+
+        dwSigCount = psdSynchData->GetSignalCount();
+
+        // AddRef SynchData to be marshaled to remote process
+        psdSynchData->AddRef();
+
+        //
+        // Prepare the message
+        //
+
+        // Cmd
+        *pbyDst++ = (BYTE)(SynchWorkerCmdDelegatedObjectSignaling & 0xFF);
+
+        // CSynchData (not aligned, copy byte by byte)
+        pbySrc = (BYTE *)&shridSynchData;
+        for (i=0; i<(int)sizeof(SharedID); i++)
+        {
+            *pbyDst++ = *pbySrc++;
+        }
+
+        // Signal Count (not aligned, copy byte by byte)
+        pbySrc = (BYTE *)&dwSigCount;
+        for (i=0; i<(int)sizeof(DWORD); i++)
+        {
+            *pbyDst++ = *pbySrc++;
+        }
+
+        _ASSERT_MSG(pbyDst <= rgSendBuf + MsgSize + 1, "Buffer overrun");
+
+        // Send the message
+        palErr = SendMsgToRemoteWorker(dwTargetProcessId, rgSendBuf, MsgSize);
+        if (NO_ERROR != palErr)
+        {
+            TRACE("Failed sending message to remote worker in process %u\n", dwTargetProcessId);
+
+            // Undo refcounting
+            psdSynchData->Release(pthrCurrent);
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::SendMsgToRemoteWorker
+
+    Sends a message (command + data) to a remote process's worker thread.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::SendMsgToRemoteWorker(
+        DWORD dwProcessId,
+        BYTE * pMsg,
+        int iMsgSize)
+    {
+#ifndef CORECLR
+        PAL_ERROR palErr = NO_ERROR;
+        int iProcessPipe, iBytesToWrite, iRetryCount;
+        ssize_t sszRet;
+        char strPipeFilename[MAX_PATH];
+        BYTE * pPos = pMsg;
+        bool fRet;
+        CPalThread *pthrCurrent = InternalGetCurrentThread();
+
+        _ASSERT_MSG(gPID != dwProcessId, "SendMsgToRemoteWorker called with local process as target process\n");
+
+        fRet = GetProcessPipeName(strPipeFilename, MAX_PATH, dwProcessId);
+
+        _ASSERT_MSG(fRet, "Failed to retrieve process pipe's name!\n");
+
+        iProcessPipe = InternalOpen(strPipeFilename, O_WRONLY);
+        if (-1 == iProcessPipe)
+        {
+            ERROR("Unable to open a process pipe to wake up a remote thread "
+                  "[pid=%u errno=%d (%s) PipeFilename=%s]\n", dwProcessId,
+                  errno, strerror(errno), strPipeFilename);
+            palErr = ERROR_INTERNAL_ERROR;
+            goto SMTRW_exit;
+        }
+
+        pPos = pMsg;
+        iBytesToWrite = iMsgSize;
+        while (0 < iBytesToWrite)
+        {
+            iRetryCount = 0;
+            do
+            {
+                sszRet = write(iProcessPipe, pPos, iBytesToWrite);
+            } while (-1 == sszRet &&
+                     EAGAIN == errno &&
+                     ++iRetryCount < MaxConsecutiveEagains &&
+                     0 == sched_yield());
+
+            if (0 >= sszRet)
+            {
+                ERROR("Error writing message to process pipe %d [target_pid=%u "
+                      "bytes_to_write=%d bytes_written=%d ret=%d errno=%d (%s) "
+                      "PipeFilename=%s]\n", iProcessPipe, dwProcessId, iMsgSize,
+                      iMsgSize - iBytesToWrite, (int)sszRet, errno, strerror(errno),
+                      strPipeFilename);
+                palErr = ERROR_INTERNAL_ERROR;
+                break;
+            }
+            iBytesToWrite -= (int)sszRet;
+            pPos += sszRet;
+
+            _ASSERT_MSG(0 == iBytesToWrite,
+                        "Interleaved messages while writing to process pipe %d\n",
+                        iProcessPipe);
+        }
+
+        // Close the opened pipe
+        close(iProcessPipe);
+
+    SMTRW_exit:
+        return palErr;
+#else // !CORECLR
+        ASSERT("There should never be a reason to send a message to a remote worker\n");
+        return ERROR_INTERNAL_ERROR;
+#endif // !CORECLR
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::WakeUpLocalWorkerThread
+
+    Wakes up the local worker thread by writing a 'nop' cmd to the
+    process pipe.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::WakeUpLocalWorkerThread(
+        SynchWorkerCmd swcWorkerCmd)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+
+        _ASSERT_MSG((swcWorkerCmd & 0xFF) == swcWorkerCmd,
+                    "Value too big for swcWorkerCmd\n");
+
+        _ASSERT_MSG((SynchWorkerCmdNop == swcWorkerCmd) ||
+                    (SynchWorkerCmdShutdown == swcWorkerCmd),
+                    "WakeUpLocalWorkerThread supports only SynchWorkerCmdNop, and SynchWorkerCmdShutdown."
+                    "[received cmd=%d]\n", swcWorkerCmd);
+
+        BYTE byCmd = (BYTE)(swcWorkerCmd & 0xFF);
+
+        TRACE("Waking up Synch Worker Thread for %u [byCmd=%u]\n",
+                    swcWorkerCmd, (unsigned int)byCmd);
+
+        // As long as we use pipes and we keep the message size
+        // within PIPE_BUF, there's no need to lock here, since the
+        // write is guaranteed not to be interleaved with/into other
+        // writes of PIPE_BUF bytes or less.
+        _ASSERT_MSG(sizeof(BYTE) <= PIPE_BUF, "Message too long\n");
+
+        int iRetryCount = 0;
+        ssize_t sszWritten;
+        do
+        {
+            sszWritten = write(m_iProcessPipeWrite, &byCmd, sizeof(BYTE));
+        } while (-1 == sszWritten &&
+                 EAGAIN == errno &&
+                 ++iRetryCount < MaxConsecutiveEagains &&
+                 0 == sched_yield());
+
+        if (sszWritten != sizeof(BYTE))
+        {
+            ERROR("Unable to write to the process pipe to wake up the "
+                   "worker thread [errno=%d (%s)]\n", errno, strerror(errno));
+            palErr = ERROR_INTERNAL_ERROR;
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::GetThreadWaitInfo
+
+    Returns a pointer to the WaitInfo structure for the passed CPalThread object
+    --*/
+    ThreadWaitInfo * CPalSynchronizationManager::GetThreadWaitInfo(
+        CPalThread * pthrCurrent)
+    {
+        return &pthrCurrent->synchronizationInfo.m_twiWaitInfo;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::UnRegisterWait
+
+    Unregister the wait described by ptwiWaitInfo that in general involves
+    a thread other than the current one (most of the times the deregistration
+    is performed by the signaling thread)
+
+    Note: this method must be called while holding the local process
+          synchronization lock.
+    --*/
+    void CPalSynchronizationManager::UnRegisterWait(
+        CPalThread * pthrCurrent,
+        ThreadWaitInfo * ptwiWaitInfo,
+        bool fHaveSharedLock)
+    {
+        int i = 0;
+        CSynchData * psdSynchData = NULL;
+        bool fSharedSynchLock = false;
+
+        if (!fHaveSharedLock && LocalWait != ptwiWaitInfo->wdWaitDomain)
+        {
+            AcquireSharedSynchLock(pthrCurrent);
+            fSharedSynchLock = true;
+        }
+
+        TRACE("Unregistering wait for thread=%u [ObjCount=%d WaitType=%u WaitDomain=%u]\n",
+              ptwiWaitInfo->pthrOwner->GetThreadId(),
+              ptwiWaitInfo->lObjCount, ptwiWaitInfo->wtWaitType,
+              ptwiWaitInfo->wdWaitDomain);
+
+        for (i=0; i < ptwiWaitInfo->lObjCount; i++)
+        {
+            WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i];
+
+            VALIDATEOBJECT(pwtlnItem);
+
+            if (pwtlnItem->dwFlags & WTLN_FLAG_OWNER_OBJECT_IS_SHARED)
+            {
+                // Shared object
+                WaitingThreadsListNode * pwtlnItemNext, * pwtlnItemPrev;
+
+                psdSynchData = SharedIDToTypePointer(CSynchData,
+                    pwtlnItem->ptrOwnerObjSynchData.shrid);
+
+                VALIDATEOBJECT(psdSynchData);
+
+                pwtlnItemNext = SharedIDToTypePointer(WaitingThreadsListNode,
+                    pwtlnItem->ptrNext.shrid);
+                pwtlnItemPrev = SharedIDToTypePointer(WaitingThreadsListNode,
+                    pwtlnItem->ptrPrev.shrid);
+                if (pwtlnItemPrev)
+                {
+                    VALIDATEOBJECT(pwtlnItemPrev);
+                    pwtlnItemPrev->ptrNext.shrid = pwtlnItem->ptrNext.shrid;
+                }
+                else
+                {
+                    psdSynchData->SetWTLHeadShrPtr(pwtlnItem->ptrNext.shrid);
+                }
+
+                if (pwtlnItemNext)
+                {
+                    VALIDATEOBJECT(pwtlnItemNext);
+                    pwtlnItemNext->ptrPrev.shrid = pwtlnItem->ptrPrev.shrid;
+                }
+                else
+                {
+                    psdSynchData->SetWTLTailShrPtr(pwtlnItem->ptrPrev.shrid);
+                }
+
+                m_cacheSHRWTListNodes.Add(pthrCurrent, pwtlnItem->shridSHRThis);
+            }
+            else
+            {
+                // Local object
+                psdSynchData = pwtlnItem->ptrOwnerObjSynchData.ptr;
+
+                VALIDATEOBJECT(psdSynchData);
+
+                if (pwtlnItem->ptrPrev.ptr)
+                {
+                    VALIDATEOBJECT(pwtlnItem);
+                    pwtlnItem->ptrPrev.ptr->ptrNext.ptr = pwtlnItem->ptrNext.ptr;
+                }
+                else
+                {
+                    psdSynchData->SetWTLHeadPtr(pwtlnItem->ptrNext.ptr);
+                }
+
+                if (pwtlnItem->ptrNext.ptr)
+                {
+                    VALIDATEOBJECT(pwtlnItem);
+                    pwtlnItem->ptrNext.ptr->ptrPrev.ptr = pwtlnItem->ptrPrev.ptr;
+                }
+                else
+                {
+                    psdSynchData->SetWTLTailPtr(pwtlnItem->ptrPrev.ptr);
+                }
+
+                m_cacheWTListNodes.Add(pthrCurrent, pwtlnItem);
+            }
+
+            // Release the node's refcount on the synch data, and decerement
+            // waiting thread count
+            psdSynchData->DecrementWaitingThreadCount();
+            psdSynchData->Release(pthrCurrent);
+        }
+
+        // Reset wait data in ThreadWaitInfo structure: it is enough
+        // to reset lObjCount, lSharedObjCount and wdWaitDomain.
+        ptwiWaitInfo->lObjCount       = 0;
+        ptwiWaitInfo->lSharedObjCount = 0;
+        ptwiWaitInfo->wdWaitDomain    = LocalWait;
+
+        // Done
+        if (fSharedSynchLock)
+        {
+            ReleaseSharedSynchLock(pthrCurrent);
+        }
+
+        return;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll
+
+    Unsignals all the objects involved in a wait all, except the target
+    one (i.e. psdTgtObjectSynchData)
+
+    Note: this method must be called while holding the synchronization locks
+          appropriate to all the objects involved in the wait-all. If any
+          of the objects is shared, the caller must own both local and
+          shared synch locks; if no shared object is involved in the wait,
+          only the local synch lock is needed.
+    --*/
+    void CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll(
+        CPalThread * pthrCurrent,
+        CPalThread * pthrTarget,
+        WaitingThreadsListNode * pwtlnNode,
+        CSynchData * psdTgtObjectSynchData)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        CSynchData * psdSynchDataItem = NULL;
+
+#ifdef _DEBUG
+        bool bOriginatingNodeFound = false;
+#endif
+
+        VALIDATEOBJECT(psdTgtObjectSynchData);
+        VALIDATEOBJECT(pwtlnNode);
+
+        _ASSERT_MSG(0 != (WTLN_FLAG_WAIT_ALL & pwtlnNode->dwFlags),
+            "UnsignalRestOfLocalAwakeningWaitAll() called on a normal (non wait all) wait");
+
+        _ASSERT_MSG(gPID == pwtlnNode->dwProcessId,
+            "UnsignalRestOfLocalAwakeningWaitAll() called on a wait all with remote awakening");
+
+        ThreadWaitInfo *ptwiWaitInfo = pwtlnNode->ptwiWaitInfo;
+
+        int iObjCount = ptwiWaitInfo->lObjCount;
+        for (int i = 0; i < iObjCount; i++)
+        {
+            WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i];
+
+            VALIDATEOBJECT(pwtlnItem);
+
+            if (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnItem->dwFlags))
+            {
+                psdSynchDataItem = SharedIDToTypePointer(CSynchData, pwtlnItem->ptrOwnerObjSynchData.shrid);
+            }
+            else
+            {
+                psdSynchDataItem = pwtlnItem->ptrOwnerObjSynchData.ptr;
+            }
+
+            VALIDATEOBJECT(psdSynchDataItem);
+
+            // Skip originating node
+            if (psdTgtObjectSynchData == psdSynchDataItem)
+            {
+#ifdef _DEBUG
+                bOriginatingNodeFound = true;
+#endif
+                continue;
+            }
+
+            palErr = psdSynchDataItem->ReleaseWaiterWithoutBlocking(pthrCurrent, pthrTarget);
+            if (NO_ERROR != palErr)
+            {
+                ERROR("ReleaseWaiterWithoutBlocking failed on SynchData @ %p [palErr = %u]\n", psdSynchDataItem, palErr);
+            }
+        }
+
+        _ASSERT_MSG(bOriginatingNodeFound, "Couldn't find originating node while unsignaling rest of the wait all\n");
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::MarkWaitForDelegatedObjectSignalingInProgress
+
+    Marks all the thread waiting list nodes involved in the the current wait-all
+    for "delegated object signaling in progress", so that this wait cannot be
+    involved in another delegated object signaling that may happen while the
+    current object singaling is being tranfered to the target process (while
+    transfering it, synchronization locks are released in this process and later
+    grabbed again in the target process; in this time window another thread
+    could signal another object part of the same wait-all. In this case no
+    signal delegation must take place.
+
+    Note: this method must be called while holding the synchronization locks
+          appropriate to the target object described by pwtlnNode (i.e. the
+          local process synch lock if the target object is local, both local
+          and shared one if the object is shared).
+    --*/
+    void CPalSynchronizationManager::MarkWaitForDelegatedObjectSignalingInProgress(
+        CPalThread * pthrCurrent,
+        WaitingThreadsListNode * pwtlnNode)
+    {
+        bool fSharedSynchLock = false;
+        bool fTargetObjectIsShared = (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNode->dwFlags));
+
+        VALIDATEOBJECT(pwtlnNode);
+
+        _ASSERT_MSG(gPID == pwtlnNode->dwProcessId,
+            "MarkWaitForDelegatedObjectSignalingInProgress() called from the wrong process");
+
+        ThreadWaitInfo *ptwiWaitInfo = pwtlnNode->ptwiWaitInfo;
+
+        if (!fSharedSynchLock && !fTargetObjectIsShared &&
+            LocalWait != ptwiWaitInfo->wdWaitDomain)
+        {
+            AcquireSharedSynchLock(pthrCurrent);
+            fSharedSynchLock = true;
+        }
+
+        _ASSERT_MSG(MultipleObjectsWaitAll == ptwiWaitInfo->wtWaitType,
+            "MarkWaitForDelegatedObjectSignalingInProgress() called on a normal (non wait-all) wait");
+
+        // Unmark all nodes other than the target one
+        int iTgtCount = ptwiWaitInfo->lObjCount;
+        for (int i = 0; i < iTgtCount; i++)
+        {
+            VALIDATEOBJECT(ptwiWaitInfo->rgpWTLNodes[i]);
+            ptwiWaitInfo->rgpWTLNodes[i]->dwFlags &= ~WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS;
+        }
+
+        // Mark the target node
+        pwtlnNode->dwFlags |= WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS;
+
+        // Done
+        if (fSharedSynchLock)
+        {
+            ReleaseSharedSynchLock(pthrCurrent);
+        }
+
+        return;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::UnmarkTWListForDelegatedObjectSignalingInProgress
+
+    Resets the "delegated object signaling in progress" flags in all the
+    nodes of the thread waitin list for the target waitable objects (represented
+    by its SynchData)
+
+    Note: this method must be called while holding the appropriate
+          synchronization locks (the local process synch lock if the target
+          object is local, both local and shared one if the object is shared).
+    --*/
+    void CPalSynchronizationManager::UnmarkTWListForDelegatedObjectSignalingInProgress(
+        CSynchData * pTgtObjectSynchData)
+    {
+        bool fSharedObject = (SharedObject == pTgtObjectSynchData->GetObjectDomain());
+        WaitingThreadsListNode * pwtlnNode;
+
+        VALIDATEOBJECT(pTgtObjectSynchData);
+
+        pwtlnNode =  fSharedObject ? SharedIDToTypePointer(WaitingThreadsListNode, pTgtObjectSynchData->GetWTLHeadShmPtr())
+                                   : pTgtObjectSynchData->GetWTLHeadPtr();
+
+        while (pwtlnNode)
+        {
+            VALIDATEOBJECT(pwtlnNode);
+
+            pwtlnNode->dwFlags &= ~WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS;
+            pwtlnNode = fSharedObject ? SharedIDToTypePointer(WaitingThreadsListNode, pwtlnNode->ptrNext.shrid)
+                                      : pwtlnNode->ptrNext.ptr;
+        }
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::RegisterProcessForMonitoring
+
+    Registers the process object represented by the passed psdSynchData and
+    pProcLocalData. The worker thread will monitor the actual process and,
+    upon process termination, it will set the exit code in pProcLocalData,
+    and it will signal the process object, by signaling its psdSynchData.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::RegisterProcessForMonitoring(
+        CPalThread * pthrCurrent,
+        CSynchData *psdSynchData,
+        IPalObject *pProcessObject,
+        CProcProcessLocalData * pProcLocalData)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        MonitoredProcessesListNode * pmpln;
+        bool fWakeUpWorker = false;
+        bool fMonitoredProcessesLock = false;
+
+        VALIDATEOBJECT(psdSynchData);
+
+        InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+
+        fMonitoredProcessesLock = true;
+
+        pmpln = m_pmplnMonitoredProcesses;
+        while (pmpln)
+        {
+            if (psdSynchData == pmpln->psdSynchData)
+            {
+                _ASSERT_MSG(pmpln->dwPid == pProcLocalData->dwProcessId, "Invalid node in Monitored Processes List\n");
+                break;
+            }
+
+            pmpln = pmpln->pNext;
+        }
+
+        if (pmpln)
+        {
+            pmpln->lRefCount++;
+        }
+        else
+        {
+            pmpln = InternalNew<MonitoredProcessesListNode>();
+            if (NULL == pmpln)
+            {
+                ERROR("No memory to allocate MonitoredProcessesListNode structure\n");
+                palErr = ERROR_NOT_ENOUGH_MEMORY;
+                goto RPFM_exit;
+            }
+
+            pmpln->lRefCount      = 1;
+            pmpln->dwPid          = pProcLocalData->dwProcessId;
+            pmpln->dwExitCode     = 0;
+            pmpln->pProcessObject = pProcessObject;
+            pmpln->pProcessObject->AddReference();
+            pmpln->pProcLocalData = pProcLocalData;
+
+            // Acquire SynchData and AddRef it
+            pmpln->psdSynchData = psdSynchData;
+            psdSynchData->AddRef();
+
+            pmpln->pNext = m_pmplnMonitoredProcesses;
+            m_pmplnMonitoredProcesses = pmpln;
+            m_lMonitoredProcessesCount++;
+
+            fWakeUpWorker = true;
+        }
+
+        // Unlock
+        InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+        fMonitoredProcessesLock = false;
+
+        if (fWakeUpWorker)
+        {
+            CPalSynchronizationManager * pSynchManager = GetInstance();
+
+            palErr = pSynchManager->WakeUpLocalWorkerThread(SynchWorkerCmdNop);
+            if (NO_ERROR != palErr)
+            {
+                ERROR("Failed waking up worker thread for process "
+                      "monitoring registration [errno=%d {%s%}]\n",
+                      errno, strerror(errno));
+                palErr = ERROR_INTERNAL_ERROR;
+            }
+        }
+
+    RPFM_exit:
+        if (fMonitoredProcessesLock)
+        {
+            InternalLeaveCriticalSection(pthrCurrent,
+                                         &s_csMonitoredProcessesLock);
+        }
+
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::UnRegisterProcessForMonitoring
+
+    Unregisters a process object currently monitored by the worker thread
+    (typically called if the wait timed out before the process exited, or
+    if the wait was a normal (i.e. non wait-all) wait that involved othter
+    objects, and another object has been signaled).
+    --*/
+    PAL_ERROR CPalSynchronizationManager::UnRegisterProcessForMonitoring(
+        CPalThread * pthrCurrent,
+        CSynchData *psdSynchData,
+        DWORD dwPid)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        MonitoredProcessesListNode * pmpln, * pmplnPrev = NULL;
+
+        VALIDATEOBJECT(psdSynchData);
+
+        InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+
+        pmpln = m_pmplnMonitoredProcesses;
+        while (pmpln)
+        {
+            if (psdSynchData == pmpln->psdSynchData)
+            {
+                _ASSERT_MSG(dwPid == pmpln->dwPid, "Invalid node in Monitored Processes List\n");
+                break;
+            }
+
+            pmplnPrev = pmpln;
+            pmpln = pmpln->pNext;
+        }
+
+        if (pmpln)
+        {
+            if (0 == --pmpln->lRefCount)
+            {
+                if (NULL != pmplnPrev)
+                {
+                    pmplnPrev->pNext = pmpln->pNext;
+                }
+                else
+                {
+                    m_pmplnMonitoredProcesses = pmpln->pNext;
+                }
+
+                m_lMonitoredProcessesCount--;
+                pmpln->pProcessObject->ReleaseReference(pthrCurrent);
+                pmpln->psdSynchData->Release(pthrCurrent);
+                InternalDelete(pmpln);
+            }
+        }
+        else
+        {
+            palErr = ERROR_NOT_FOUND;
+        }
+
+        InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::ThreadPrepareForShutdown
+
+    Used to hijack thread execution from known spots within the
+    Synchronization Manager in case a PAL shutdown is initiated
+    or the thread is being terminated by another thread.
+    --*/
+    void CPalSynchronizationManager::ThreadPrepareForShutdown()
+    {
+        TRACE("The Synchronization Manager hijacked the current thread "
+              "for process shutdown or thread termination\n");
+        while (true)
+        {
+            poll(NULL, 0, INFTIM);
+            sched_yield();
+        }
+
+        ASSERT("This code should never be executed\n");
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::DoMonitorProcesses
+
+    This method is called by the worker thread to execute one step of
+    monitoring for all the process currently registered for monitoring
+    --*/
+    LONG CPalSynchronizationManager::DoMonitorProcesses(
+        CPalThread * pthrCurrent)
+    {
+        MonitoredProcessesListNode * pNode, * pPrev = NULL, * pNext;
+        LONG lInitialNodeCount;
+        LONG lRemovingCount = 0;
+        bool fLocalSynchLock = false;
+        bool fSharedSynchLock = false;
+        bool fMonitoredProcessesLock = false;
+
+        // Note: we first need to grab the monitored processes lock to walk
+        //       the list of monitored processes, and then, if there is any
+        //       which exited, to grab the synchronization lock(s) to signal
+        //       the process object. Anyway we cannot grab the synchronization
+        //       lock(s) while holding the monitored processes lock; that
+        //       would cause deadlock, since RegisterProcessForMonitoring and
+        //       UnRegisterProcessForMonitoring call stacks grab the locks
+        //       in the opposite order. Grabbing the synch lock(s) first (and
+        //       therefore all the times) would cause unacceptable contention
+        //       (process monitoring is done in polling mode).
+        //       Therefore we need to remove list nodes for processes that
+        //       exited copying them to the exited array, while holding only
+        //       the monitored processes lock, and then to signal them from that
+        //       array holding synch lock(s) and monitored processes lock,
+        //       acquired in this order. Holding again the monitored processes
+        //       lock is needed in order to support object promotion.
+
+        // Grab the monitored processes lock
+        InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+        fMonitoredProcessesLock = true;
+
+        lInitialNodeCount = m_lMonitoredProcessesCount;
+
+        pNode = m_pmplnMonitoredProcesses;
+        while (pNode)
+        {
+            pNext = pNode->pNext;
+
+            if (HasProcessExited(pNode->dwPid,
+                                 &pNode->dwExitCode,
+                                 &pNode->fIsActualExitCode))
+            {
+                TRACE("Process %u exited with return code %u\n",
+                      pNode->dwPid,
+                      pNode->fIsActualExitCode ? "actual" : "guessed",
+                      pNode->dwExitCode);
+
+                if (NULL != pPrev)
+                {
+                    pPrev->pNext = pNext;
+                }
+                else
+                {
+                    m_pmplnMonitoredProcesses = pNext;
+                }
+
+                m_lMonitoredProcessesCount--;
+
+                // Insert in the list of nodes for exited processes
+                pNode->pNext = m_pmplnExitedNodes;
+                m_pmplnExitedNodes = pNode;
+                lRemovingCount++;
+            }
+            else
+            {
+                pPrev = pNode;
+            }
+
+            // Go to the next
+            pNode = pNext;
+        }
+
+        // Release the monitored processes lock
+        InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+        fMonitoredProcessesLock = false;
+
+        if (lRemovingCount > 0)
+        {
+            // First grab the local synch lock
+            AcquireLocalSynchLock(pthrCurrent);
+            fLocalSynchLock = true;
+
+            // Acquire the monitored processes lock
+            InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+            fMonitoredProcessesLock = true;
+
+            if (!fSharedSynchLock)
+            {
+                bool fSharedSynchLockIsNeeded = false;
+
+                // See if the shared lock is needed
+                pNode = m_pmplnExitedNodes;
+                while (pNode)
+                {
+                    if (SharedObject == pNode->psdSynchData->GetObjectDomain())
+                    {
+                        fSharedSynchLockIsNeeded = true;
+                        break;
+                    }
+
+                    pNode = pNode->pNext;
+                }
+
+                if (fSharedSynchLockIsNeeded)
+                {
+                    // Release the monitored processes lock
+                    InternalLeaveCriticalSection(pthrCurrent,
+                                                 &s_csMonitoredProcessesLock);
+                    fMonitoredProcessesLock = false;
+
+                    // Acquire the shared synch lock
+                    AcquireSharedSynchLock(pthrCurrent);
+                    fSharedSynchLock = true;
+
+                    // Acquire again the monitored processes lock
+                    InternalEnterCriticalSection(pthrCurrent,
+                                                 &s_csMonitoredProcessesLock);
+                    fMonitoredProcessesLock = true;
+                }
+            }
+
+            // Start from the beginning of the exited processes list
+            pNode = m_pmplnExitedNodes;
+
+            // Invalidate the list
+            m_pmplnExitedNodes = NULL;
+
+            while (pNode)
+            {
+                pNext = pNode->pNext;
+
+                TRACE("Process pid=%u exited with exitcode=%u\n",
+                      pNode->dwPid, pNode->dwExitCode);
+
+                // Store the exit code in the process local data
+                if (pNode->fIsActualExitCode)
+                {
+                    pNode->pProcLocalData->dwExitCode = pNode->dwExitCode;
+                }
+
+                // Set process status to PS_DONE
+                pNode->pProcLocalData->ps = PS_DONE;
+
+                // Set signal count
+                pNode->psdSynchData->SetSignalCount(1);
+
+                // Releasing all local waiters
+                //
+                // We just called directly in CSynchData::SetSignalCount(), so
+                // we need to take care of waking up waiting threads according
+                // to the Process object semantics (i.e. every thread must be
+                // awakend). Anyway if a process object is shared among two or
+                // more processes and threads from different processes are
+                // waiting on it, the object will be registered for monitoring
+                // in each of the processes. As result its signal count will
+                // be set to one more times (which is not a problem, given the
+                // process object semantics) and each worker thread will wake
+                // up waiting threads. Therefore we need to make sure that each
+                // worker wakes up only threads in its own process: we do that
+                // by calling ReleaseAllLocalWaiters
+                pNode->psdSynchData->ReleaseAllLocalWaiters(pthrCurrent);
+
+                // We are done with pProcLocalData, so we can release the process object
+                pNode->pProcessObject->ReleaseReference(pthrCurrent);
+
+                // Release the reference to the SynchData
+                pNode->psdSynchData->Release(pthrCurrent);
+
+                // Delete the node
+                InternalDelete(pNode);
+
+                // Go to the next
+                pNode = pNext;
+            }
+        }
+
+        if (fMonitoredProcessesLock)
+        {
+            InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+        }
+
+        if (fSharedSynchLock)
+        {
+            ReleaseSharedSynchLock(pthrCurrent);
+        }
+
+        if (fLocalSynchLock)
+        {
+            ReleaseLocalSynchLock(pthrCurrent);
+        }
+
+        return (lInitialNodeCount - lRemovingCount);
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::DiscardMonitoredProcesses
+
+    This method is called at shutdown time to discard all the registration
+    for the processes currently monitored by the worker thread.
+    This method must be called at shutdown time, otherwise some shared memory
+    may be leaked at process shutdown.
+    --*/
+    void CPalSynchronizationManager::DiscardMonitoredProcesses(
+        CPalThread * pthrCurrent)
+    {
+        MonitoredProcessesListNode * pNode;
+
+        // Grab the monitored processes lock
+        InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+
+        while (m_pmplnMonitoredProcesses)
+        {
+            pNode = m_pmplnMonitoredProcesses;
+            m_pmplnMonitoredProcesses = pNode->pNext;
+            pNode->pProcessObject->ReleaseReference(pthrCurrent);
+            pNode->psdSynchData->Release(pthrCurrent);
+            InternalDelete(pNode);
+        }
+
+        // Release the monitored processes lock
+        InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::CreateProcessPipe
+
+    Creates the process pipe for the current process
+    --*/
+    bool CPalSynchronizationManager::CreateProcessPipe()
+    {
+        bool fRet = true;
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+        int iKq = -1;
+#endif // HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+
+#ifndef CORECLR
+        int iPipeRd = -1, iPipeWr = -1;
+        char szPipeFilename[MAX_PATH];
+
+        /* Create the blocking pipe */
+        if (!GetProcessPipeName(szPipeFilename, MAX_PATH, gPID))
+        {
+            ERROR("couldn't get process pipe's name\n");
+            szPipeFilename[0] = 0;
+            fRet = false;
+            goto CPP_exit;
+        }
+
+        /* create the pipe, with full access to the owner only */
+        if (mkfifo(szPipeFilename, S_IRWXU) == -1)
+        {
+            if (errno == EEXIST)
+            {
+                /* Some how no one deleted the pipe, perhaps it was left behind
+                from a crash?? Delete the pipe and try again. */
+                if (-1 == unlink(szPipeFilename))
+                {
+                    ERROR( "Unable to delete the process pipe that was left behind.\n" );
+                    fRet = false;
+                    goto CPP_exit;
+                }
+                else
+                {
+                    if (mkfifo(szPipeFilename, S_IRWXU) == -1)
+                    {
+                        ERROR( "Still unable to create the process pipe...giving up!\n" );
+                        fRet = false;
+                        goto CPP_exit;
+                    }
+                }
+            }
+            else
+            {
+                ERROR( "Unable to create the process pipe.\n" );
+                fRet = false;
+                goto CPP_exit;
+            }
+        }
+
+        iPipeRd = InternalOpen(szPipeFilename, O_RDONLY | O_NONBLOCK);
+        if (iPipeRd == -1)
+        {
+            ERROR("Unable to open the process pipe for read\n");
+            fRet = false;
+            goto CPP_exit;
+        }
+
+        iPipeWr = InternalOpen(szPipeFilename, O_WRONLY | O_NONBLOCK);
+        if (iPipeWr == -1)
+        {
+            ERROR("Unable to open the process pipe for write\n");
+            fRet = false;
+            goto CPP_exit;
+        }
+#else // !CORECLR
+        int rgiPipe[] = { -1, -1 };
+        int pipeRv =
+#if HAVE_PIPE2
+            pipe2(rgiPipe, O_CLOEXEC);
+#else
+            pipe(rgiPipe);
+#endif // HAVE_PIPE2
+        if (pipeRv == -1)
+        {
+            ERROR("Unable to create the process pipe\n");
+            fRet = false;
+            goto CPP_exit;
+        }
+#if !HAVE_PIPE2
+        fcntl(rgiPipe[0], F_SETFD, FD_CLOEXEC); // make pipe non-inheritable, if possible
+        fcntl(rgiPipe[1], F_SETFD, FD_CLOEXEC);
+#endif // !HAVE_PIPE2
+#endif // !CORECLR
+
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+        iKq = kqueue();
+        if (-1 == iKq)
+        {
+            ERROR("Failed to create kqueue associated to process pipe\n");
+            fRet = false;
+            goto CPP_exit;
+        }
+#endif // HAVE_KQUEUE
+
+    CPP_exit:
+        if (fRet)
+        {
+            // Succeeded
+#ifndef CORECLR
+            m_iProcessPipeRead = iPipeRd;
+            m_iProcessPipeWrite = iPipeWr;
+#else // !CORECLR
+            m_iProcessPipeRead = rgiPipe[0];
+            m_iProcessPipeWrite = rgiPipe[1];
+#endif // !CORECLR
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+            m_iKQueue = iKq;
+#endif // HAVE_KQUEUE
+        }
+        else
+        {
+#ifndef CORECLR
+            // Failed
+            if (0 != szPipeFilename[0])
+            {
+                unlink(szPipeFilename);
+            }
+            if (-1 != iPipeRd)
+            {
+                close(iPipeRd);
+            }
+            if (-1 != iPipeWr)
+            {
+                close(iPipeWr);
+            }
+#else // !CORECLR
+            if (-1 != rgiPipe[0])
+            {
+                close(rgiPipe[0]);
+                close(rgiPipe[1]);
+            }
+#endif // !CORECLR
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+            if (-1 != iKq)
+            {
+                close(iKq);
+            }
+#endif // HAVE_KQUEUE
+        }
+
+        return fRet;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::ShutdownProcessPipe
+
+    Shuts down the process pipe and removes the fifo so that other processes
+    can no longer open it. It also closes the local write end of the pipe (see
+    comment below). From this moment on the worker thread will process any
+    possible data already received in the pipe (but not yet consumed) and any
+    data written by processes that still have a opened write end of this pipe;
+    it will wait (with timeout) until the last remote process which has a write
+    end opened closes it, and then it will yield to process shutdown.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::ShutdownProcessPipe()
+    {
+        PAL_ERROR palErr = NO_ERROR;
+#ifndef CORECLR
+        char szPipeFilename[MAX_PATH];
+
+        if (GetProcessPipeName(szPipeFilename, MAX_PATH, gPID))
+        {
+            if (unlink(szPipeFilename) == -1)
+            {
+                ERROR("Unable to unlink the pipe file name errno=%d (%s)\n",
+                      errno, strerror(errno));
+                palErr = ERROR_INTERNAL_ERROR;
+                // go on anyway
+            }
+        }
+        else
+        {
+            ERROR("Couldn't get the process pipe's name\n");
+            palErr = ERROR_INTERNAL_ERROR;
+            // go on anyway
+        }
+#endif // CORECLR
+
+        if (-1 != m_iProcessPipeWrite)
+        {
+            // Closing the write end of the process pipe. When the last process
+            // that still has a open write-fd on this pipe will close it, the
+            // worker thread will receive an EOF; the worker thread will wait
+            // for this EOF before shutting down, so to ensure to process any
+            // possible data already written to the pipe by other processes
+            // when the shutdown has been initiated in the current process.
+            // Note: no need here to worry about platforms where close(pipe)
+            // blocks on outstanding syscalls, since we are the only one using
+            // this fd.
+            TRACE("Closing the write end of process pipe\n");
+            if (close(m_iProcessPipeWrite) == -1)
+            {
+                ERROR("Unable to close the write end of process pipe\n");
+                palErr = ERROR_INTERNAL_ERROR;
+            }
+
+            m_iProcessPipeWrite = -1;
+        }
+
+        return palErr;
+    }
+
+#ifndef CORECLR
+    /*++
+    Method:
+      CPalSynchronizationManager::GetProcessPipeName
+
+    Returns the process pipe name for the target process (identified by its PID)
+    --*/
+    bool CPalSynchronizationManager::GetProcessPipeName(
+        LPSTR pDest,
+        int iDestSize,
+        DWORD dwPid)
+    {
+        CHAR config_dir[MAX_PATH];
+        int needed_size;
+
+        _ASSERT_MSG(NULL != pDest, "Destination pointer is NULL!\n");
+        _ASSERT_MSG(0 < iDestSize,"Invalid buffer size %d\n", iDestSize);
+
+        if (!PALGetPalConfigDir(config_dir, MAX_PATH))
+        {
+            ASSERT("Unable to determine the PAL config directory.\n");
+            pDest[0] = '\0';
+            return false;
+        }
+        needed_size = snprintf(pDest, iDestSize, "%s/%s-%u", config_dir,
+                               PROCESS_PIPE_NAME_PREFIX, dwPid);
+        pDest[iDestSize-1] = 0;
+        if(needed_size >= iDestSize)
+        {
+            ERROR("threadpipe name needs %d characters, buffer only has room for "
+                  "%d\n", needed_size, iDestSize+1);
+            return false;
+        }
+        return true;
+    }
+#endif // !CORECLR
+
+    /*++
+    Method:
+      CPalSynchronizationManager::AcquireProcessLock
+
+    Acquires the local Process Lock (which currently is the same as the
+    the local Process Synch Lock)
+    --*/
+    void CPalSynchronizationManager::AcquireProcessLock(CPalThread * pthrCurrent)
+    {
+        AcquireLocalSynchLock(pthrCurrent);
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::ReleaseProcessLock
+
+    Releases the local Process Lock (which currently is the same as the
+    the local Process Synch Lock)
+    --*/
+    void CPalSynchronizationManager::ReleaseProcessLock(CPalThread * pthrCurrent)
+    {
+        ReleaseLocalSynchLock(pthrCurrent);
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::PromoteObjectSynchData
+
+    Promotes an object's synchdata from local to shared
+    --*/
+    PAL_ERROR CPalSynchronizationManager::PromoteObjectSynchData(
+        CPalThread *pthrCurrent,
+        VOID *pvLocalSynchData,
+        VOID **ppvSharedSynchData)
+    {
+        PAL_ERROR palError = NO_ERROR;
+        CSynchData *psdLocal = reinterpret_cast<CSynchData *>(pvLocalSynchData);
+        CSynchData *psdShared = NULL;
+        SharedID shridSynchData = NULL;
+        SharedID *rgshridWTLNodes = NULL;
+        CObjectType *pot = NULL;
+        ULONG ulcWaitingThreads;
+
+        _ASSERTE(NULL != pthrCurrent);
+        _ASSERTE(NULL != pvLocalSynchData);
+        _ASSERTE(NULL != ppvSharedSynchData);
+        _ASSERTE(ProcessLocalObject == psdLocal->GetObjectDomain());
+
+#if _DEBUG
+
+        //
+        // TODO: Verify that the proper locks are held
+        //
+#endif
+
+        //
+        // Allocate shared memory CSynchData and map to local memory
+        //
+
+        shridSynchData = m_cacheSHRSynchData.Get(pthrCurrent);
+        if (NULL == shridSynchData)
+        {
+            ERROR("Unable to allocate shared memory\n");
+            palError = ERROR_NOT_ENOUGH_MEMORY;
+            goto POSD_exit;
+        }
+
+        psdShared = SharedIDToTypePointer(CSynchData, shridSynchData);
+        _ASSERTE(NULL != psdShared);
+
+        //
+        // Allocate shared memory WaitingThreadListNodes if there are
+        // any threads currently waiting on this object
+        //
+
+        ulcWaitingThreads = psdLocal->GetWaitingThreadCount();
+        if (0 < ulcWaitingThreads)
+        {
+            int i;
+
+            rgshridWTLNodes = InternalNewArray<SharedID>(ulcWaitingThreads);
+            if (NULL == rgshridWTLNodes)
+            {
+                palError = ERROR_OUTOFMEMORY;
+                goto POSD_exit;
+            }
+
+            i = m_cacheSHRWTListNodes.Get(
+                    pthrCurrent,
+                    ulcWaitingThreads,
+                    rgshridWTLNodes
+                    );
+
+            if (static_cast<ULONG>(i) != ulcWaitingThreads)
+            {
+                for (i -= 1; i >= 0; i -= 1)
+                {
+                    m_cacheSHRWTListNodes.Add(pthrCurrent, rgshridWTLNodes[i]);
+                }
+
+                palError = ERROR_OUTOFMEMORY;
+                goto POSD_exit;
+            }
+        }
+
+        //
+        // If the synch data is for a process object we need to grab
+        // the monitored process list lock here
+        //
+
+        pot = psdLocal->GetObjectType();
+        _ASSERTE(NULL != pot);
+
+        if (otiProcess == pot->GetId())
+        {
+            InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+        }
+
+        //
+        // Copy pertinent CSynchData info to the shared memory version (and
+        // initialize other members)
+        //
+
+        psdShared->SetSharedThis(shridSynchData);
+        psdShared->SetObjectDomain(SharedObject);
+        psdShared->SetObjectType(psdLocal->GetObjectType());
+        psdShared->SetSignalCount(psdLocal->GetSignalCount());
+
+#ifdef SYNCH_STATISTICS
+        psdShared->SetStatContentionCount(psdLocal->GetStatContentionCount());
+        psdShared->SetStatWaitCount(psdLocal->GetStatWaitCount());
+#endif
+
+        //
+        // Rebuild the waiting thread list, and update the wait domain
+        // for the waiting threads
+        //
+
+        psdShared->SetWTLHeadShrPtr(NULL);
+        psdShared->SetWTLTailShrPtr(NULL);
+
+        if (0 < ulcWaitingThreads)
+        {
+            WaitingThreadsListNode *pwtlnOld;
+            WaitingThreadsListNode *pwtlnNew;
+            int i = 0;
+
+            for (pwtlnOld = psdLocal->GetWTLHeadPtr();
+                 pwtlnOld != NULL;
+                 pwtlnOld = pwtlnOld->ptrNext.ptr, i += 1)
+            {
+                pwtlnNew = SharedIDToTypePointer(
+                    WaitingThreadsListNode,
+                    rgshridWTLNodes[i]
+                    );
+
+                _ASSERTE(NULL != pwtlnNew);
+
+                pwtlnNew->shridSHRThis = rgshridWTLNodes[i];
+                pwtlnNew->ptrOwnerObjSynchData.shrid = shridSynchData;
+
+                pwtlnNew->dwThreadId = pwtlnOld->dwThreadId;
+                pwtlnNew->dwProcessId = pwtlnOld->dwProcessId;
+                pwtlnNew->dwObjIndex = pwtlnOld->dwObjIndex;
+                pwtlnNew->dwFlags = pwtlnOld->dwFlags | WTLN_FLAG_OWNER_OBJECT_IS_SHARED;
+                pwtlnNew->shridWaitingState = pwtlnOld->shridWaitingState;
+                pwtlnNew->ptwiWaitInfo = pwtlnOld->ptwiWaitInfo;
+
+                psdShared->SharedWaiterEnqueue(rgshridWTLNodes[i], false);
+                psdShared->AddRef();
+
+                _ASSERTE(pwtlnOld = pwtlnOld->ptwiWaitInfo->rgpWTLNodes[pwtlnOld->dwObjIndex]);
+                pwtlnNew->ptwiWaitInfo->rgpWTLNodes[pwtlnNew->dwObjIndex] = pwtlnNew;
+
+                pwtlnNew->ptwiWaitInfo->lSharedObjCount += 1;
+                if (pwtlnNew->ptwiWaitInfo->lSharedObjCount
+                    == pwtlnNew->ptwiWaitInfo->lObjCount)
+                {
+                    pwtlnNew->ptwiWaitInfo->wdWaitDomain = SharedWait;
+                }
+                else
+                {
+                    _ASSERTE(pwtlnNew->ptwiWaitInfo->lSharedObjCount
+                        < pwtlnNew->ptwiWaitInfo->lObjCount);
+
+                    pwtlnNew->ptwiWaitInfo->wdWaitDomain = MixedWait;
+                }
+            }
+
+            _ASSERTE(psdShared->GetWaitingThreadCount() == ulcWaitingThreads);
+        }
+
+        //
+        // If the object tracks ownership and has a current owner update
+        // the OwnedObjectsListNode to point to the shared memory synch
+        // data
+        //
+
+        if (CObjectType::OwnershipTracked == pot->GetOwnershipSemantics())
+        {
+            OwnedObjectsListNode *pooln;
+
+            pooln = psdLocal->GetOwnershipListNode();
+            if (NULL != pooln)
+            {
+                pooln->pPalObjSynchData = psdShared;
+                psdShared->SetOwnershipListNode(pooln);
+                psdShared->AddRef();
+
+                //
+                // Copy over other ownership info.
+                //
+
+                psdShared->SetOwner(psdLocal->GetOwnerThread());
+                psdShared->SetOwnershipCount(psdLocal->GetOwnershipCount());
+                _ASSERTE(!psdShared->IsAbandoned());
+            }
+            else
+            {
+                _ASSERTE(0 == psdLocal->GetOwnershipCount());
+                _ASSERTE(0 == psdShared->GetOwnershipCount());
+                psdShared->SetAbandoned(psdLocal->IsAbandoned());
+            }
+        }
+
+        //
+        // If the synch data is for a process object update the monitored
+        // process list nodes to point to the shared memory object data,
+        // and release the monitored process list lock
+        //
+
+        if (otiProcess == pot->GetId())
+        {
+            MonitoredProcessesListNode *pmpn;
+
+            pmpn = m_pmplnMonitoredProcesses;
+            while (NULL != pmpn)
+            {
+                if (psdLocal == pmpn->psdSynchData)
+                {
+                    pmpn->psdSynchData = psdShared;
+                    psdShared->AddRef();
+                }
+
+                pmpn = pmpn->pNext;
+            }
+
+            pmpn = m_pmplnExitedNodes;
+            while (NULL != pmpn)
+            {
+                if (psdLocal == pmpn->psdSynchData)
+                {
+                    pmpn->psdSynchData = psdShared;
+                    psdShared->AddRef();
+                }
+
+                pmpn = pmpn->pNext;
+            }
+
+            InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+        }
+
+        *ppvSharedSynchData = reinterpret_cast<VOID*>(shridSynchData);
+
+        //
+        // Free the local memory items to caches
+        //
+
+        if (0 < ulcWaitingThreads)
+        {
+            WaitingThreadsListNode *pwtln;
+
+            pwtln = psdLocal->GetWTLHeadPtr();
+            while (NULL != pwtln)
+            {
+                WaitingThreadsListNode *pwtlnTemp;
+
+                pwtlnTemp = pwtln;
+                pwtln = pwtln->ptrNext.ptr;
+                m_cacheWTListNodes.Add(pthrCurrent, pwtlnTemp);
+            }
+        }
+
+        m_cacheSynchData.Add(pthrCurrent, psdLocal);
+
+    POSD_exit:
+
+        if (NULL != rgshridWTLNodes)
+        {
+            InternalDeleteArray(rgshridWTLNodes);
+        }
+
+        return palError;
+    }
+
+
+    /////////////////////////////
+    //                         //
+    //  _ThreadNativeWaitData  //
+    //                         //
+    /////////////////////////////
+
+    _ThreadNativeWaitData::~_ThreadNativeWaitData()
+    {
+        if (fInitialized)
+        {
+            fInitialized = false;
+            pthread_cond_destroy(&cond);
+            pthread_mutex_destroy(&mutex);
+        }
+    }
+
+
+    //////////////////////////////////
+    //                              //
+    //  CThreadSynchronizationInfo  //
+    //                              //
+    //////////////////////////////////
+
+    CThreadSynchronizationInfo::CThreadSynchronizationInfo() :
+            m_tsThreadState(TS_IDLE),
+            m_shridWaitAwakened(NULL),
+            m_lLocalSynchLockCount(0),
+            m_lSharedSynchLockCount(0)
+    {
+        InitializeListHead(&m_leOwnedObjsList);
+
+#ifdef SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        m_lPendingSignalingCount = 0;
+        InitializeListHead(&m_lePendingSignalingsOverflowList);
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+    }
+
+    CThreadSynchronizationInfo::~CThreadSynchronizationInfo()
+    {
+        if (NULL != m_shridWaitAwakened)
+        {
+            free(m_shridWaitAwakened);
+        }
+    }
+
+    void CThreadSynchronizationInfo::AcquireNativeWaitLock()
+    {
+#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        int iRet;
+        iRet = pthread_mutex_lock(&m_tnwdNativeData.mutex);
+        _ASSERT_MSG(0 == iRet, "pthread_mutex_lock failed with error=%d\n", iRet);
+#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+    }
+
+    void CThreadSynchronizationInfo::ReleaseNativeWaitLock()
+    {
+#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        int iRet;
+        iRet = pthread_mutex_unlock(&m_tnwdNativeData.mutex);
+        _ASSERT_MSG(0 == iRet, "pthread_mutex_unlock failed with error=%d\n", iRet);
+#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+    }
+
+    bool CThreadSynchronizationInfo::TryAcquireNativeWaitLock()
+    {
+        bool fRet = true;
+#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        int iRet;
+        iRet = pthread_mutex_trylock(&m_tnwdNativeData.mutex);
+        _ASSERT_MSG(0 == iRet || EBUSY == iRet,
+                    "pthread_mutex_trylock failed with error=%d\n", iRet);
+        fRet = (0 == iRet);
+#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+        return fRet;
+    }
+
+    /*++
+    Method:
+      CThreadSynchronizationInfo::InitializePreCreate
+
+    Part of CThreadSynchronizationInfo's initialization to be carried out
+    before actual thread creation
+    --*/
+    PAL_ERROR CThreadSynchronizationInfo::InitializePreCreate(void)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        DWORD * pdwWaitState = NULL;
+        int iRet;
+        const int MaxUnavailableResourceRetries = 10;
+        int iEagains;
+        pthread_condattr_t attrs;
+        pthread_condattr_t *attrsPtr = nullptr;
+
+        m_shridWaitAwakened = malloc(sizeof(DWORD));
+        if (NULL == m_shridWaitAwakened)
+        {
+            ERROR("Fail allocating thread wait status shared object\n");
+            palErr = ERROR_NOT_ENOUGH_MEMORY;
+            goto IPrC_exit;
+        }
+
+        pdwWaitState = SharedIDToTypePointer(DWORD,
+            m_shridWaitAwakened);
+
+        _ASSERT_MSG(NULL != pdwWaitState,
+            "Unable to map shared wait state: bad shared ID [shrid=%p]\n", (VOID*)m_shridWaitAwakened);
+
+        VolatileStore<DWORD>(pdwWaitState, TWS_ACTIVE);
+        m_tsThreadState = TS_STARTING;
+
+#if HAVE_CLOCK_MONOTONIC && HAVE_PTHREAD_CONDATTR_SETCLOCK
+        attrsPtr = &attrs;
+        iRet = pthread_condattr_init(&attrs);
+        if (0 != iRet)
+        {
+            ERROR("Failed to initialize thread synchronization condition attribute "
+                  "[error=%d (%s)]\n", iRet, strerror(iRet));
+            if (ENOMEM == iRet)
+            {
+                palErr = ERROR_NOT_ENOUGH_MEMORY;
+            }
+            else
+            {
+                palErr = ERROR_INTERNAL_ERROR;
+            }
+            goto IPrC_exit;
+        }
+
+        // Ensure that the pthread_cond_timedwait will use CLOCK_MONOTONIC
+        iRet = pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
+        if (0 != iRet)
+        {
+            ERROR("Failed set thread synchronization condition timed wait clock "
+                  "[error=%d (%s)]\n", iRet, strerror(iRet));
+            palErr = ERROR_INTERNAL_ERROR;
+            pthread_condattr_destroy(&attrs);
+            goto IPrC_exit;
+        }
+#endif // HAVE_CLOCK_MONOTONIC && HAVE_PTHREAD_CONDATTR_SETCLOCK
+
+        iEagains = 0;
+    Mutex_retry:
+        iRet = pthread_mutex_init(&m_tnwdNativeData.mutex, NULL);
+        if (0 != iRet)
+        {
+            ERROR("Failed creating thread synchronization mutex [error=%d (%s)]\n", iRet, strerror(iRet));
+            if (EAGAIN == iRet && MaxUnavailableResourceRetries >= ++iEagains)
+            {
+                poll(NULL, 0, std::min(100,10*iEagains));
+                goto Mutex_retry;
+            }
+            else if (ENOMEM == iRet)
+            {
+                palErr = ERROR_NOT_ENOUGH_MEMORY;
+            }
+            else
+            {
+                palErr = ERROR_INTERNAL_ERROR;
+            }
+
+            goto IPrC_exit;
+        }
+
+        iEagains = 0;
+    Cond_retry:
+
+        iRet = pthread_cond_init(&m_tnwdNativeData.cond, attrsPtr);
+
+        if (0 != iRet)
+        {
+            ERROR("Failed creating thread synchronization condition "
+                  "[error=%d (%s)]\n", iRet, strerror(iRet));
+            if (EAGAIN == iRet && MaxUnavailableResourceRetries >= ++iEagains)
+            {
+                poll(NULL, 0, std::min(100,10*iEagains));
+                goto Cond_retry;
+            }
+            else if (ENOMEM == iRet)
+            {
+                palErr = ERROR_NOT_ENOUGH_MEMORY;
+            }
+            else
+            {
+                palErr = ERROR_INTERNAL_ERROR;
+            }
+            pthread_mutex_destroy(&m_tnwdNativeData.mutex);
+            goto IPrC_exit;
+        }
+
+        m_tnwdNativeData.fInitialized = true;
+
+    IPrC_exit:
+        if (attrsPtr != nullptr)
+        {
+            pthread_condattr_destroy(attrsPtr);
+        }
+        if (NO_ERROR != palErr)
+        {
+            m_tsThreadState = TS_FAILED;
+        }
+        return palErr;
+    }
+
+    /*++
+    Method:
+      CThreadSynchronizationInfo::InitializePostCreate
+
+    Part of CThreadSynchronizationInfo's initialization to be carried out
+    after actual thread creation
+    --*/
+    PAL_ERROR CThreadSynchronizationInfo::InitializePostCreate(
+        CPalThread *pthrCurrent,
+        SIZE_T threadId,
+        DWORD dwLwpId)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+
+        if (TS_FAILED == m_tsThreadState)
+        {
+            palErr = ERROR_INTERNAL_ERROR;
+        }
+
+        m_twiWaitInfo.pthrOwner = pthrCurrent;
+
+        return palErr;
+    }
+
+
+    /*++
+    Method:
+      CThreadSynchronizationInfo::AddObjectToOwnedList
+
+    Adds an object to the list of currently owned objects.
+    --*/
+    void CThreadSynchronizationInfo::AddObjectToOwnedList(POwnedObjectsListNode pooln)
+    {
+        InsertTailList(&m_leOwnedObjsList, &pooln->Link);
+    }
+
+    /*++
+    Method:
+      CThreadSynchronizationInfo::RemoveObjectFromOwnedList
+
+    Removes an object from the list of currently owned objects.
+    --*/
+    void CThreadSynchronizationInfo::RemoveObjectFromOwnedList(POwnedObjectsListNode pooln)
+    {
+        RemoveEntryList(&pooln->Link);
+    }
+
+    /*++
+    Method:
+      CThreadSynchronizationInfo::RemoveFirstObjectFromOwnedList
+
+    Removes the first object from the list of currently owned objects.
+    --*/
+    POwnedObjectsListNode CThreadSynchronizationInfo::RemoveFirstObjectFromOwnedList()
+    {
+        OwnedObjectsListNode * poolnItem;
+
+        if (IsListEmpty(&m_leOwnedObjsList))
+        {
+            poolnItem = NULL;
+        }
+        else
+        {
+            PLIST_ENTRY pLink = RemoveHeadList(&m_leOwnedObjsList);
+            poolnItem = CONTAINING_RECORD(pLink, OwnedObjectsListNode, Link);
+        }
+
+        return poolnItem;
+    }
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+    /*++
+    Method:
+      CThreadSynchronizationInfo::RunDeferredThreadConditionSignalings
+
+    Carries out all the pending condition signalings for the current thread.
+    --*/
+    PAL_ERROR CThreadSynchronizationInfo::RunDeferredThreadConditionSignalings()
+    {
+        PAL_ERROR palErr = NO_ERROR;
+
+        _ASSERTE(0 <= m_lPendingSignalingCount);
+
+        if (0 < m_lPendingSignalingCount)
+        {
+            LONG lArrayPendingSignalingCount = std::min(PendingSignalingsArraySize, m_lPendingSignalingCount);
+            LONG lIdx = 0;
+            PAL_ERROR palTempErr;
+
+            // Signal all the pending signalings from the array
+            for (lIdx = 0; lIdx < lArrayPendingSignalingCount; lIdx++)
+            {
+                // Do the actual signaling
+                palTempErr = CPalSynchronizationManager::SignalThreadCondition(
+                    m_rgpthrPendingSignalings[lIdx]->synchronizationInfo.GetNativeData());
+                if (NO_ERROR != palTempErr)
+                {
+                    palErr = palTempErr;
+                }
+
+                // Release the thread reference
+                m_rgpthrPendingSignalings[lIdx]->ReleaseThreadReference();
+            }
+
+            // Signal any pending signalings from the array overflow list
+            if (m_lPendingSignalingCount > PendingSignalingsArraySize)
+            {
+                PLIST_ENTRY pLink;
+                DeferredSignalingListNode * pdsln;
+
+                while (!IsListEmpty(&m_lePendingSignalingsOverflowList))
+                {
+                    // Remove a node from the head of the queue
+                    // Note: no need to synchronize the access to this list since
+                    // it is meant to be accessed only by the owner thread.
+                    pLink = RemoveHeadList(&m_lePendingSignalingsOverflowList);
+                    pdsln = CONTAINING_RECORD(pLink,
+                                              DeferredSignalingListNode,
+                                              Link);
+
+                    // Do the actual signaling
+                    palTempErr = CPalSynchronizationManager::SignalThreadCondition(
+                        pdsln->pthrTarget->synchronizationInfo.GetNativeData());
+                    if (NO_ERROR != palTempErr)
+                    {
+                        palErr = palTempErr;
+                    }
+
+                    // Release the thread reference
+                    pdsln->pthrTarget->ReleaseThreadReference();
+
+                    // Delete the node
+                    InternalDelete(pdsln);
+
+                    lIdx += 1;
+                }
+
+                _ASSERTE(lIdx == m_lPendingSignalingCount);
+            }
+
+            // Reset the counter of pending signalings for this thread
+            m_lPendingSignalingCount = 0;
+        }
+
+        return palErr;
+    }
+
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+    /*++
+    Method:
+      CPalSynchronizationManager::HasProcessExited
+
+    Tests whether or not a process has exited
+    --*/
+    bool CPalSynchronizationManager::HasProcessExited(
+        DWORD dwPid,
+        DWORD * pdwExitCode,
+        bool * pfIsActualExitCode)
+    {
+        pid_t pidWaitRetval;
+        int iStatus;
+        bool fRet = false;
+
+        TRACE("Looking for status of process; trying wait()\n");
+
+        while(1)
+        {
+            /* try to get state of process, using non-blocking call */
+            pidWaitRetval = waitpid(dwPid, &iStatus, WNOHANG);
+
+            if ((DWORD)pidWaitRetval == dwPid)
+            {
+                /* success; get the exit code */
+                if (WIFEXITED(iStatus))
+                {
+                    *pdwExitCode = WEXITSTATUS(iStatus);
+                    *pfIsActualExitCode = true;
+                    TRACE("Exit code was %d\n", *pdwExitCode);
+                }
+                else
+                {
+                    WARN("Process terminated without exiting; can't get exit "
+                         "code. Assuming EXIT_FAILURE.\n");
+                    *pfIsActualExitCode = true;
+                    *pdwExitCode = EXIT_FAILURE;
+                }
+
+                fRet = true;
+            }
+            else if (0 == pidWaitRetval)
+            {
+                // The process is still running.
+                TRACE("Process %#x is still active.\n", dwPid);
+            }
+            else
+            {
+                // A legitimate cause of failure is EINTR; if this happens we
+                // have to try again. A second legitimate cause is ECHILD, which
+                // happens if we're trying to retrieve the status of a currently-
+                // running process that isn't a child of this process.
+                if(EINTR == errno)
+                {
+                    TRACE("waitpid() failed with EINTR; re-waiting\n");
+                    continue;
+                }
+                else if (ECHILD == errno)
+                {
+                    TRACE("waitpid() failed with ECHILD; calling kill instead\n");
+                    if (kill(dwPid, 0) != 0)
+                    {
+                        if (ESRCH == errno)
+                        {
+                            WARN("kill() failed with ESRCH, i.e. target "
+                                 "process exited and it wasn't a child, "
+                                 "so can't get the exit code, assuming  "
+                                 "it was 0.\n");
+                            *pfIsActualExitCode = false;
+                            *pdwExitCode = 0;
+                        }
+                        else
+                        {
+                            ERROR("kill(pid, 0) failed; errno is %d (%s)\n",
+                                  errno, strerror(errno));
+                            *pfIsActualExitCode = false;
+                            *pdwExitCode = EXIT_FAILURE;
+                        }
+
+                        fRet = true;
+                    }
+                }
+                else
+                {
+                    // Ignoring unexpected waitpid errno and assuming that
+                    // the process is still running
+                    ERROR("waitpid(pid=%u) failed with errno=%d (%s)\n",
+                          dwPid, errno, strerror(errno));
+                }
+            }
+
+            // Break out of the loop in all cases except EINTR.
+            break;
+        }
+
+        return fRet;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::InterlockedAwaken
+
+    Tries to change the target wait status to 'active' in an interlocked fashion
+    --*/
+    bool CPalSynchronizationManager::InterlockedAwaken(
+        DWORD *pWaitState,
+        bool fAlertOnly)
+    {
+        DWORD dwPrevState;
+
+        dwPrevState = InterlockedCompareExchange((LONG *)pWaitState, TWS_ACTIVE, TWS_ALERTABLE);
+        if (TWS_ALERTABLE != dwPrevState)
+        {
+            if (fAlertOnly)
+            {
+                return false;
+            }
+
+            dwPrevState = InterlockedCompareExchange((LONG *)pWaitState, TWS_ACTIVE, TWS_WAITING);
+            if (TWS_WAITING == dwPrevState)
+            {
+                return true;
+            }
+        }
+        else
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /*++
+    Method:
+      CPalSynchronizationManager::GetAbsoluteTimeout
+
+    Converts a relative timeout to an absolute one.
+    --*/
+    PAL_ERROR CPalSynchronizationManager::GetAbsoluteTimeout(DWORD dwTimeout, struct timespec * ptsAbsTmo, BOOL fPreferMonotonicClock)
+    {
+        PAL_ERROR palErr = NO_ERROR;
+        int iRet;
+
+#if HAVE_CLOCK_MONOTONIC && HAVE_PTHREAD_CONDATTR_SETCLOCK
+        if (fPreferMonotonicClock)
+        {
+            iRet = clock_gettime(CLOCK_MONOTONIC, ptsAbsTmo);
+        }
+        else
+        {
+#endif
+#if HAVE_WORKING_CLOCK_GETTIME
+            // Not every platform implements a (working) clock_gettime
+            iRet = clock_gettime(CLOCK_REALTIME, ptsAbsTmo);
+#elif HAVE_WORKING_GETTIMEOFDAY
+            // Not every platform implements a (working) gettimeofday
+            struct timeval tv;
+            iRet = gettimeofday(&tv, NULL);
+            if (0 == iRet)
+            {
+                ptsAbsTmo->tv_sec  = tv.tv_sec;
+                ptsAbsTmo->tv_nsec = tv.tv_usec * tccMicroSecondsToNanoSeconds;
+            }
+#else
+#ifdef DBI_COMPONENT_MONO
+    return ERROR_INTERNAL_ERROR;
+#else
+    #error "Don't know how to get hi-res current time on this platform"
+#endif
+#endif // HAVE_WORKING_CLOCK_GETTIME, HAVE_WORKING_GETTIMEOFDAY
+#if HAVE_CLOCK_MONOTONIC && HAVE_PTHREAD_CONDATTR_SETCLOCK
+        }
+#endif
+        if (0 == iRet)
+        {
+            ptsAbsTmo->tv_sec  += dwTimeout / tccSecondsToMillieSeconds;
+            ptsAbsTmo->tv_nsec += (dwTimeout % tccSecondsToMillieSeconds) * tccMillieSecondsToNanoSeconds;
+            while (ptsAbsTmo->tv_nsec >= tccSecondsToNanoSeconds)
+            {
+                ptsAbsTmo->tv_sec  += 1;
+                ptsAbsTmo->tv_nsec -= tccSecondsToNanoSeconds;
+            }
+        }
+        else
+        {
+            palErr = ERROR_INTERNAL_ERROR;
+        }
+
+        return palErr;
+    }
+}
diff --git a/src/pal/src/synchmgr/synchmanager.hpp b/src/pal/src/synchmgr/synchmanager.hpp
new file mode 100644 (file)
index 0000000..4338a61
--- /dev/null
@@ -0,0 +1,986 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    synchmanager.hpp
+
+Abstract:
+    Private header file for synchronization manager and
+    controllers implementation
+
+
+
+--*/
+#ifndef _SYNCHMANAGER_HPP_
+#define _SYNCHMANAGER_HPP_
+
+#include "pal/synchobjects.hpp"
+#include "pal/synchcache.hpp"
+#include "pal/cs.hpp"
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+#include "pal/procobj.hpp"
+#include "pal/init.h"
+#include "pal/process.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#if HAVE_KQUEUE
+#include <sys/event.h>
+#endif // HAVE_KQUEUE
+#include "pal/dbgmsg.h"
+
+#ifdef _DEBUG
+// #define SYNCH_OBJECT_VALIDATION
+// #define SYNCH_STATISTICS
+#endif
+
+#ifdef SYNCH_OBJECT_VALIDATION
+#define VALIDATEOBJECT(obj) ((obj)->ValidateObject())
+#else
+#define VALIDATEOBJECT(obj)
+#endif
+
+namespace CorUnix
+{
+    const DWORD WTLN_FLAG_OWNER_OBJECT_IS_SHARED                 = 1<<0;
+    const DWORD WTLN_FLAG_WAIT_ALL                               = 1<<1;
+    const DWORD WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS = 1<<2;
+
+#ifdef SYNCH_OBJECT_VALIDATION
+    const DWORD HeadSignature  = 0x48454144;
+    const DWORD TailSignature  = 0x5441494C;
+    const DWORD EmptySignature = 0xBAADF00D;
+#endif
+
+    enum THREAD_WAIT_STATE
+    {
+        TWS_ACTIVE,
+        TWS_WAITING,
+        TWS_ALERTABLE,
+        TWS_EARLYDEATH,
+    };
+
+    enum WaitCompletionState
+    {
+        WaitIsNotSatisfied,
+        WaitIsSatisfied,
+        WaitMayBeSatisfied
+    };
+
+    typedef union _SynchDataGenrPtr
+    {
+        SharedID shrid;
+        CSynchData * ptr;
+    } SynchDataGenrPtr;
+
+    typedef union _WTLNodeGenrPtr
+    {
+        SharedID shrid;
+        struct _WaitingThreadsListNode * ptr;
+    } WTLNodeGenrPtr;
+
+    typedef struct _WaitingThreadsListNode
+    {
+#ifdef SYNCH_OBJECT_VALIDATION
+        DWORD dwDebugHeadSignature;
+#endif
+        WTLNodeGenrPtr ptrNext;
+        WTLNodeGenrPtr ptrPrev;
+        SharedID shridSHRThis;
+
+        // Data
+        DWORD dwThreadId;
+        DWORD dwProcessId;
+        DWORD dwObjIndex;
+        DWORD dwFlags;
+
+        // Pointers to related objects
+        SharedID shridWaitingState;
+        SynchDataGenrPtr ptrOwnerObjSynchData;
+        struct _ThreadWaitInfo * ptwiWaitInfo;  // valid only in the
+                                                // target process
+#ifdef SYNCH_OBJECT_VALIDATION
+        _WaitingThreadsListNode();
+        ~_WaitingThreadsListNode();
+        void ValidateObject(void);
+        void ValidateEmptyObject(void);
+        void InvalidateObject(void);
+
+        DWORD dwDebugTailSignature;
+#endif
+    } WaitingThreadsListNode;
+
+    typedef struct _DeferredSignalingListNode
+    {
+        LIST_ENTRY Link;
+        CPalThread * pthrTarget;
+    } DeferredSignalingListNode;
+
+    typedef struct _OwnedObjectsListNode
+    {
+        LIST_ENTRY Link;
+        CSynchData * pPalObjSynchData;
+    } OwnedObjectsListNode;
+
+    class CPalSynchronizationManager; // fwd declaration
+    class CProcProcessLocalData;      // fwd declaration
+
+    class CSynchData
+    {
+#ifdef SYNCH_OBJECT_VALIDATION
+        DWORD m_dwDebugHeadSignature;
+#endif
+        // NB: For perforformance purposes this class is supposed
+        //     to have no virtual methods, and no destructor.
+
+        WTLNodeGenrPtr  m_ptrWTLHead;
+        WTLNodeGenrPtr  m_ptrWTLTail;
+        ULONG m_ulcWaitingThreads;
+        SharedID m_shridThis;
+        ObjectDomain m_odObjectDomain;
+        PalObjectTypeId m_otiObjectTypeId;
+        LONG  m_lRefCount;
+        LONG  m_lSignalCount;
+
+        // Ownership data
+        LONG  m_lOwnershipCount;
+        DWORD m_dwOwnerPid;
+        DWORD m_dwOwnerTid; // used only by remote processes
+                            // (thread ids may be recycled)
+        CPalThread * m_pOwnerThread; // valid only on the target process
+        OwnedObjectsListNode * m_poolnOwnedObjectListNode;
+        bool m_fAbandoned;
+
+#ifdef SYNCH_STATISTICS
+        ULONG m_lStatWaitCount;
+        ULONG m_lStatContentionCount;
+#endif
+
+    public:
+        CSynchData()
+            : m_ulcWaitingThreads(0), m_shridThis(NULL), m_lRefCount(1),
+              m_lSignalCount(0), m_lOwnershipCount(0), m_dwOwnerPid(0),
+              m_dwOwnerTid(0), m_pOwnerThread(NULL),
+              m_poolnOwnedObjectListNode(NULL), m_fAbandoned(false)
+        {
+            // m_ptrWTLHead, m_ptrWTLTail, m_odObjectDomain
+            // and m_otiObjectTypeId are initialized by
+            // CPalSynchronizationManager::AllocateObjectSynchData
+#ifdef SYNCH_STATISTICS
+            m_lStatWaitCount = 0;
+            m_lStatContentionCount = 0;
+#endif
+#ifdef SYNCH_OBJECT_VALIDATION
+            ValidateEmptyObject();
+            m_dwDebugHeadSignature = HeadSignature;;
+            m_dwDebugTailSignature = TailSignature;
+#endif
+        }
+
+        LONG AddRef()
+        {
+            return InterlockedIncrement(&m_lRefCount);
+        }
+
+        LONG Release(CPalThread * pthrCurrent);
+
+        bool CanWaiterWaitWithoutBlocking(
+            CPalThread * pWaiterThread,
+            bool * pfAbandoned);
+
+        PAL_ERROR ReleaseWaiterWithoutBlocking(
+            CPalThread * pthrCurrent,
+            CPalThread * pthrTarget);
+
+        void WaiterEnqueue(WaitingThreadsListNode * pwtlnNewNode, bool fPrioritize);
+        void SharedWaiterEnqueue(SharedID shridNewNode, bool fPrioritize);
+
+        // Object Domain accessor methods
+        ObjectDomain GetObjectDomain(void)
+        {
+            return m_odObjectDomain;
+        }
+        void SetObjectDomain(ObjectDomain odObjectDomain)
+        {
+            m_odObjectDomain = odObjectDomain;
+        }
+
+        // Object Type accessor methods
+        CObjectType * GetObjectType(void)
+        {
+            return CObjectType::GetObjectTypeById(m_otiObjectTypeId);
+        }
+        PalObjectTypeId GetObjectTypeId(void)
+        {
+            return m_otiObjectTypeId;
+        }
+        void SetObjectType(CObjectType * pot)
+        {
+            m_otiObjectTypeId = pot->GetId();
+        }
+        void SetObjectType(PalObjectTypeId oti)
+        {
+            m_otiObjectTypeId = oti;
+        }
+
+        // Object shared 'this' pointer accessor methods
+        SharedID GetSharedThis (void)
+        {
+            return m_shridThis;
+        }
+        void SetSharedThis (SharedID shridThis)
+        {
+            m_shridThis = shridThis;
+        }
+
+        void Signal(
+            CPalThread * pthrCurrent,
+            LONG lSignalCount,
+            bool fWorkerThread);
+
+        bool ReleaseFirstWaiter(
+            CPalThread * pthrCurrent,
+            bool * pfDelegated,
+            bool fWorkerThread);
+
+        LONG ReleaseAllLocalWaiters(
+            CPalThread * pthrCurrent);
+
+        WaitCompletionState IsRestOfWaitAllSatisfied(
+            WaitingThreadsListNode * pwtlnNode);
+
+        // Object signal count accessor methods
+        LONG GetSignalCount(void)
+        {
+            _ASSERTE(m_lSignalCount >= 0);
+            return m_lSignalCount;
+        }
+        void SetSignalCount(LONG lSignalCount)
+        {
+            _ASSERTE(m_lSignalCount >= 0);
+            _ASSERTE(lSignalCount >= 0);
+            m_lSignalCount = lSignalCount;
+        }
+        LONG DecrementSignalCount(void)
+        {
+            _ASSERTE(m_lSignalCount > 0);
+            return --m_lSignalCount;
+        }
+
+        // Object ownership accessor methods
+        void SetOwner(CPalThread * pOwnerThread);
+        void ResetOwnership(void);
+        PAL_ERROR AssignOwnershipToThread(
+            CPalThread * pthrCurrent,
+            CPalThread * pthrTarget);
+        DWORD GetOwnerProcessID(void)
+        {
+            return m_dwOwnerPid;
+        }
+        DWORD GetOwnerThreadID(void)
+        {
+            return m_dwOwnerTid;
+        }
+        CPalThread * GetOwnerThread(void)
+        {
+            return m_pOwnerThread;
+        }
+        OwnedObjectsListNode * GetOwnershipListNode(void)
+        {
+            return m_poolnOwnedObjectListNode;
+        }
+        void SetOwnershipListNode(OwnedObjectsListNode * pooln)
+        {
+            m_poolnOwnedObjectListNode = pooln;
+        }
+
+        // Object ownership count accessor methods
+        LONG GetOwnershipCount(void)
+        {
+            return m_lOwnershipCount;
+        }
+        void SetOwnershipCount(LONG lOwnershipCount)
+        {
+            m_lOwnershipCount = lOwnershipCount;
+        }
+
+        // Object abandoned flag accessor methods
+        void SetAbandoned(bool fAbandoned)
+                                    { m_fAbandoned = fAbandoned; }
+        bool IsAbandoned(void) { return m_fAbandoned; }
+
+        void IncrementWaitingThreadCount(void)
+        {
+            m_ulcWaitingThreads += 1;
+        }
+        void DecrementWaitingThreadCount(void)
+        {
+            m_ulcWaitingThreads -= 1;
+        }
+        ULONG GetWaitingThreadCount(void)
+        {
+            return m_ulcWaitingThreads;
+        }
+
+
+#ifdef SYNCH_STATISTICS
+        void IncrementStatWaitCount(void)
+        {
+            m_lStatWaitCount++;
+        }
+        LONG GetStatWaitCount(void)
+        {
+            return m_lStatWaitCount;
+        }
+        void IncrementStatContentionCount(void)
+        {
+            m_lStatContentionCount++;
+        }
+        LONG GetStatContentionCount(void)
+        {
+            return m_lStatContentionCount;
+        }
+#endif
+        //
+        // Wating threads list access methods
+        //
+        WaitingThreadsListNode * GetWTLHeadPtr(void)
+        {
+            return m_ptrWTLHead.ptr;
+        }
+        WaitingThreadsListNode * GetWTLTailPtr(void)
+        {
+            return m_ptrWTLTail.ptr;
+        }
+        SharedID GetWTLHeadShmPtr(void)
+        {
+            return m_ptrWTLHead.shrid;
+        }
+        SharedID GetWTLTailShmPtr(void)
+        {
+            return m_ptrWTLTail.shrid;
+        }
+        void SetWTLHeadPtr(WaitingThreadsListNode * p)
+        {
+            m_ptrWTLHead.ptr = p;
+        }
+        void SetWTLTailPtr(WaitingThreadsListNode * p)
+        {
+            m_ptrWTLTail.ptr = p;
+        }
+        void SetWTLHeadShrPtr(SharedID shrid)
+        {
+            m_ptrWTLHead.shrid = shrid;
+        }
+        void SetWTLTailShrPtr(SharedID shrid)
+        {
+            m_ptrWTLTail.shrid = shrid;
+        }
+#ifdef SYNCH_OBJECT_VALIDATION
+        ~CSynchData();
+        void ValidateObject(bool fDestructor = false);
+        void ValidateEmptyObject(void);
+        void InvalidateObject(void);
+
+        DWORD m_dwDebugTailSignature;
+#endif
+    };
+
+
+    class CSynchControllerBase
+    {
+        friend class CPalSynchronizationManager;
+
+        // NB: For perforformance purposes this class is supposed
+        //     to have no virtual methods, contructor and
+        //     destructor
+    public:
+        enum ControllerType { WaitController, StateController };
+
+    protected:
+        CPalThread * m_pthrOwner;
+        ControllerType m_ctCtrlrType;
+        ObjectDomain m_odObjectDomain;
+        CObjectType * m_potObjectType;
+        CSynchData * m_psdSynchData;
+        WaitDomain m_wdWaitDomain;
+
+        PAL_ERROR Init(
+            CPalThread * pthrCurrent,
+            ControllerType ctCtrlrType,
+            ObjectDomain odObjectDomain,
+            CObjectType *potObjectType,
+            CSynchData * psdSynchData,
+            WaitDomain wdWaitDomain);
+
+        void Release(void);
+
+        void SetSynchData(CSynchData * psdSynchData)
+        {
+            m_psdSynchData = psdSynchData;
+        }
+        CSynchData * GetSynchData()
+        {
+            return m_psdSynchData;
+        }
+    };
+
+    class CSynchWaitController : public CSynchControllerBase,
+                                 public ISynchWaitController
+    {
+        // Per-object-type specific data
+        //
+        // Process (otiProcess)
+        IPalObject *m_pProcessObject; // process that owns m_pProcLocalData, this is stored without a reference
+        CProcProcessLocalData * m_pProcLocalData;
+
+    public:
+        CSynchWaitController() : m_pProcessObject(NULL), m_pProcLocalData(NULL) {}
+        virtual ~CSynchWaitController() = default;
+
+        //
+        // ISynchWaitController methods
+        //
+        virtual PAL_ERROR CanThreadWaitWithoutBlocking(
+            bool * pfCanWaitWithoutBlocking,
+            bool * pfAbandoned);
+
+        virtual PAL_ERROR ReleaseWaitingThreadWithoutBlocking(void);
+
+        virtual PAL_ERROR RegisterWaitingThread(
+            WaitType wtWaitType,
+            DWORD dwIndex,
+            bool fAlertable,
+            bool fPrioritize);
+
+        virtual void ReleaseController(void);
+
+        CProcProcessLocalData * GetProcessLocalData(void);
+
+        void SetProcessData(IPalObject* pProcessObject, CProcProcessLocalData * pProcLocalData);
+    };
+
+    class CSynchStateController : public CSynchControllerBase,
+                                  public ISynchStateController
+    {
+    public:
+        // NB: For perforformance purposes this class is supposed
+        //     to have no constructor
+        virtual ~CSynchStateController() = default;
+
+        //
+        // ISynchStateController methods
+        //
+        virtual PAL_ERROR GetSignalCount(LONG *plSignalCount);
+        virtual PAL_ERROR SetSignalCount(LONG lNewCount);
+        virtual PAL_ERROR IncrementSignalCount(LONG lAmountToIncrement);
+        virtual PAL_ERROR DecrementSignalCount(LONG lAmountToDecrement);
+        virtual PAL_ERROR SetOwner(CPalThread *pNewOwningThread);
+        virtual PAL_ERROR DecrementOwnershipCount(void);
+        virtual void ReleaseController(void);
+    };
+
+    class CPalSynchronizationManager : public IPalSynchronizationManager
+    {
+        friend class CPalSynchMgrController;
+        template <class T> friend T *CorUnix::InternalNew();
+
+    public:
+        // types
+        typedef CSynchCache<CSynchWaitController>      CSynchWaitControllerCache;
+        typedef CSynchCache<CSynchStateController>     CSynchStateControllerCache;
+        typedef CSynchCache<CSynchData>                CSynchDataCache;
+        typedef CSHRSynchCache<CSynchData>             CSHRSynchDataCache;
+        typedef CSynchCache<WaitingThreadsListNode>    CWaitingThreadsListNodeCache;
+        typedef CSHRSynchCache<WaitingThreadsListNode> CSHRWaitingThreadsListNodeCache;
+        typedef CSynchCache<OwnedObjectsListNode>      COwnedObjectsListNodeCache;
+
+    private:
+        // types
+        enum InitStatus
+        {
+            SynchMgrStatusIdle,
+            SynchMgrStatusInitializing,
+            SynchMgrStatusRunning,
+            SynchMgrStatusShuttingDown,
+            SynchMgrStatusReadyForProcessShutDown,
+            SynchMgrStatusError
+        };
+        enum SynchWorkerCmd
+        {
+            SynchWorkerCmdNop,
+            SynchWorkerCmdRemoteSignal,
+            SynchWorkerCmdDelegatedObjectSignaling,
+            SynchWorkerCmdShutdown,
+            SynchWorkerCmdTerminationRequest,
+            SynchWorkerCmdLast
+        };
+
+        typedef struct _MonitoredProcessesListNode
+        {
+            struct _MonitoredProcessesListNode * pNext;
+            LONG lRefCount;
+            CSynchData * psdSynchData;
+            DWORD dwPid;
+            DWORD dwExitCode;
+            bool fIsActualExitCode;
+
+            // Object that owns pProcLocalData. This is stored, with a reference, to
+            // ensure that pProcLocalData is not deleted.
+            IPalObject *pProcessObject;
+            CProcProcessLocalData * pProcLocalData;
+        } MonitoredProcessesListNode;
+
+        // constants
+        static const int CtrlrsCacheMaxSize                = 256;
+        static const int SynchDataCacheMaxSize             = 256;
+        static const int WTListNodeCacheMaxSize            = 256;
+        static const int OwnedObjectsListCacheMaxSize      = 16;
+        static const int MaxWorkerConsecutiveEintrs        = 128;
+        static const int MaxConsecutiveEagains             = 128;
+        static const int WorkerThreadProcMonitoringTimeout = 250;  // ms
+        static const int WorkerThreadShuttingDownTimeout   = 1000; // ms
+        static const int WorkerCmdCompletionTimeout        = 250;  // ms
+        static const DWORD SecondNativeWaitTimeout         = INFINITE;
+        static const DWORD WorkerThreadTerminationTimeout  = 2000; // ms
+
+        // static members
+        static CPalSynchronizationManager * s_pObjSynchMgr;
+        static Volatile<LONG>               s_lInitStatus;
+        static CRITICAL_SECTION             s_csSynchProcessLock;
+        static CRITICAL_SECTION             s_csMonitoredProcessesLock;
+
+        // members
+        DWORD                           m_dwWorkerThreadTid;
+        IPalObject *                    m_pipoThread;
+        CPalThread *                    m_pthrWorker;
+        int                             m_iProcessPipeRead;
+        int                             m_iProcessPipeWrite;
+#if HAVE_KQUEUE
+        int                             m_iKQueue;
+        struct kevent                   m_keProcessPipeEvent;
+#endif // HAVE_KQUEUE
+
+        MonitoredProcessesListNode *    m_pmplnMonitoredProcesses;
+        LONG                            m_lMonitoredProcessesCount;
+        MonitoredProcessesListNode *    m_pmplnExitedNodes;
+
+        // caches
+        CSynchWaitControllerCache       m_cacheWaitCtrlrs;
+        CSynchStateControllerCache      m_cacheStateCtrlrs;
+        CSynchDataCache                 m_cacheSynchData;
+        CSHRSynchDataCache              m_cacheSHRSynchData;
+        CWaitingThreadsListNodeCache    m_cacheWTListNodes;
+        CSHRWaitingThreadsListNodeCache m_cacheSHRWTListNodes;
+        COwnedObjectsListNodeCache      m_cacheOwnedObjectsListNodes;
+
+        // static methods
+        static PAL_ERROR Initialize();
+        static DWORD PALAPI WorkerThread(LPVOID pArg);
+
+    protected:
+        CPalSynchronizationManager();
+
+        PAL_ERROR GetSynchControllersForObjects(
+            CPalThread *pthrCurrent,
+            IPalObject *rgObjects[],
+            DWORD dwObjectCount,
+            void ** ppvControllers,
+            CSynchControllerBase::ControllerType ctCtrlrType);
+
+    private:
+        static IPalSynchronizationManager * CreatePalSynchronizationManager();
+        static PAL_ERROR StartWorker(CPalThread * pthrCurrent);
+        static PAL_ERROR PrepareForShutdown(void);
+
+    public:
+        virtual ~CPalSynchronizationManager();
+
+        static CPalSynchronizationManager * GetInstance(void)
+        {
+            // No need here to check for NULL and in case create the
+            // singleton, since its creation is enforced by the PAL
+            // initialization code.
+            return s_pObjSynchMgr;
+        }
+
+        //
+        // Inline utility methods
+        //
+        static void AcquireLocalSynchLock(CPalThread * pthrCurrent)
+        {
+            _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+
+            if (1 == ++pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount)
+            {
+                InternalEnterCriticalSection(pthrCurrent, &s_csSynchProcessLock);
+            }
+        }
+        static void ReleaseLocalSynchLock(CPalThread * pthrCurrent)
+        {
+            _ASSERTE(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+            if (0 == --pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount)
+            {
+                InternalLeaveCriticalSection(pthrCurrent, &s_csSynchProcessLock);
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+                pthrCurrent->synchronizationInfo.RunDeferredThreadConditionSignalings();
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+            }
+        }
+        static LONG ResetLocalSynchLock(CPalThread * pthrCurrent)
+        {
+            LONG lRet = pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount;
+
+            _ASSERTE(0 <= lRet);
+            if (0 < lRet)
+            {
+                pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount = 0;
+                InternalLeaveCriticalSection(pthrCurrent, &s_csSynchProcessLock);
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+                pthrCurrent->synchronizationInfo.RunDeferredThreadConditionSignalings();
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+            }
+            return lRet;
+        }
+        static LONG GetLocalSynchLockCount(CPalThread * pthrCurrent)
+        {
+            _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+            return pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount;
+        }
+
+        static void AcquireSharedSynchLock(CPalThread * pthrCurrent)
+        {
+            _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount);
+            _ASSERT_MSG(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount,
+                "The local synch lock should be acquired before grabbing the "
+                "shared one.\n");
+            if (1 == ++pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount)
+            {
+                SHMLock();
+            }
+        }
+        static void ReleaseSharedSynchLock(CPalThread * pthrCurrent)
+        {
+            _ASSERTE(0 < pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount);
+            if (0 == --pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount)
+            {
+                _ASSERT_MSG(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount,
+                    "Final release of the shared synch lock while not holding the "
+                    "local one. Local synch lock should always be acquired first and "
+                    "released last.\n");
+                SHMRelease();
+            }
+        }
+        static LONG ResetSharedSynchLock(CPalThread * pthrCurrent)
+        {
+            LONG lRet = pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount;
+
+            _ASSERTE(0 <= lRet);
+            _ASSERTE(0 == lRet ||
+                     0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+            if (0 < lRet)
+            {
+                pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount = 0;
+                SHMRelease();
+            }
+            return lRet;
+        }
+        static LONG GetSharedSynchLockCount(CPalThread * pthrCurrent)
+        {
+            _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount);
+            _ASSERTE(0 == pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount ||
+                     0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+            return pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount;
+        }
+
+        CSynchWaitController * CacheGetWaitCtrlr(CPalThread * pthrCurrent)
+        {
+            return m_cacheWaitCtrlrs.Get(pthrCurrent);
+        }
+        int CacheGetWaitCtrlr(
+            CPalThread * pthrCurrent,
+            int n,
+            CSynchWaitController * prgCtrlrs[])
+        {
+            return m_cacheWaitCtrlrs.Get(pthrCurrent, n, prgCtrlrs);
+        }
+        void CacheAddWaitCtrlr(
+            CPalThread * pthrCurrent,
+            CSynchWaitController * pCtrlr)
+        {
+            m_cacheWaitCtrlrs.Add(pthrCurrent, pCtrlr);
+        }
+        CSynchStateController * CacheGetStateCtrlr(CPalThread * pthrCurrent)
+        {
+            return m_cacheStateCtrlrs.Get(pthrCurrent);
+        }
+        int CacheGetStateCtrlr(
+            CPalThread * pthrCurrent,
+            int n,
+            CSynchStateController * prgCtrlrs[])
+        {
+            return m_cacheStateCtrlrs.Get(pthrCurrent, n, prgCtrlrs);
+        }
+        void CacheAddStateCtrlr(
+            CPalThread * pthrCurrent,
+            CSynchStateController * pCtrlr)
+        {
+            m_cacheStateCtrlrs.Add(pthrCurrent, pCtrlr);
+        }
+
+        CSynchData * CacheGetLocalSynchData(CPalThread * pthrCurrent)
+        {
+            return m_cacheSynchData.Get(pthrCurrent);
+        }
+        void CacheAddLocalSynchData(
+            CPalThread * pthrCurrent,
+            CSynchData * psdSynchData)
+        {
+            m_cacheSynchData.Add(pthrCurrent, psdSynchData);
+        }
+        SharedID CacheGetSharedSynchData(CPalThread * pthrCurrent)
+        {
+            return m_cacheSHRSynchData.Get(pthrCurrent);
+        }
+        void CacheAddSharedSynchData(
+            CPalThread * pthrCurrent,
+            SharedID shridSData)
+        {
+            m_cacheSHRSynchData.Add(pthrCurrent, shridSData);
+        }
+
+        WaitingThreadsListNode * CacheGetLocalWTListNode(
+            CPalThread * pthrCurrent)
+        {
+            return m_cacheWTListNodes.Get(pthrCurrent);
+        }
+        void CacheAddLocalWTListNode(
+            CPalThread * pthrCurrent,
+            WaitingThreadsListNode * pWTLNode)
+        {
+            m_cacheWTListNodes.Add(pthrCurrent, pWTLNode);
+        }
+        SharedID CacheGetSharedWTListNode(CPalThread * pthrCurrent)
+        {
+            return m_cacheSHRWTListNodes.Get(pthrCurrent);
+        }
+        void CacheAddSharedWTListNode(
+            CPalThread * pthrCurrent,
+            SharedID shridWTLNode)
+        {
+            m_cacheSHRWTListNodes.Add(pthrCurrent, shridWTLNode);
+        }
+
+        OwnedObjectsListNode * CacheGetOwnedObjsListNode(
+            CPalThread * pthrCurrent)
+        {
+            return m_cacheOwnedObjectsListNodes.Get(pthrCurrent);
+        }
+        void CacheAddOwnedObjsListNode(
+            CPalThread * pthrCurrent,
+            OwnedObjectsListNode * pNode)
+        {
+            m_cacheOwnedObjectsListNodes.Add(pthrCurrent, pNode);
+        }
+
+
+        //
+        // IPalSynchronizationManager methods
+        //
+        virtual PAL_ERROR BlockThread(
+            CPalThread *pthrCurrent,
+            DWORD dwTimeout,
+            bool fAlertable,
+            bool fIsSleep,
+            ThreadWakeupReason *ptwrWakeupReason,
+            DWORD *pdwSignaledObject);
+
+        virtual PAL_ERROR AbandonObjectsOwnedByThread(
+            CPalThread *pthrCurrent,
+            CPalThread *pthrTarget);
+
+        virtual PAL_ERROR GetSynchWaitControllersForObjects(
+            CPalThread *pthrCurrent,
+            IPalObject *rgObjects[],
+            DWORD dwObjectCount,
+            ISynchWaitController *rgControllers[]);
+
+        virtual PAL_ERROR GetSynchStateControllersForObjects(
+            CPalThread *pthrCurrent,
+            IPalObject *rgObjects[],
+            DWORD dwObjectCount,
+            ISynchStateController *rgControllers[]);
+
+        virtual PAL_ERROR AllocateObjectSynchData(
+            CObjectType *potObjectType,
+            ObjectDomain odObjectDomain,
+            VOID **ppvSynchData);
+
+        virtual void FreeObjectSynchData(
+            CObjectType *potObjectType,
+            ObjectDomain odObjectDomain,
+            VOID *pvSynchData);
+
+        virtual PAL_ERROR PromoteObjectSynchData(
+            CPalThread *pthrCurrent,
+            VOID *pvLocalSynchData,
+            VOID **ppvSharedSynchData);
+
+        virtual PAL_ERROR CreateSynchStateController(
+            CPalThread *pthrCurrent,
+            CObjectType *potObjectType,
+            VOID *pvSynchData,
+            ObjectDomain odObjectDomain,
+            ISynchStateController **ppStateController);
+
+        virtual PAL_ERROR CreateSynchWaitController(
+            CPalThread *pthrCurrent,
+            CObjectType *potObjectType,
+            VOID *pvSynchData,
+            ObjectDomain odObjectDomain,
+            ISynchWaitController **ppWaitController);
+
+        virtual void AcquireProcessLock(CPalThread *pthrCurrent);
+
+        virtual void ReleaseProcessLock(CPalThread *pthrCurrent);
+
+        //
+        // Static helper methods
+        //
+    public:
+        static PAL_ERROR WakeUpLocalThread(
+            CPalThread * pthrCurrent,
+            CPalThread * pthrTarget,
+            ThreadWakeupReason twrWakeupReason,
+            DWORD dwObjectIndex);
+
+        static PAL_ERROR SignalThreadCondition(
+            ThreadNativeWaitData * ptnwdNativeWaitData);
+
+        static PAL_ERROR DeferThreadConditionSignaling(
+            CPalThread * pthrCurrent,
+            CPalThread * pthrTarget);
+
+        static PAL_ERROR WakeUpRemoteThread(
+            SharedID shridWLNode);
+
+        static PAL_ERROR DelegateSignalingToRemoteProcess(
+            CPalThread * pthrCurrent,
+            DWORD dwTargetProcessId,
+            SharedID shridSynchData);
+
+        static PAL_ERROR SendMsgToRemoteWorker(
+            DWORD dwProcessId,
+            BYTE * pMsg,
+            int iMsgSize);
+
+        static ThreadWaitInfo * GetThreadWaitInfo(
+            CPalThread * pthrCurrent);
+
+        //
+        // The following methods must be called only by a Sync*Controller or
+        // while holding the required synchronization global locks
+        //
+        static void UnsignalRestOfLocalAwakeningWaitAll(
+            CPalThread * pthrCurrent,
+            CPalThread * pthrTarget,
+            WaitingThreadsListNode * pwtlnNode,
+            CSynchData * psdTgtObjectSynchData);
+
+        static void MarkWaitForDelegatedObjectSignalingInProgress(
+            CPalThread * pthrCurrent,
+            WaitingThreadsListNode * pwtlnNode);
+
+        static void UnmarkTWListForDelegatedObjectSignalingInProgress(
+            CSynchData * pTgtObjectSynchData);
+
+        static PAL_ERROR ThreadNativeWait(
+            ThreadNativeWaitData * ptnwdNativeWaitData,
+            DWORD dwTimeout,
+            ThreadWakeupReason * ptwrWakeupReason,
+            DWORD * pdwSignaledObject);
+
+        static void ThreadPrepareForShutdown(void);
+
+#ifndef CORECLR
+        static bool GetProcessPipeName(
+            LPSTR pDest,
+            int iDestSize,
+            DWORD dwPid);
+#endif // !CORECLR
+
+        //
+        // Non-static helper methods
+        //
+    private:
+        LONG DoMonitorProcesses(CPalThread * pthrCurrent);
+
+        void DiscardMonitoredProcesses(CPalThread * pthrCurrent);
+
+        PAL_ERROR ReadCmdFromProcessPipe(
+            int iPollTimeout,
+            SynchWorkerCmd * pswcWorkerCmd,
+            SharedID * pshridMarshaledData,
+            DWORD * pdwData);
+
+        PAL_ERROR WakeUpLocalWorkerThread(
+            SynchWorkerCmd swcWorkerCmd);
+
+        int ReadBytesFromProcessPipe(
+            int iTimeout,
+            BYTE * pRecvBuf,
+            LONG lBytes);
+
+        bool CreateProcessPipe();
+
+        PAL_ERROR ShutdownProcessPipe();
+
+    public:
+        //
+        // The following methods must be called only by a Sync*Controller or
+        // while holding the required synchronization global locks
+        //
+        void UnRegisterWait(
+            CPalThread * pthrCurrent,
+            ThreadWaitInfo * ptwiWaitInfo,
+            bool fHaveSharedLock);
+
+        PAL_ERROR RegisterProcessForMonitoring(
+            CPalThread * pthrCurrent,
+            CSynchData *psdSynchData,
+            IPalObject *pProcessObject,
+            CProcProcessLocalData * pProcLocalData);
+
+        PAL_ERROR UnRegisterProcessForMonitoring(
+            CPalThread * pthrCurrent,
+            CSynchData *psdSynchData,
+            DWORD dwPid);
+
+        //
+        // Utility static methods, no lock required
+        //
+        static bool HasProcessExited(
+            DWORD dwPid,
+            DWORD * pdwExitCode,
+            bool * pfIsActualExitCode);
+
+        static bool InterlockedAwaken(
+            DWORD *pWaitState,
+            bool fAlertOnly);
+
+        static PAL_ERROR GetAbsoluteTimeout(
+            DWORD dwTimeout,
+            struct timespec * ptsAbsTmo,
+            BOOL fPreferMonotonicClock);
+    };
+}
+
+#endif // _SYNCHMANAGER_HPP_
diff --git a/src/pal/src/synchmgr/wait.cpp b/src/pal/src/synchmgr/wait.cpp
new file mode 100644 (file)
index 0000000..1b1206d
--- /dev/null
@@ -0,0 +1,360 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    wait.cpp
+
+Abstract:
+
+    Implementation of waiting functions as described in
+    the WIN32 API
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/synchobjects.hpp"
+#include "pal/handlemgr.hpp"
+#include "pal/mutex.hpp"
+#include "pal/malloc.hpp"
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(SYNC);
+
+#define MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE (MAXIMUM_WAIT_OBJECTS / 4)
+
+using namespace CorUnix;
+
+static PalObjectTypeId sg_rgWaitObjectsIds[] =
+    {
+        otiProcess,
+        otiThread
+    };
+static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds,
+    sizeof(sg_rgWaitObjectsIds)/sizeof(sg_rgWaitObjectsIds[0]));
+
+/*++
+Function:
+  WaitForSingleObject
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+WaitForSingleObject(IN HANDLE hHandle,
+                    IN DWORD dwMilliseconds)
+{
+    DWORD dwRet;
+
+    PERF_ENTRY(WaitForSingleObject);
+    ENTRY("WaitForSingleObject(hHandle=%p, dwMilliseconds=%u)\n",
+          hHandle, dwMilliseconds);
+
+    CPalThread * pThread = InternalGetCurrentThread();
+
+    dwRet = InternalWaitForMultipleObjectsEx(pThread, 1, &hHandle, FALSE,
+                                             dwMilliseconds, FALSE);
+
+    LOGEXIT("WaitForSingleObject returns DWORD %u\n", dwRet);
+    PERF_EXIT(WaitForSingleObject);
+    return dwRet;
+}
+
+DWORD CorUnix::InternalWaitForMultipleObjectsEx(
+    CPalThread * pThread,
+    DWORD nCount,
+    CONST HANDLE *lpHandles,
+    BOOL bWaitAll,
+    DWORD dwMilliseconds,
+    BOOL bAlertable,
+    BOOL bPrioritize)
+{
+    DWORD dwRet = WAIT_FAILED;
+    PAL_ERROR palErr = NO_ERROR;
+    int i, iSignaledObjCount, iSignaledObjIndex = -1;
+    bool fWAll = (bool)bWaitAll, fNeedToBlock  = false;
+    bool fAbandoned = false;
+    WaitType wtWaitType;
+
+    IPalObject            * pIPalObjStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL };
+    ISynchWaitController  * pISyncStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL };
+    IPalObject           ** ppIPalObjs = pIPalObjStackArray;
+    ISynchWaitController ** ppISyncWaitCtrlrs = pISyncStackArray;
+
+    if ((nCount == 0) || (nCount > MAXIMUM_WAIT_OBJECTS))
+    {
+        ppIPalObjs = NULL;        // make delete at the end safe
+        ppISyncWaitCtrlrs = NULL; // make delete at the end safe
+        ERROR("Invalid object count=%d [range: 1 to %d]\n",
+               nCount, MAXIMUM_WAIT_OBJECTS)
+        pThread->SetLastError(ERROR_INVALID_PARAMETER);
+        goto WFMOExIntExit;
+    }
+    else if (nCount == 1)
+    {
+        fWAll = false;  // makes no difference when nCount is 1
+        wtWaitType = SingleObject;
+    }
+    else
+    {
+        wtWaitType = fWAll ? MultipleObjectsWaitAll : MultipleObjectsWaitOne;
+        if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE)
+        {
+            ppIPalObjs = InternalNewArray<IPalObject*>(nCount);
+            ppISyncWaitCtrlrs = InternalNewArray<ISynchWaitController*>(nCount);
+            if ((NULL == ppIPalObjs) || (NULL == ppISyncWaitCtrlrs))
+            {
+                ERROR("Out of memory allocating internal structures\n");
+                pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                goto WFMOExIntExit;
+            }
+        }
+    }
+
+    palErr = g_pObjectManager->ReferenceMultipleObjectsByHandleArray(pThread,
+                                                                     (VOID **)lpHandles,
+                                                                     nCount,
+                                                                     &sg_aotWaitObject,
+                                                                     ppIPalObjs);
+    if (NO_ERROR != palErr)
+    {
+        ERROR("Unable to obtain object for some or all of the handles [error=%u]\n",
+              palErr);
+        if (palErr == ERROR_INVALID_HANDLE)
+            pThread->SetLastError(ERROR_INVALID_HANDLE);
+        else
+            pThread->SetLastError(ERROR_INTERNAL_ERROR);
+        goto WFMOExIntExit;
+    }
+
+    if (nCount > 1)
+    {
+        ERROR("Attempt to wait for any or all handles including a cross-process sync object", ERROR_NOT_SUPPORTED);
+        pThread->SetLastError(ERROR_NOT_SUPPORTED);
+        goto WFMOExIntCleanup;
+    }
+
+    if (fWAll)
+    {
+        // For a wait-all operation, check for duplicate wait objects in the array. This just uses a brute-force O(n^2)
+        // algorithm, but since MAXIMUM_WAIT_OBJECTS is small, the worst case is not so bad, and the average case would involve
+        // significantly fewer items.
+        for (DWORD i = 0; i < nCount - 1; ++i)
+        {
+            IPalObject *const objectToCheck = ppIPalObjs[i];
+            for (DWORD j = i + 1; j < nCount; ++j)
+            {
+                if (ppIPalObjs[j] == objectToCheck)
+                {
+                    ERROR("Duplicate handle provided for a wait-all operation [error=%u]\n", ERROR_INVALID_PARAMETER);
+                    pThread->SetLastError(ERROR_INVALID_PARAMETER);
+                    goto WFMOExIntCleanup;
+                }
+            }
+        }
+    }
+
+    palErr = g_pSynchronizationManager->GetSynchWaitControllersForObjects(
+        pThread, ppIPalObjs, nCount, ppISyncWaitCtrlrs);
+    if (NO_ERROR != palErr)
+    {
+        ERROR("Unable to obtain ISynchWaitController interface for some or all "
+              "of the objects [error=%u]\n", palErr);
+        pThread->SetLastError(ERROR_INTERNAL_ERROR);
+        goto WFMOExIntCleanup;
+    }
+
+    if (bAlertable)
+    {
+        pThread->SetLastError(ERROR_INTERNAL_ERROR);
+        dwRet = WAIT_FAILED;
+        goto WFMOExIntCleanup;
+    }
+
+    iSignaledObjCount = 0;
+    iSignaledObjIndex = -1;
+    for (i=0;i<(int)nCount;i++)
+    {
+        bool fValue, fWaitObjectAbandoned = false;
+        palErr = ppISyncWaitCtrlrs[i]->CanThreadWaitWithoutBlocking(&fValue, &fWaitObjectAbandoned);
+        if (NO_ERROR != palErr)
+        {
+            ERROR("ISynchWaitController::CanThreadWaitWithoutBlocking() failed for "
+                  "%d-th object [handle=%p error=%u]\n", i, lpHandles[i], palErr);
+            pThread->SetLastError(ERROR_INTERNAL_ERROR);
+            goto WFMOExIntReleaseControllers;
+        }
+        if (fWaitObjectAbandoned)
+        {
+            fAbandoned = true;
+        }
+        if (fValue)
+        {
+            iSignaledObjCount++;
+            iSignaledObjIndex = i;
+            if (!fWAll)
+                break;
+        }
+    }
+
+    fNeedToBlock = (iSignaledObjCount == 0) || (fWAll && (iSignaledObjCount < (int)nCount));
+    if (!fNeedToBlock)
+    {
+        // At least one object signaled, or bWaitAll==TRUE and all object signaled.
+        // No need to wait, let's unsignal the object(s) and return without blocking
+        int iStartIdx, iEndIdx;
+
+        if (fWAll)
+        {
+            iStartIdx = 0;
+            iEndIdx = nCount;
+        }
+        else
+        {
+            iStartIdx = iSignaledObjIndex;
+            iEndIdx = iStartIdx + 1;
+        }
+
+        // Unsignal objects
+        if( iStartIdx < 0 )
+        {
+            ERROR("Buffer underflow due to iStartIdx < 0");
+            pThread->SetLastError(ERROR_INTERNAL_ERROR);
+            dwRet = WAIT_FAILED;
+            goto WFMOExIntCleanup;
+        }
+        for (i = iStartIdx; i < iEndIdx; i++)
+        {
+            palErr = ppISyncWaitCtrlrs[i]->ReleaseWaitingThreadWithoutBlocking();
+            if (NO_ERROR != palErr)
+            {
+                ERROR("ReleaseWaitingThreadWithoutBlocking() failed for %d-th "
+                      "object [handle=%p error=%u]\n",
+                      i, lpHandles[i], palErr);
+                pThread->SetLastError(palErr);
+                goto WFMOExIntReleaseControllers;
+            }
+        }
+
+        dwRet = (fAbandoned ? WAIT_ABANDONED_0 : WAIT_OBJECT_0);
+    }
+    else if (0 == dwMilliseconds)
+    {
+        // Not enough objects signaled, but timeout is zero: no actual wait
+        dwRet = WAIT_TIMEOUT;
+        fNeedToBlock = false;
+    }
+    else
+    {
+        // Register the thread for waiting on all objects
+        for (i=0;i<(int)nCount;i++)
+        {
+            palErr = ppISyncWaitCtrlrs[i]->RegisterWaitingThread(
+                                                        wtWaitType,
+                                                        i,
+                                                        (TRUE == bAlertable),
+                                                        bPrioritize != FALSE);
+            if (NO_ERROR != palErr)
+            {
+                ERROR("RegisterWaitingThread() failed for %d-th object "
+                      "[handle=%p error=%u]\n", i, lpHandles[i], palErr);
+                pThread->SetLastError(palErr);
+                goto WFMOExIntReleaseControllers;
+            }
+        }
+    }
+
+WFMOExIntReleaseControllers:
+    // Release all controllers before going to sleep
+    for (i = 0; i < (int)nCount; i++)
+    {
+        ppISyncWaitCtrlrs[i]->ReleaseController();
+        ppISyncWaitCtrlrs[i] = NULL;
+    }
+    if (NO_ERROR != palErr)
+        goto WFMOExIntCleanup;
+
+    if (fNeedToBlock)
+    {
+        ThreadWakeupReason twrWakeupReason;
+
+        //
+        // Going to sleep
+        //
+        palErr = g_pSynchronizationManager->BlockThread(pThread,
+                                                        dwMilliseconds,
+                                                        (TRUE == bAlertable),
+                                                        false,
+                                                        &twrWakeupReason,
+                                                        (DWORD *)&iSignaledObjIndex);
+        //
+        // Awakened
+        //
+        if (NO_ERROR != palErr)
+        {
+            ERROR("IPalSynchronizationManager::BlockThread failed for thread "
+                  "pThread=%p [error=%u]\n", pThread, palErr);
+            pThread->SetLastError(palErr);
+            goto WFMOExIntCleanup;
+        }
+        switch (twrWakeupReason)
+        {
+        case WaitSucceeded:
+            dwRet = WAIT_OBJECT_0; // offset added later
+            break;
+        case MutexAbondoned:
+            dwRet =  WAIT_ABANDONED_0; // offset added later
+            break;
+        case WaitTimeout:
+            dwRet = WAIT_TIMEOUT;
+            break;
+        case WaitFailed:
+        default:
+            ERROR("Thread %p awakened with some failure\n", pThread);
+            dwRet = WAIT_FAILED;
+            break;
+        }
+    }
+
+    if (!fWAll && ((WAIT_OBJECT_0 == dwRet) || (WAIT_ABANDONED_0 == dwRet)))
+    {
+        _ASSERT_MSG(0 <= iSignaledObjIndex,
+                    "Failed to identify signaled/abandoned object\n");
+        _ASSERT_MSG(iSignaledObjIndex >= 0 && nCount > static_cast<DWORD>(iSignaledObjIndex),
+                    "SignaledObjIndex object out of range "
+                    "[index=%d obj_count=%u\n",
+                    iSignaledObjCount, nCount);
+
+        if (iSignaledObjIndex < 0)
+        {
+            pThread->SetLastError(ERROR_INTERNAL_ERROR);
+            dwRet = WAIT_FAILED;
+            goto WFMOExIntCleanup;
+        }
+        dwRet += iSignaledObjIndex;
+    }
+
+WFMOExIntCleanup:
+    for (i = 0; i < (int)nCount; i++)
+    {
+        ppIPalObjs[i]->ReleaseReference(pThread);
+        ppIPalObjs[i] = NULL;
+    }
+
+WFMOExIntExit:
+    if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE)
+    {
+        InternalDeleteArray(ppIPalObjs);
+        InternalDeleteArray(ppISyncWaitCtrlrs);
+    }
+
+    return dwRet;
+}
diff --git a/src/pal/src/synchobj/mutex.cpp b/src/pal/src/synchobj/mutex.cpp
new file mode 100644 (file)
index 0000000..4212522
--- /dev/null
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+Module Name:
+
+    mutex.cpp
+
+Abstract:
+
+    Implementation of mutex synchroniztion object as described in
+    the WIN32 API
+
+Revision History:
+
+--*/
+
+#include "pal/mutex.hpp"
+
+/* Basic spinlock implementation */
+void SPINLOCKAcquire (LONG * lock, unsigned int flags)
+{
+    size_t loop_seed = 1, loop_count = 0;
+
+    if (flags & SYNCSPINLOCK_F_ASYMMETRIC)
+    {
+        loop_seed = ((size_t)pthread_self() % 10) + 1;
+    }
+    while (InterlockedCompareExchange(lock, 1, 0))
+    {
+        if (!(flags & SYNCSPINLOCK_F_ASYMMETRIC) || (++loop_count % loop_seed))
+        {
+#if PAL_IGNORE_NORMAL_THREAD_PRIORITY
+            struct timespec tsSleepTime;
+            tsSleepTime.tv_sec = 0;
+            tsSleepTime.tv_nsec = 1;
+            nanosleep(&tsSleepTime, NULL);
+#else
+            sched_yield();
+#endif
+        }
+    }
+
+}
+
+void SPINLOCKRelease (LONG * lock)
+{
+    VolatileStore(lock, 0);
+}
+
+DWORD SPINLOCKTryAcquire (LONG * lock)
+{
+    return InterlockedCompareExchange(lock, 1, 0);
+    // only returns 0 or 1.
+}
diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp
new file mode 100644 (file)
index 0000000..294c12f
--- /dev/null
@@ -0,0 +1,3661 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+Module Name:
+
+    process.cpp
+
+Abstract:
+
+    Implementation of process object and functions related to processes.
+
+--*/
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so do this first
+
+#include "pal/procobj.hpp"
+#include "pal/thread.hpp"
+#include "pal/file.hpp"
+#include "pal/handlemgr.hpp"
+#include "pal/module.h"
+#include "procprivate.hpp"
+#include "pal/palinternal.h"
+#include "pal/process.h"
+#include "pal/init.h"
+#include "pal/critsect.h"
+#include "pal/debug.h"
+#include "pal/utils.h"
+#include "pal/environ.h"
+#include "pal/virtual.h"
+#include "pal/stackstring.hpp"
+
+#include <errno.h>
+#if HAVE_POLL
+#include <poll.h>
+#else
+#include "pal/fakepoll.h"
+#endif  // HAVE_POLL
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#if HAVE_PRCTL_H
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#endif
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <debugmacrosext.h>
+#include <semaphore.h>
+#include <stdint.h>
+#include <dlfcn.h>
+#include <limits.h>
+#include <vector>
+
+#ifdef __linux__
+#include <sys/syscall.h> // __NR_membarrier
+// Ensure __NR_membarrier is defined for portable builds.
+# if !defined(__NR_membarrier)
+#  if defined(__amd64__)
+#   define __NR_membarrier  324
+#  elif defined(__i386__)
+#   define __NR_membarrier  375
+#  elif defined(__arm__)
+#   define __NR_membarrier  389
+#  elif defined(__aarch64__)
+#   define __NR_membarrier  283
+#  else
+#   error Unknown architecture
+#  endif
+# endif
+#endif
+
+#ifdef __APPLE__
+#include <libproc.h>
+#include <sys/sysctl.h>
+#include <sys/posix_sem.h>
+#include <mach/task.h>
+#include <mach/vm_map.h>
+extern "C"
+{
+    #include <mach/thread_state.h>
+}
+#endif // __APPLE__
+
+#ifdef __NetBSD__
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <kvm.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#endif
+
+extern char *g_szCoreCLRPath;
+
+using namespace CorUnix;
+
+CObjectType CorUnix::otProcess(
+                otiProcess,
+                NULL,   // No cleanup routine
+                NULL,   // No initialization routine
+                0,      // No immutable data
+                NULL,   // No immutable data copy routine
+                NULL,   // No immutable data cleanup routine
+                sizeof(CProcProcessLocalData),
+                NULL,   // No process local data cleanup routine
+                0,      // No shared data
+                PROCESS_ALL_ACCESS,
+                CObjectType::SecuritySupported,
+                CObjectType::SecurityInfoNotPersisted,
+                CObjectType::UnnamedObject,
+                CObjectType::CrossProcessDuplicationAllowed,
+                CObjectType::WaitableObject,
+                CObjectType::SingleTransitionObject,
+                CObjectType::ThreadReleaseHasNoSideEffects,
+                CObjectType::NoOwner
+                );
+
+//
+// Helper membarrier function
+//
+#ifdef __NR_membarrier
+# define membarrier(...)  syscall(__NR_membarrier, __VA_ARGS__)
+#else
+# define membarrier(...)  -ENOSYS
+#endif
+
+enum membarrier_cmd
+{
+    MEMBARRIER_CMD_QUERY                                 = 0,
+    MEMBARRIER_CMD_GLOBAL                                = (1 << 0),
+    MEMBARRIER_CMD_GLOBAL_EXPEDITED                      = (1 << 1),
+    MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED             = (1 << 2),
+    MEMBARRIER_CMD_PRIVATE_EXPEDITED                     = (1 << 3),
+    MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED            = (1 << 4),
+    MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE           = (1 << 5),
+    MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE  = (1 << 6)
+};
+
+//
+// Tracks if the OS supports FlushProcessWriteBuffers using membarrier
+//
+static int s_flushUsingMemBarrier = 0;
+
+//
+// Helper memory page used by the FlushProcessWriteBuffers
+//
+static int* s_helperPage = 0;
+
+//
+// Mutex to make the FlushProcessWriteBuffersMutex thread safe
+//
+pthread_mutex_t flushProcessWriteBuffersMutex;
+
+CAllowedObjectTypes aotProcess(otiProcess);
+
+//
+// The representative IPalObject for this process
+//
+IPalObject* CorUnix::g_pobjProcess;
+
+//
+// Critical section that protects process data (e.g., the
+// list of active threads)/
+//
+CRITICAL_SECTION g_csProcess;
+
+//
+// List and count of active threads
+//
+CPalThread* CorUnix::pGThreadList;
+DWORD g_dwThreadCount;
+
+//
+// The command line and app name for the process
+//
+LPWSTR g_lpwstrCmdLine = NULL;
+LPWSTR g_lpwstrAppDir = NULL;
+
+// Thread ID of thread that has started the ExitProcess process
+Volatile<LONG> terminator = 0;
+
+// Process and session ID of this process.
+DWORD gPID = (DWORD) -1;
+DWORD gSID = (DWORD) -1;
+
+// The lowest common supported semaphore length, including null character
+// NetBSD-7.99.25: 15 characters
+// MacOSX 10.11: 31 -- Core 1.0 RC2 compatibility
+#if defined(__NetBSD__)
+#define CLR_SEM_MAX_NAMELEN 15
+#elif defined(__APPLE__)
+#define CLR_SEM_MAX_NAMELEN PSEMNAMLEN
+#elif defined(NAME_MAX)
+#define CLR_SEM_MAX_NAMELEN (NAME_MAX - 4)
+#else
+// On Solaris, MAXNAMLEN is 512, which is higher than MAX_PATH defined by pal.h
+#define CLR_SEM_MAX_NAMELEN MAX_PATH
+#endif
+
+static_assert_no_msg(CLR_SEM_MAX_NAMELEN <= MAX_PATH);
+
+//
+// Key used for associating CPalThread's with the underlying pthread
+// (through pthread_setspecific)
+//
+pthread_key_t CorUnix::thObjKey;
+
+static WCHAR W16_WHITESPACE[]= {0x0020, 0x0009, 0x000D, 0};
+static WCHAR W16_WHITESPACE_DQUOTE[]= {0x0020, 0x0009, 0x000D, '"', 0};
+
+enum FILETYPE
+{
+    FILE_ERROR,/*ERROR*/
+    FILE_UNIX, /*Unix Executable*/
+    FILE_DIR   /*Directory*/
+};
+
+#pragma pack(push,1)
+// When creating the semaphore name on Mac running in a sandbox, We reference this structure as a byte array
+// in order to encode its data into a string. Its important to make sure there is no padding between the fields
+// and also at the end of the buffer. Hence, this structure is defined inside a pack(1)
+struct UnambiguousProcessDescriptor
+{
+    UnambiguousProcessDescriptor()
+    {
+    }
+
+    UnambiguousProcessDescriptor(DWORD processId, UINT64 disambiguationKey)
+    {
+        Init(processId, disambiguationKey);
+    }
+
+    void Init(DWORD processId, UINT64 disambiguationKey)
+    {
+        m_processId = processId;
+        m_disambiguationKey = disambiguationKey;
+    }
+    UINT64 m_disambiguationKey;
+    DWORD m_processId;
+};
+#pragma pack(pop)
+
+static
+DWORD
+StartupHelperThread(
+    LPVOID p);
+
+static
+BOOL
+GetProcessIdDisambiguationKey(
+    IN DWORD processId,
+    OUT UINT64 *disambiguationKey);
+
+static
+void
+CreateSemaphoreName(
+    char semName[CLR_SEM_MAX_NAMELEN],
+    LPCSTR semaphoreName,
+    const UnambiguousProcessDescriptor& unambiguousProcessDescriptor,
+    LPCSTR applicationGroupId);
+
+static BOOL getFileName(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, PathCharString& lpFileName);
+static char ** buildArgv(LPCWSTR lpCommandLine, PathCharString& lpAppPath, UINT *pnArg);
+static BOOL getPath(PathCharString& lpFileName, PathCharString& lpPathFileName);
+static int checkFileType(LPCSTR lpFileName);
+static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUnconditionally);
+
+ProcessModules *GetProcessModulesFromHandle(IN HANDLE hProcess, OUT LPDWORD lpCount);
+ProcessModules *CreateProcessModules(IN DWORD dwProcessId, OUT LPDWORD lpCount);
+void DestroyProcessModules(IN ProcessModules *listHead);
+
+/*++
+Function:
+  GetCurrentProcessId
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetCurrentProcessId(
+            VOID)
+{
+    PERF_ENTRY(GetCurrentProcessId);
+    ENTRY("GetCurrentProcessId()\n" );
+
+    LOGEXIT("GetCurrentProcessId returns DWORD %#x\n", gPID);
+    PERF_EXIT(GetCurrentProcessId);
+    return gPID;
+}
+
+
+/*++
+Function:
+  GetCurrentSessionId
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetCurrentSessionId(
+            VOID)
+{
+    PERF_ENTRY(GetCurrentSessionId);
+    ENTRY("GetCurrentSessionId()\n" );
+
+    LOGEXIT("GetCurrentSessionId returns DWORD %#x\n", gSID);
+    PERF_EXIT(GetCurrentSessionId);
+    return gSID;
+}
+
+
+/*++
+Function:
+  GetCurrentProcess
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+GetCurrentProcess(
+          VOID)
+{
+    PERF_ENTRY(GetCurrentProcess);
+    ENTRY("GetCurrentProcess()\n" );
+
+    LOGEXIT("GetCurrentProcess returns HANDLE %p\n", hPseudoCurrentProcess);
+    PERF_EXIT(GetCurrentProcess);
+
+    /* return a pseudo handle */
+    return hPseudoCurrentProcess;
+}
+
+/*++
+Function:
+  CreateProcessW
+
+Note:
+  Only Standard handles need to be inherited.
+  Security attributes parameters are not used.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+CreateProcessW(
+           IN LPCWSTR lpApplicationName,
+           IN LPWSTR lpCommandLine,
+           IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
+           IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+           IN BOOL bInheritHandles,
+           IN DWORD dwCreationFlags,
+           IN LPVOID lpEnvironment,
+           IN LPCWSTR lpCurrentDirectory,
+           IN LPSTARTUPINFOW lpStartupInfo,
+           OUT LPPROCESS_INFORMATION lpProcessInformation)
+{
+    PAL_ERROR palError = NO_ERROR;
+    CPalThread *pThread;
+
+    PERF_ENTRY(CreateProcessW);
+    ENTRY("CreateProcessW(lpAppName=%p (%S), lpCmdLine=%p (%S), lpProcessAttr=%p,"
+           "lpThreadAttr=%p, bInherit=%d, dwFlags=%#x, lpEnv=%p,"
+           "lpCurrentDir=%p (%S), lpStartupInfo=%p, lpProcessInfo=%p)\n",
+           lpApplicationName?lpApplicationName:W16_NULLSTRING,
+           lpApplicationName?lpApplicationName:W16_NULLSTRING,
+           lpCommandLine?lpCommandLine:W16_NULLSTRING,
+           lpCommandLine?lpCommandLine:W16_NULLSTRING,lpProcessAttributes,
+           lpThreadAttributes, bInheritHandles, dwCreationFlags,lpEnvironment,
+           lpCurrentDirectory?lpCurrentDirectory:W16_NULLSTRING,
+           lpCurrentDirectory?lpCurrentDirectory:W16_NULLSTRING,
+           lpStartupInfo, lpProcessInformation);
+
+    pThread = InternalGetCurrentThread();
+
+    palError = InternalCreateProcess(
+        pThread,
+        lpApplicationName,
+        lpCommandLine,
+        lpProcessAttributes,
+        lpThreadAttributes,
+        dwCreationFlags,
+        lpEnvironment,
+        lpCurrentDirectory,
+        lpStartupInfo,
+        lpProcessInformation
+        );
+
+    if (NO_ERROR != palError)
+    {
+        pThread->SetLastError(palError);
+    }
+
+    LOGEXIT("CreateProcessW returns BOOL %d\n", NO_ERROR == palError);
+    PERF_EXIT(CreateProcessW);
+
+    return NO_ERROR == palError;
+}
+
+PAL_ERROR
+PrepareStandardHandle(
+    CPalThread *pThread,
+    HANDLE hFile,
+    IPalObject **ppobjFile,
+    int *piFd
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    IPalObject *pobjFile = NULL;
+    IDataLock *pDataLock = NULL;
+    CFileProcessLocalData *pLocalData = NULL;
+    int iError = 0;
+
+    palError = g_pObjectManager->ReferenceObjectByHandle(
+        pThread,
+        hFile,
+        &aotFile,
+        &pobjFile
+        );
+
+    if (NO_ERROR != palError)
+    {
+        ERROR("Bad handle passed through CreateProcess\n");
+        goto PrepareStandardHandleExit;
+    }
+
+    palError = pobjFile->GetProcessLocalData(
+        pThread,
+        ReadLock,
+        &pDataLock,
+        reinterpret_cast<void **>(&pLocalData)
+        );
+
+    if (NO_ERROR != palError)
+    {
+        ASSERT("Unable to access file data\n");
+        goto PrepareStandardHandleExit;
+    }
+
+    //
+    // The passed in file needs to be inheritable
+    //
+
+    if (!pLocalData->inheritable)
+    {
+        ERROR("Non-inheritable handle passed through CreateProcess\n");
+        palError = ERROR_INVALID_HANDLE;
+        goto PrepareStandardHandleExit;
+    }
+
+    iError = fcntl(pLocalData->unix_fd, F_SETFD, 0);
+    if (-1 == iError)
+    {
+        ERROR("Unable to remove close-on-exec for file (errno %i)\n", errno);
+        palError = ERROR_INVALID_HANDLE;
+        goto PrepareStandardHandleExit;
+    }
+
+    *piFd = pLocalData->unix_fd;
+    pDataLock->ReleaseLock(pThread, FALSE);
+    pDataLock = NULL;
+
+    //
+    // Transfer pobjFile reference to out parameter
+    //
+
+    *ppobjFile = pobjFile;
+    pobjFile = NULL;
+
+PrepareStandardHandleExit:
+
+    if (NULL != pDataLock)
+    {
+        pDataLock->ReleaseLock(pThread, FALSE);
+    }
+
+    if (NULL != pobjFile)
+    {
+        pobjFile->ReleaseReference(pThread);
+    }
+
+    return palError;
+}
+
+PAL_ERROR
+CorUnix::InternalCreateProcess(
+    CPalThread *pThread,
+    LPCWSTR lpApplicationName,
+    LPWSTR lpCommandLine,
+    LPSECURITY_ATTRIBUTES lpProcessAttributes,
+    LPSECURITY_ATTRIBUTES lpThreadAttributes,
+    DWORD dwCreationFlags,
+    LPVOID lpEnvironment,
+    LPCWSTR lpCurrentDirectory,
+    LPSTARTUPINFOW lpStartupInfo,
+    LPPROCESS_INFORMATION lpProcessInformation
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    IPalObject *pobjProcess = NULL;
+    IPalObject *pobjProcessRegistered = NULL;
+    IDataLock *pLocalDataLock = NULL;
+    CProcProcessLocalData *pLocalData;
+    IDataLock *pSharedDataLock = NULL;
+    CPalThread *pDummyThread = NULL;
+    HANDLE hDummyThread = NULL;
+    HANDLE hProcess = NULL;
+    CObjectAttributes oa(NULL, lpProcessAttributes);
+
+    IPalObject *pobjFileIn = NULL;
+    int iFdIn = -1;
+    IPalObject *pobjFileOut = NULL;
+    int iFdOut = -1;
+    IPalObject *pobjFileErr = NULL;
+    int iFdErr = -1;
+
+    pid_t processId;
+    PathCharString lpFileNamePS;
+    char **lppArgv = NULL;
+    UINT nArg;
+    int  iRet;
+    char **EnvironmentArray=NULL;
+    int child_blocking_pipe = -1;
+    int parent_blocking_pipe = -1;
+
+    /* Validate parameters */
+
+    /* note : specs indicate lpApplicationName should always
+       be NULL; however support for it is already implemented. Leaving the code
+       in, specs can change; but rejecting non-NULL for now to conform to the
+       spec. */
+    if( NULL != lpApplicationName )
+    {
+        ASSERT("lpApplicationName should be NULL, but is %S instead\n",
+               lpApplicationName);
+        palError = ERROR_INVALID_PARAMETER;
+        goto InternalCreateProcessExit;
+    }
+
+    if (0 != (dwCreationFlags & ~(CREATE_SUSPENDED|CREATE_NEW_CONSOLE)))
+    {
+        ASSERT("Unexpected creation flags (%#x)\n", dwCreationFlags);
+        palError = ERROR_INVALID_PARAMETER;
+        goto InternalCreateProcessExit;
+    }
+
+    /* Security attributes parameters are ignored */
+    if (lpProcessAttributes != NULL &&
+        (lpProcessAttributes->lpSecurityDescriptor != NULL ||
+         lpProcessAttributes->bInheritHandle != TRUE))
+    {
+        ASSERT("lpProcessAttributes is invalid, parameter ignored (%p)\n",
+               lpProcessAttributes);
+        palError = ERROR_INVALID_PARAMETER;
+        goto InternalCreateProcessExit;
+    }
+
+    if (lpThreadAttributes != NULL)
+    {
+        ASSERT("lpThreadAttributes parameter must be NULL (%p)\n",
+               lpThreadAttributes);
+        palError = ERROR_INVALID_PARAMETER;
+        goto InternalCreateProcessExit;
+    }
+
+    /* note : Win32 crashes in this case */
+    if(NULL == lpStartupInfo)
+    {
+        ERROR("lpStartupInfo is NULL\n");
+        palError = ERROR_INVALID_PARAMETER;
+        goto InternalCreateProcessExit;
+    }
+
+    /* Validate lpStartupInfo.cb field */
+    if (lpStartupInfo->cb < sizeof(STARTUPINFOW))
+    {
+        ASSERT("lpStartupInfo parameter structure size is invalid (%u)\n",
+              lpStartupInfo->cb);
+        palError = ERROR_INVALID_PARAMETER;
+        goto InternalCreateProcessExit;
+    }
+
+    /* lpStartupInfo should be either zero or STARTF_USESTDHANDLES */
+    if (lpStartupInfo->dwFlags & ~STARTF_USESTDHANDLES)
+    {
+        ASSERT("lpStartupInfo parameter invalid flags (%#x)\n",
+              lpStartupInfo->dwFlags);
+        palError = ERROR_INVALID_PARAMETER;
+        goto InternalCreateProcessExit;
+    }
+
+    /* validate given standard handles if we have any */
+    if (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)
+    {
+        palError = PrepareStandardHandle(
+            pThread,
+            lpStartupInfo->hStdInput,
+            &pobjFileIn,
+            &iFdIn
+            );
+
+        if (NO_ERROR != palError)
+        {
+            goto InternalCreateProcessExit;
+        }
+
+        palError = PrepareStandardHandle(
+            pThread,
+            lpStartupInfo->hStdOutput,
+            &pobjFileOut,
+            &iFdOut
+            );
+
+        if (NO_ERROR != palError)
+        {
+            goto InternalCreateProcessExit;
+        }
+
+        palError = PrepareStandardHandle(
+            pThread,
+            lpStartupInfo->hStdError,
+            &pobjFileErr,
+            &iFdErr
+            );
+
+        if (NO_ERROR != palError)
+        {
+            goto InternalCreateProcessExit;
+        }
+    }
+
+    if (!getFileName(lpApplicationName, lpCommandLine, lpFileNamePS))
+    {
+        ERROR("Can't find executable!\n");
+        palError = ERROR_FILE_NOT_FOUND;
+        goto InternalCreateProcessExit;
+    }
+
+    /* check type of file */
+    iRet = checkFileType(lpFileNamePS);
+
+    switch (iRet)
+    {
+        case FILE_ERROR: /* file not found, or not an executable */
+            WARN ("File is not valid (%s)", lpFileNamePS.GetString());
+            palError = ERROR_FILE_NOT_FOUND;
+            goto InternalCreateProcessExit;
+
+        case FILE_UNIX: /* Unix binary file */
+            break;  /* nothing to do */
+
+        case FILE_DIR:/*Directory*/
+            WARN ("File is a Directory (%s)", lpFileNamePS.GetString());
+            palError = ERROR_ACCESS_DENIED;
+            goto InternalCreateProcessExit;
+            break;
+
+        default: /* not supposed to get here */
+            ASSERT ("Invalid return type from checkFileType");
+            palError = ERROR_FILE_NOT_FOUND;
+            goto InternalCreateProcessExit;
+    }
+
+    /* build Argument list, lppArgv is allocated in buildArgv function and
+       requires to be freed */
+    lppArgv = buildArgv(lpCommandLine, lpFileNamePS, &nArg);
+
+    /* set the Environment variable */
+    if (lpEnvironment != NULL)
+    {
+        unsigned i;
+        // Since CREATE_UNICODE_ENVIRONMENT isn't supported we know the string is ansi
+        unsigned EnvironmentEntries = 0;
+        // Convert the environment block to array of strings
+        // Count the number of entries
+        // Is it a string that contains null terminated string, the end is delimited
+        // by two null in a row.
+        for (i = 0; ((char *)lpEnvironment)[i]!='\0'; i++)
+        {
+            EnvironmentEntries ++;
+            for (;((char *)lpEnvironment)[i]!='\0'; i++)
+            {
+            }
+        }
+        EnvironmentEntries++;
+        EnvironmentArray = (char **)InternalMalloc(EnvironmentEntries * sizeof(char *));
+
+        EnvironmentEntries = 0;
+        // Convert the environment block to array of strings
+        // Count the number of entries
+        // Is it a string that contains null terminated string, the end is delimited
+        // by two null in a row.
+        for (i = 0; ((char *)lpEnvironment)[i]!='\0'; i++)
+        {
+            EnvironmentArray[EnvironmentEntries] = &((char *)lpEnvironment)[i];
+            EnvironmentEntries ++;
+            for (;((char *)lpEnvironment)[i]!='\0'; i++)
+            {
+            }
+        }
+        EnvironmentArray[EnvironmentEntries] = NULL;
+    }
+
+    //
+    // Allocate and register the process object for the new process
+    //
+
+    palError = g_pObjectManager->AllocateObject(
+        pThread,
+        &otProcess,
+        &oa,
+        &pobjProcess
+        );
+
+    if (NO_ERROR != palError)
+    {
+        ERROR("Unable to allocate object for new proccess\n");
+        goto InternalCreateProcessExit;
+    }
+
+    palError = g_pObjectManager->RegisterObject(
+        pThread,
+        pobjProcess,
+        &aotProcess,
+        &hProcess,
+        &pobjProcessRegistered
+        );
+
+    //
+    // pobjProcess is invalidated by the above call, so
+    // NULL it out here
+    //
+
+    pobjProcess = NULL;
+
+    if (NO_ERROR != palError)
+    {
+        ERROR("Unable to register new process object\n");
+        goto InternalCreateProcessExit;
+    }
+
+    //
+    // Create a new "dummy" thread object
+    //
+
+    palError = InternalCreateDummyThread(
+        pThread,
+        lpThreadAttributes,
+        &pDummyThread,
+        &hDummyThread
+        );
+
+    if (dwCreationFlags & CREATE_SUSPENDED)
+    {
+        int pipe_descs[2];
+
+        if (-1 == pipe(pipe_descs))
+        {
+            ERROR("pipe() failed! error is %d (%s)\n", errno, strerror(errno));
+            palError = ERROR_NOT_ENOUGH_MEMORY;
+            goto InternalCreateProcessExit;
+        }
+
+        /* [0] is read end, [1] is write end */
+        pDummyThread->suspensionInfo.SetBlockingPipe(pipe_descs[1]);
+        parent_blocking_pipe = pipe_descs[1];
+        child_blocking_pipe = pipe_descs[0];
+    }
+
+    palError = pobjProcessRegistered->GetProcessLocalData(
+        pThread,
+        WriteLock,
+        &pLocalDataLock,
+        reinterpret_cast<void **>(&pLocalData)
+        );
+
+    if (NO_ERROR != palError)
+    {
+        ASSERT("Unable to obtain local data for new process object\n");
+        goto InternalCreateProcessExit;
+    }
+
+
+    /* fork the new process */
+    processId = fork();
+
+    if (processId == -1)
+    {
+        ASSERT("Unable to create a new process with fork()\n");
+        if (-1 != child_blocking_pipe)
+        {
+            close(child_blocking_pipe);
+            close(parent_blocking_pipe);
+        }
+
+        palError = ERROR_INTERNAL_ERROR;
+        goto InternalCreateProcessExit;
+    }
+
+    /* From the time the child process begins running, to when it reaches execve,
+    the child process is not a real PAL process and does not own any PAL
+    resources, although it has access to the PAL resources of its parent process.
+    Thus, while the child process is in this window, it is dangerous for it to affect
+    its parent's PAL resources. As a consequence, no PAL code should be used
+    in this window; all code should make unix calls. Note the use of _exit
+    instead of exit to avoid calling PAL_Terminate and the lack of TRACE's and
+    ASSERT's. */
+
+    if (processId == 0)  /* child process */
+    {
+        // At this point, the PAL should be considered uninitialized for this child process.
+
+        // Don't want to enter the init_critsec here since we're trying to avoid
+        // calling PAL functions. Furthermore, nothing should be changing
+        // the init_count in the child process at this point since this is the only
+        // thread executing.
+        init_count = 0;
+
+        sigset_t sm;
+
+        //
+        // Clear out the signal mask for the new process.
+        //
+
+        sigemptyset(&sm);
+        iRet = sigprocmask(SIG_SETMASK, &sm, NULL);
+        if (iRet != 0)
+        {
+            _exit(EXIT_FAILURE);
+        }
+
+        if (dwCreationFlags & CREATE_SUSPENDED)
+        {
+            BYTE resume_code = 0;
+            ssize_t read_ret;
+
+            /* close the write end of the pipe, the child doesn't need it */
+            close(parent_blocking_pipe);
+
+            read_again:
+            /* block until ResumeThread writes something to the pipe */
+            read_ret = read(child_blocking_pipe, &resume_code, sizeof(resume_code));
+            if (sizeof(resume_code) != read_ret)
+            {
+                if (read_ret == -1 && EINTR == errno)
+                {
+                    goto read_again;
+                }
+                else
+                {
+                    /* note : read might return 0 (and return EAGAIN) if the other
+                       end of the pipe gets closed - for example because the parent
+                       process dies (very) abruptly */
+                    _exit(EXIT_FAILURE);
+                }
+            }
+            if (WAKEUPCODE != resume_code)
+            {
+                // resume_code should always equal WAKEUPCODE.
+                _exit(EXIT_FAILURE);
+            }
+
+            close(child_blocking_pipe);
+        }
+
+        /* Set the current directory */
+        if (lpCurrentDirectory)
+        {
+            SetCurrentDirectoryW(lpCurrentDirectory);
+        }
+
+        /* Set the standard handles to the incoming values */
+        if (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)
+        {
+            /* For each handle, we need to duplicate the incoming unix
+               fd to the corresponding standard one.  The API that I use,
+               dup2, will copy the source to the destination, automatically
+               closing the existing destination, in an atomic way */
+            if (dup2(iFdIn, STDIN_FILENO) == -1)
+            {
+                // Didn't duplicate standard in.
+                _exit(EXIT_FAILURE);
+            }
+
+            if (dup2(iFdOut, STDOUT_FILENO) == -1)
+            {
+                // Didn't duplicate standard out.
+                _exit(EXIT_FAILURE);
+            }
+
+            if (dup2(iFdErr, STDERR_FILENO) == -1)
+            {
+                // Didn't duplicate standard error.
+                _exit(EXIT_FAILURE);
+            }
+
+            /* now close the original FDs, we don't need them anymore */
+            close(iFdIn);
+            close(iFdOut);
+            close(iFdErr);
+        }
+
+        /* execute the new process */
+
+        if (EnvironmentArray)
+        {
+            execve(lpFileNamePS, lppArgv, EnvironmentArray);
+        }
+        else
+        {
+            execve(lpFileNamePS, lppArgv, palEnvironment);
+        }
+
+        /* if we get here, it means the execve function call failed so just exit */
+        _exit(EXIT_FAILURE);
+    }
+
+    /* parent process */
+
+    /* close the read end of the pipe, the parent doesn't need it */
+    close(child_blocking_pipe);
+
+    /* Set the process ID */
+    pLocalData->dwProcessId = processId;
+    pLocalDataLock->ReleaseLock(pThread, TRUE);
+    pLocalDataLock = NULL;
+
+    //
+    // Release file handle info; we don't need them anymore. Note that
+    // this must happen after we've released the data locks, as
+    // otherwise a deadlock could result.
+    //
+
+    if (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)
+    {
+        pobjFileIn->ReleaseReference(pThread);
+        pobjFileIn = NULL;
+        pobjFileOut->ReleaseReference(pThread);
+        pobjFileOut = NULL;
+        pobjFileErr->ReleaseReference(pThread);
+        pobjFileErr = NULL;
+    }
+
+    /* fill PROCESS_INFORMATION strucutre */
+    lpProcessInformation->hProcess = hProcess;
+    lpProcessInformation->hThread = hDummyThread;
+    lpProcessInformation->dwProcessId = processId;
+    lpProcessInformation->dwThreadId_PAL_Undefined = 0;
+
+
+    TRACE("New process created: id=%#x\n", processId);
+
+InternalCreateProcessExit:
+
+    if (NULL != pLocalDataLock)
+    {
+        pLocalDataLock->ReleaseLock(pThread, FALSE);
+    }
+
+    if (NULL != pSharedDataLock)
+    {
+        pSharedDataLock->ReleaseLock(pThread, FALSE);
+    }
+
+    if (NULL != pobjProcess)
+    {
+        pobjProcess->ReleaseReference(pThread);
+    }
+
+    if (NULL != pobjProcessRegistered)
+    {
+        pobjProcessRegistered->ReleaseReference(pThread);
+    }
+
+    if (NO_ERROR != palError)
+    {
+        if (NULL != hProcess)
+        {
+            g_pObjectManager->RevokeHandle(pThread, hProcess);
+        }
+
+        if (NULL != hDummyThread)
+        {
+            g_pObjectManager->RevokeHandle(pThread, hDummyThread);
+        }
+    }
+
+    if (EnvironmentArray)
+    {
+        free(EnvironmentArray);
+    }
+
+    /* if we still have the file structures at this point, it means we
+       encountered an error sometime between when we acquired them and when we
+       fork()ed. We not only have to release them, we have to give them back
+       their close-on-exec flag */
+    if (NULL != pobjFileIn)
+    {
+        if(-1 == fcntl(iFdIn, F_SETFD, 1))
+        {
+            WARN("couldn't restore close-on-exec flag to stdin descriptor! "
+                 "errno is %d (%s)\n", errno, strerror(errno));
+        }
+        pobjFileIn->ReleaseReference(pThread);
+    }
+
+    if (NULL != pobjFileOut)
+    {
+        if(-1 == fcntl(iFdOut, F_SETFD, 1))
+        {
+            WARN("couldn't restore close-on-exec flag to stdout descriptor! "
+                 "errno is %d (%s)\n", errno, strerror(errno));
+        }
+        pobjFileOut->ReleaseReference(pThread);
+    }
+
+    if (NULL != pobjFileErr)
+    {
+        if(-1 == fcntl(iFdErr, F_SETFD, 1))
+        {
+            WARN("couldn't restore close-on-exec flag to stderr descriptor! "
+                 "errno is %d (%s)\n", errno, strerror(errno));
+        }
+        pobjFileErr->ReleaseReference(pThread);
+    }
+
+    /* free allocated memory */
+    if (lppArgv)
+    {
+        free(*lppArgv);
+        free(lppArgv);
+    }
+
+    return palError;
+}
+
+/*++
+Function:
+  TerminateProcess
+
+Note:
+  hProcess is a handle on the current process.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+TerminateProcess(
+    IN HANDLE hProcess,
+    IN UINT uExitCode)
+{
+    BOOL ret;
+
+    PERF_ENTRY(TerminateProcess);
+    ENTRY("TerminateProcess(hProcess=%p, uExitCode=%u)\n",hProcess, uExitCode );
+
+    ret = PROCEndProcess(hProcess, uExitCode, TRUE);
+
+    LOGEXIT("TerminateProcess returns BOOL %d\n", ret);
+    PERF_EXIT(TerminateProcess);
+    return ret;
+}
+
+/*++
+Function:
+  RaiseFailFastException
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+RaiseFailFastException(
+    IN PEXCEPTION_RECORD pExceptionRecord,
+    IN PCONTEXT pContextRecord,
+    IN DWORD dwFlags)
+{
+    PERF_ENTRY(RaiseFailFastException);
+    ENTRY("RaiseFailFastException");
+
+    TerminateCurrentProcessNoExit(TRUE);
+    PROCAbort();
+
+    LOGEXIT("RaiseFailFastException");
+    PERF_EXIT(RaiseFailFastException);
+}
+
+/*++
+Function:
+  PROCEndProcess
+
+  Called from TerminateProcess and ExitProcess. This does the work of
+  TerminateProcess, but also takes a flag that determines whether we
+  shut down unconditionally. If the flag is set, the PAL will do very
+  little extra work before exiting. Most importantly, it won't shut
+  down any DLLs that are loaded.
+
+--*/
+static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUnconditionally)
+{
+    DWORD dwProcessId;
+    BOOL ret = FALSE;
+
+    dwProcessId = PROCGetProcessIDFromHandle(hProcess);
+    if (dwProcessId == 0)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+    }
+    else if(dwProcessId != GetCurrentProcessId())
+    {
+        if (uExitCode != 0)
+            WARN("exit code 0x%x ignored for external process.\n", uExitCode);
+
+        if (kill(dwProcessId, SIGKILL) == 0)
+        {
+            ret = TRUE;
+        }
+        else
+        {
+            switch (errno) {
+            case ESRCH:
+                SetLastError(ERROR_INVALID_HANDLE);
+                break;
+            case EPERM:
+                SetLastError(ERROR_ACCESS_DENIED);
+                break;
+            default:
+                // Unexpected failure.
+                ASSERT(FALSE);
+                SetLastError(ERROR_INTERNAL_ERROR);
+                break;
+            }
+        }
+    }
+    else
+    {
+        // WARN/ERROR before starting the termination process and/or leaving the PAL.
+        if (bTerminateUnconditionally)
+        {
+            WARN("exit code 0x%x ignored for terminate.\n", uExitCode);
+        }
+        else if ((uExitCode & 0xff) != uExitCode)
+        {
+            // TODO: Convert uExitCodes into sysexits(3)?
+            ERROR("exit() only supports the lower 8-bits of an exit code. "
+                "status will only see error 0x%x instead of 0x%x.\n", uExitCode & 0xff, uExitCode);
+        }
+
+        TerminateCurrentProcessNoExit(bTerminateUnconditionally);
+
+        LOGEXIT("PROCEndProcess will not return\n");
+
+        if (bTerminateUnconditionally)
+        {
+            // abort() has the semantics that
+            // (1) it doesn't run atexit handlers
+            PROCAbort();
+        }
+        else
+        {
+            exit(uExitCode);
+        }
+
+        ASSERT(FALSE); // we shouldn't get here
+    }
+
+    return ret;
+}
+
+static bool IsCoreClrModule(const char* pModulePath)
+{
+    // Strip off everything up to and including the last slash in the path to get name
+    const char* pModuleName = pModulePath;
+    while (strchr(pModuleName, '/') != NULL)
+    {
+        pModuleName = strchr(pModuleName, '/');
+        pModuleName++; // pass the slash
+    }
+
+    return _stricmp(pModuleName, MAKEDLLNAME_A("coreclr")) == 0;
+}
+
+// Build the semaphore names using the PID and a value that can be used for distinguishing
+// between processes with the same PID (which ran at different times). This is to avoid
+// cases where a prior process with the same PID exited abnormally without having a chance
+// to clean up its semaphore.
+// Note to anyone modifying these names in the future: Semaphore names on OS X are limited
+// to SEM_NAME_LEN characters, including null. SEM_NAME_LEN is 31 (at least on OS X 10.11).
+// NetBSD limits semaphore names to 15 characters, including null (at least up to 7.99.25).
+// Keep 31 length for Core 1.0 RC2 compatibility
+#if defined(__NetBSD__)
+static const char* RuntimeSemaphoreNameFormat = "/clr%s%08llx";
+#else
+static const char* RuntimeSemaphoreNameFormat = "/clr%s%08x%016llx";
+#endif
+
+static const char* RuntimeStartupSemaphoreName = "st";
+static const char* RuntimeContinueSemaphoreName = "co";
+
+#if defined(__NetBSD__)
+static uint64_t HashSemaphoreName(uint64_t a, uint64_t b)
+{
+    return (a ^ b) & 0xffffffff;
+}
+#else
+#define HashSemaphoreName(a,b) a,b
+#endif
+
+static const char *const TwoWayNamedPipePrefix = "clr-debug-pipe";
+static const char* IpcNameFormat = "%s-%d-%llu-%s";
+
+class PAL_RuntimeStartupHelper
+{
+    LONG m_ref;
+    bool m_canceled;
+    PPAL_STARTUP_CALLBACK m_callback;
+    PVOID m_parameter;
+    DWORD m_threadId;
+    HANDLE m_threadHandle;
+    DWORD m_processId;
+#ifdef __APPLE__
+    char m_applicationGroupId[MAX_APPLICATION_GROUP_ID_LENGTH+1];
+#endif // __APPLE__
+    char m_startupSemName[CLR_SEM_MAX_NAMELEN];
+    char m_continueSemName[CLR_SEM_MAX_NAMELEN];
+
+    // A value that, used in conjunction with the process ID, uniquely identifies a process.
+    // See the format we use for debugger semaphore names for why this is necessary.
+    UINT64 m_processIdDisambiguationKey;
+
+    // Debugger waits on this semaphore and the runtime signals it on startup.
+    sem_t *m_startupSem;
+
+    // Debuggee waits on this semaphore and the debugger signals it after the startup callback
+    // registered (m_callback) returns.
+    sem_t *m_continueSem;
+
+    LPCSTR GetApplicationGroupId() const
+    {
+#ifdef __APPLE__
+        return m_applicationGroupId[0] == '\0' ? nullptr : m_applicationGroupId;
+#else // __APPLE__
+        return nullptr;
+#endif // __APPLE__
+    }
+
+public:
+    PAL_RuntimeStartupHelper(DWORD dwProcessId, PPAL_STARTUP_CALLBACK pfnCallback, PVOID parameter) :
+        m_ref(1),
+        m_canceled(false),
+        m_callback(pfnCallback),
+        m_parameter(parameter),
+        m_threadId(0),
+        m_threadHandle(NULL),
+        m_processId(dwProcessId),
+        m_startupSem(SEM_FAILED),
+        m_continueSem(SEM_FAILED)
+    {
+    }
+
+    ~PAL_RuntimeStartupHelper()
+    {
+        if (m_startupSem != SEM_FAILED)
+        {
+            sem_close(m_startupSem);
+            sem_unlink(m_startupSemName);
+        }
+
+        if (m_continueSem != SEM_FAILED)
+        {
+            sem_close(m_continueSem);
+            sem_unlink(m_continueSemName);
+        }
+
+        if (m_threadHandle != NULL)
+        {
+            CloseHandle(m_threadHandle);
+        }
+    }
+
+    LONG AddRef()
+    {
+        LONG ref = InterlockedIncrement(&m_ref);
+        return ref;
+    }
+
+    LONG Release()
+    {
+        LONG ref = InterlockedDecrement(&m_ref);
+        if (ref == 0)
+        {
+            InternalDelete(this);
+        }
+        return ref;
+    }
+
+    PAL_ERROR GetSemError()
+    {
+        PAL_ERROR pe;
+        switch (errno)
+        {
+            case ENOENT:
+                pe = ERROR_NOT_FOUND;
+                break;
+            case EACCES:
+                pe = ERROR_INVALID_ACCESS;
+                break;
+            case EINVAL:
+            case ENAMETOOLONG:
+                pe = ERROR_INVALID_NAME;
+                break;
+            case ENOMEM:
+                pe = ERROR_OUTOFMEMORY;
+                break;
+            case EEXIST:
+                pe = ERROR_ALREADY_EXISTS;
+                break;
+            case ENOSPC:
+                pe = ERROR_TOO_MANY_SEMAPHORES;
+                break;
+            default:
+                pe = ERROR_INVALID_PARAMETER;
+                break;
+        }
+        return pe;
+    }
+
+    PAL_ERROR Register(LPCWSTR lpApplicationGroupId)
+    {
+        CPalThread *pThread = InternalGetCurrentThread();
+        PAL_ERROR pe = NO_ERROR;
+        BOOL ret;
+        UnambiguousProcessDescriptor unambiguousProcessDescriptor;
+        SIZE_T osThreadId = 0;
+
+#ifdef __APPLE__
+        if (lpApplicationGroupId != NULL)
+        {
+            /* Convert to ASCII */
+            int applicationGroupIdLength = WideCharToMultiByte(CP_ACP, 0, lpApplicationGroupId, -1, m_applicationGroupId, sizeof(m_applicationGroupId), NULL, NULL);
+            if (applicationGroupIdLength == 0)
+            {
+                pe = GetLastError();
+                TRACE("applicationGroupId: Failed to convert to multibyte string (%u)\n", pe);
+                if (pe == ERROR_INSUFFICIENT_BUFFER)
+                {
+                    pe = ERROR_BAD_LENGTH;
+                }
+                goto exit;
+            }
+        }
+        else
+        {
+            // Indicate that group ID is not being used
+            m_applicationGroupId[0] = '\0';
+        }
+#endif // __APPLE__
+
+        // See semaphore name format for details about this value. We store it so that
+        // it can be used by the cleanup code that removes the semaphore with sem_unlink.
+        ret = GetProcessIdDisambiguationKey(m_processId, &m_processIdDisambiguationKey);
+
+        // If GetProcessIdDisambiguationKey failed for some reason, it should set the value
+        // to 0. We expect that anyone else opening the semaphore name will also fail and thus
+        // will also try to use 0 as the value.
+        _ASSERTE(ret == TRUE || m_processIdDisambiguationKey == 0);
+
+        unambiguousProcessDescriptor.Init(m_processId, m_processIdDisambiguationKey);
+        CreateSemaphoreName(m_startupSemName, RuntimeStartupSemaphoreName, unambiguousProcessDescriptor, GetApplicationGroupId());
+        CreateSemaphoreName(m_continueSemName, RuntimeContinueSemaphoreName, unambiguousProcessDescriptor, GetApplicationGroupId());
+
+        TRACE("PAL_RuntimeStartupHelper.Register creating startup '%s' continue '%s'\n", m_startupSemName, m_continueSemName);
+
+        // Create the continue semaphore first so we don't race with PAL_NotifyRuntimeStarted. This open will fail if another
+        // debugger is trying to attach to this process because the name will already exist.
+        m_continueSem = sem_open(m_continueSemName, O_CREAT | O_EXCL, S_IRWXU, 0);
+        if (m_continueSem == SEM_FAILED)
+        {
+            TRACE("sem_open(continue) failed: errno is %d (%s)\n", errno, strerror(errno));
+            pe = GetSemError();
+            goto exit;
+        }
+
+        // Create the debuggee startup semaphore so the runtime (debuggee) knows to wait for a debugger connection.
+        m_startupSem = sem_open(m_startupSemName, O_CREAT | O_EXCL, S_IRWXU, 0);
+        if (m_startupSem == SEM_FAILED)
+        {
+            TRACE("sem_open(startup) failed: errno is %d (%s)\n", errno, strerror(errno));
+            pe = GetSemError();
+            goto exit;
+        }
+
+        // Add a reference for the thread handler
+        AddRef();
+        pe = InternalCreateThread(
+            pThread,
+            NULL,
+            0,
+            ::StartupHelperThread,
+            this,
+            0,
+            UserCreatedThread,
+            &osThreadId,
+            &m_threadHandle);
+
+        if (NO_ERROR != pe)
+        {
+            TRACE("InternalCreateThread failed %d\n", pe);
+            Release();
+            goto exit;
+        }
+        m_threadId = (DWORD)osThreadId;
+    exit:
+        return pe;
+    }
+
+    void Unregister()
+    {
+        m_canceled = true;
+
+        // Tell the runtime to continue
+        if (sem_post(m_continueSem) != 0)
+        {
+            ASSERT("sem_post(continueSem) failed: errno is %d (%s)\n", errno, strerror(errno));
+        }
+
+        // Tell the worker thread to continue
+        if (sem_post(m_startupSem) != 0)
+        {
+            ASSERT("sem_post(startupSem) failed: errno is %d (%s)\n", errno, strerror(errno));
+        }
+
+        // Don't need to wait for the worker thread if unregister called on it
+        if (m_threadId != (DWORD)THREADSilentGetCurrentThreadId())
+        {
+            // Wait for work thread to exit
+            if (WaitForSingleObject(m_threadHandle, INFINITE) != WAIT_OBJECT_0)
+            {
+                ASSERT("WaitForSingleObject\n");
+            }
+        }
+    }
+
+    //
+    // There are a couple race conditions that need to be considered here:
+    //
+    // * On launch, between the fork and execv in the PAL's CreateProcess where the target process
+    //   may contain a coreclr module image if the debugger process is running managed code. This
+    //   makes just checking if the coreclr module exists not enough.
+    //
+    // * On launch (after the execv) or attach when the coreclr is loaded but before the DAC globals
+    //   table is initialized where it is too soon to use/initialize the DAC on the debugger side.
+    //
+    // They are both fixed by check if the one of transport pipe files has been created.
+    //
+    bool IsCoreClrProcessReady()
+    {
+        char pipeName[MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH];
+
+        PAL_GetTransportPipeName(pipeName, m_processId, GetApplicationGroupId(), "in");
+
+        struct stat buf;
+        if (stat(pipeName, &buf) == 0)
+        {
+            TRACE("IsCoreClrProcessReady: stat(%s) SUCCEEDED\n", pipeName);
+            return true;
+        }
+        TRACE("IsCoreClrProcessReady: stat(%s) FAILED: errno is %d (%s)\n", pipeName, errno, strerror(errno));
+        return false;
+    }
+
+    PAL_ERROR InvokeStartupCallback()
+    {
+        ProcessModules *listHead = NULL;
+        PAL_ERROR pe = NO_ERROR;
+        DWORD count;
+
+        if (m_canceled)
+        {
+            goto exit;
+        }
+
+        // Enumerate all the modules in the process and invoke the callback
+        // for the coreclr module if found.
+        listHead = CreateProcessModules(m_processId, &count);
+        if (listHead == NULL)
+        {
+            TRACE("CreateProcessModules failed for pid %d\n", m_processId);
+            pe = ERROR_INVALID_PARAMETER;
+            goto exit;
+        }
+
+        for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+        {
+            if (IsCoreClrModule(entry->Name))
+            {
+                PAL_CPP_TRY
+                {
+                    TRACE("InvokeStartupCallback executing callback %p %s\n", entry->BaseAddress, entry->Name);
+                    m_callback(entry->Name, entry->BaseAddress, m_parameter);
+                }
+                PAL_CPP_CATCH_ALL
+                {
+                }
+                PAL_CPP_ENDTRY
+
+                // Currently only the first coreclr module in a process is supported
+                break;
+            }
+        }
+
+    exit:
+        // Wake up the runtime
+        if (sem_post(m_continueSem) != 0)
+        {
+            ASSERT("sem_post(continueSem) failed: errno is %d (%s)\n", errno, strerror(errno));
+        }
+        if (listHead != NULL)
+        {
+            DestroyProcessModules(listHead);
+        }
+        return pe;
+    }
+
+    void StartupHelperThread()
+    {
+        PAL_ERROR pe = NO_ERROR;
+
+        if (IsCoreClrProcessReady())
+        {
+            pe = InvokeStartupCallback();
+        }
+        else {
+            TRACE("sem_wait(startup)\n");
+
+            // Wait until the coreclr runtime (debuggee) starts up
+            while (sem_wait(m_startupSem) != 0)
+            {
+                if (EINTR == errno)
+                {
+                    TRACE("sem_wait() failed with EINTR; re-waiting");
+                    continue;
+                }
+                TRACE("sem_wait(startup) failed: errno is %d (%s)\n", errno, strerror(errno));
+                pe = GetSemError();
+            }
+
+            if (pe == NO_ERROR)
+            {
+                pe = InvokeStartupCallback();
+            }
+        }
+
+        // Invoke the callback on errors
+        if (pe != NO_ERROR && !m_canceled)
+        {
+            SetLastError(pe);
+            m_callback(NULL, NULL, m_parameter);
+        }
+    }
+};
+
+static
+DWORD
+StartupHelperThread(LPVOID p)
+{
+    TRACE("PAL's StartupHelperThread starting\n");
+
+    PAL_RuntimeStartupHelper *helper = (PAL_RuntimeStartupHelper *)p;
+    helper->StartupHelperThread();
+    helper->Release();
+    return 0;
+}
+
+/*++
+    PAL_RegisterForRuntimeStartup
+
+Parameters:
+    dwProcessId - process id of runtime process
+    lpApplicationGroupId - A string representing the application group ID of a sandboxed
+                           process running in Mac. Pass NULL if the process is not
+                           running in a sandbox and other platforms.
+    pfnCallback - function to callback for coreclr module found
+    parameter - data to pass to callback
+    ppUnregisterToken - pointer to put PAL_UnregisterForRuntimeStartup token.
+
+Return value:
+    PAL_ERROR
+
+Note:
+    If the modulePath or hModule is NULL when the callback is invoked, an error occured
+    and GetLastError() will return the Win32 error code.
+
+    The callback is always invoked on a separate thread and this API returns immediately.
+
+    Only the first coreclr module is currently supported.
+
+--*/
+DWORD
+PALAPI
+PAL_RegisterForRuntimeStartup(
+    IN DWORD dwProcessId,
+    IN LPCWSTR lpApplicationGroupId,
+    IN PPAL_STARTUP_CALLBACK pfnCallback,
+    IN PVOID parameter,
+    OUT PVOID *ppUnregisterToken)
+{
+    _ASSERTE(pfnCallback != NULL);
+    _ASSERTE(ppUnregisterToken != NULL);
+
+    PAL_RuntimeStartupHelper *helper = InternalNew<PAL_RuntimeStartupHelper>(dwProcessId, pfnCallback, parameter);
+
+    // Create the debuggee startup semaphore so the runtime (debuggee) knows to wait for
+    // a debugger connection.
+    PAL_ERROR pe = helper->Register(lpApplicationGroupId);
+    if (NO_ERROR != pe)
+    {
+        helper->Release();
+        helper = NULL;
+    }
+
+    *ppUnregisterToken = helper;
+    return pe;
+}
+
+/*++
+    PAL_UnregisterForRuntimeStartup
+
+    Stops/cancels startup notification. This API can be called in the startup callback. Otherwise,
+    it will block until the callback thread finishes and no more callbacks will be initiated after
+    this API returns.
+
+Parameters:
+    dwUnregisterToken - token from PAL_RegisterForRuntimeStartup or NULL.
+
+Return value:
+    PAL_ERROR
+--*/
+DWORD
+PALAPI
+PAL_UnregisterForRuntimeStartup(
+    IN PVOID pUnregisterToken)
+{
+    if (pUnregisterToken != NULL)
+    {
+        PAL_RuntimeStartupHelper *helper = (PAL_RuntimeStartupHelper *)pUnregisterToken;
+        helper->Unregister();
+        helper->Release();
+    }
+    return NO_ERROR;
+}
+
+#ifdef __APPLE__
+
+// We use 7bits from each byte, so this computes the extra size we need to encode a given byte count
+constexpr int GetExtraEncodedAreaSize(UINT rawByteCount)
+{
+    return (rawByteCount+6)/7;
+}
+const int SEMAPHORE_ENCODED_NAME_EXTRA_LENGTH = GetExtraEncodedAreaSize(sizeof(UnambiguousProcessDescriptor));
+const int SEMAPHORE_ENCODED_NAME_LENGTH =
+    sizeof(UnambiguousProcessDescriptor) + /* For process ID + disambiguationKey */
+    SEMAPHORE_ENCODED_NAME_EXTRA_LENGTH; /* For base 255 extra encoding space */
+
+static_assert_no_msg(MAX_APPLICATION_GROUP_ID_LENGTH
+    + 1 /* For / */
+    + 2 /* For ST/CO name prefix */
+    + SEMAPHORE_ENCODED_NAME_LENGTH /* For encoded name string */
+    + 1 /* For null terminator */
+    <= CLR_SEM_MAX_NAMELEN);
+
+// In Apple we are limited by the length of the semaphore name. However, the characters which can be used in the
+// name can be anything between 1 and 255 (since 0 will terminate the string). Thus, we encode each byte b in
+// unambiguousProcessDescriptor as b ? b : 1, and mark an additional bit indicating if b is 0 or not. We use 7 bits
+// out of each extra byte so 1 bit will always be '1'. This will ensure that our extra bytes are never 0 which are
+// invalid characters. Thus we need an extra byte for each 7 input bytes. Hence, only extra 2 bytes for the name string.
+void EncodeSemaphoreName(char *encodedSemName, const UnambiguousProcessDescriptor& unambiguousProcessDescriptor)
+{
+    const unsigned char *buffer = (const unsigned char *)&unambiguousProcessDescriptor;
+    char *extraEncodingBits = encodedSemName + sizeof(UnambiguousProcessDescriptor);
+
+    // Reset the extra encoding bit area
+    for (int i=0; i<SEMAPHORE_ENCODED_NAME_EXTRA_LENGTH; i++)
+    {
+        extraEncodingBits[i] = 0x80;
+    }
+
+    // Encode each byte in unambiguousProcessDescriptor
+    for (int i=0; i<sizeof(UnambiguousProcessDescriptor); i++)
+    {
+        unsigned char b = buffer[i];
+        encodedSemName[i] = b ? b : 1;
+        extraEncodingBits[i/7] |= (b ? 0 : 1) << (i%7);
+    }
+}
+#endif
+
+void CreateSemaphoreName(char semName[CLR_SEM_MAX_NAMELEN], LPCSTR semaphoreName, const UnambiguousProcessDescriptor& unambiguousProcessDescriptor, LPCSTR applicationGroupId)
+{
+    int length = 0;
+
+#ifdef __APPLE__
+    if (applicationGroupId != nullptr)
+    {
+        // We assume here that applicationGroupId has been already tested for length and is less than MAX_APPLICATION_GROUP_ID_LENGTH
+        length = sprintf_s(semName, CLR_SEM_MAX_NAMELEN, "%s/%s", applicationGroupId, semaphoreName);
+        _ASSERTE(length > 0 && length < CLR_SEM_MAX_NAMELEN);
+
+        EncodeSemaphoreName(semName+length, unambiguousProcessDescriptor);
+        length += SEMAPHORE_ENCODED_NAME_LENGTH;
+        semName[length] = 0;
+    }
+    else
+#endif // __APPLE__
+    {
+        length = sprintf_s(
+            semName,
+            CLR_SEM_MAX_NAMELEN,
+            RuntimeSemaphoreNameFormat,
+            semaphoreName,
+            HashSemaphoreName(unambiguousProcessDescriptor.m_processId, unambiguousProcessDescriptor.m_disambiguationKey));
+    }
+
+    _ASSERTE(length > 0 && length < CLR_SEM_MAX_NAMELEN );
+}
+
+/*++
+ Function:
+  GetProcessIdDisambiguationKey
+
+  Get a numeric value that can be used to disambiguate between processes with the same PID,
+  provided that one of them is still running. The numeric value can mean different things
+  on different platforms, so it should not be used for any other purpose. Under the hood,
+  it is implemented based on the creation time of the process.
+--*/
+BOOL
+GetProcessIdDisambiguationKey(DWORD processId, UINT64 *disambiguationKey)
+{
+    if (disambiguationKey == nullptr)
+    {
+        _ASSERTE(!"disambiguationKey argument cannot be null!");
+        return FALSE;
+    }
+
+    *disambiguationKey = 0;
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+
+    // On OS X, we return the process start time expressed in Unix time (the number of seconds
+    // since the start of the Unix epoch).
+    struct kinfo_proc info = {};
+    size_t size = sizeof(info);
+    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, processId };
+    int ret = ::sysctl(mib, sizeof(mib)/sizeof(*mib), &info, &size, nullptr, 0);
+
+    if (ret == 0)
+    {
+#if defined(__APPLE__)
+        timeval procStartTime = info.kp_proc.p_starttime;
+#else // __FreeBSD__
+        timeval procStartTime = info.ki_start;
+#endif
+        long secondsSinceEpoch = procStartTime.tv_sec;
+
+        *disambiguationKey = secondsSinceEpoch;
+        return TRUE;
+    }
+    else
+    {
+        _ASSERTE(!"Failed to get start time of a process.");
+        return FALSE;
+    }
+
+#elif defined(__NetBSD__)
+
+    // On NetBSD, we return the process start time expressed in Unix time (the number of seconds
+    // since the start of the Unix epoch).
+    kvm_t *kd;
+    int cnt;
+    struct kinfo_proc2 *info;
+
+    kd = kvm_open(nullptr, nullptr, nullptr, KVM_NO_FILES, "kvm_open");
+    if (kd == nullptr)
+    {
+        _ASSERTE(!"Failed to get start time of a process.");
+        return FALSE;
+    }
+
+    info = kvm_getproc2(kd, KERN_PROC_PID, processId, sizeof(struct kinfo_proc2), &cnt);
+    if (info == nullptr || cnt < 1)
+    {
+        kvm_close(kd);
+        _ASSERTE(!"Failed to get start time of a process.");
+        return FALSE;
+    }
+
+    kvm_close(kd);
+
+    long secondsSinceEpoch = info->p_ustart_sec;
+    *disambiguationKey = secondsSinceEpoch;
+
+    return TRUE;
+
+#elif HAVE_PROCFS_STAT
+
+    // Here we read /proc/<pid>/stat file to get the start time for the process.
+    // We return this value (which is expressed in jiffies since boot time).
+
+    // Making something like: /proc/123/stat
+    char statFileName[64];
+
+    INDEBUG(int chars = )
+    snprintf(statFileName, sizeof(statFileName), "/proc/%d/stat", processId);
+    _ASSERTE(chars > 0 && chars <= (int)sizeof(statFileName));
+
+    FILE *statFile = fopen(statFileName, "r");
+    if (statFile == nullptr)
+    {
+        TRACE("GetProcessIdDisambiguationKey: fopen() FAILED");
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    char *line = nullptr;
+    size_t lineLen = 0;
+    if (getline(&line, &lineLen, statFile) == -1)
+    {
+        TRACE("GetProcessIdDisambiguationKey: getline() FAILED");
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    unsigned long long starttime;
+
+    // According to `man proc`, the second field in the stat file is the filename of the executable,
+    // in parentheses. Tokenizing the stat file using spaces as separators breaks when that name
+    // has spaces in it, so we start using sscanf_s after skipping everything up to and including the
+    // last closing paren and the space after it.
+    char *scanStartPosition = strrchr(line, ')') + 2;
+
+    // All the format specifiers for the fields in the stat file are provided by 'man proc'.
+    int sscanfRet = sscanf_s(scanStartPosition,
+        "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %llu \n",
+         &starttime);
+
+    if (sscanfRet != 1)
+    {
+        _ASSERTE(!"Failed to parse stat file contents with sscanf_s.");
+        return FALSE;
+    }
+
+    free(line);
+    fclose(statFile);
+
+    *disambiguationKey = starttime;
+    return TRUE;
+
+#else
+    // If this is not OS X and we don't have /proc, we just return FALSE.
+    WARN("GetProcessIdDisambiguationKey was called but is not implemented on this platform!");
+    return FALSE;
+#endif
+}
+
+/*++
+ Function:
+  PAL_GetTransportName
+
+  Builds the transport IPC names from the process id.
+--*/
+VOID
+PALAPI
+PAL_GetTransportName(
+    const unsigned int MAX_TRANSPORT_NAME_LENGTH,
+    OUT char *name,
+    IN const char *prefix,
+    IN DWORD id,
+    IN const char *applicationGroupId,
+    IN const char *suffix)
+{
+    *name = '\0';
+    DWORD dwRetVal = 0;
+    UINT64 disambiguationKey = 0;
+    PathCharString formatBufferString;
+    BOOL ret = GetProcessIdDisambiguationKey(id, &disambiguationKey);
+    char *formatBuffer = formatBufferString.OpenStringBuffer(MAX_TRANSPORT_NAME_LENGTH-1);
+    if (formatBuffer == nullptr)
+    {
+        ERROR("Out Of Memory");
+        return;
+    }
+
+    // If GetProcessIdDisambiguationKey failed for some reason, it should set the value
+    // to 0. We expect that anyone else making the pipe name will also fail and thus will
+    // also try to use 0 as the value.
+    _ASSERTE(ret == TRUE || disambiguationKey == 0);
+#ifdef __APPLE__
+    if (nullptr != applicationGroupId)
+    {
+        // Verify the length of the application group ID
+        int applicationGroupIdLength = strlen(applicationGroupId);
+        if (applicationGroupIdLength > MAX_APPLICATION_GROUP_ID_LENGTH)
+        {
+            ERROR("The length of applicationGroupId is larger than MAX_APPLICATION_GROUP_ID_LENGTH");
+            return;
+        }
+
+        // In sandbox, all IPC files (locks, pipes) should be written to the application group
+        // container. The path returned by GetTempPathA will be unique for each process and cannot
+        // be used for IPC between two different processes
+        if (!GetApplicationContainerFolder(formatBufferString, applicationGroupId, applicationGroupIdLength))
+        {
+            ERROR("Out Of Memory");
+            return;
+        }
+
+        // Verify the size of the path won't exceed maximum allowed size
+        if (formatBufferString.GetCount() >= MAX_TRANSPORT_NAME_LENGTH)
+        {
+            ERROR("GetApplicationContainerFolder returned a path that was larger than MAX_TRANSPORT_NAME_LENGTH");
+            return;
+        }
+    }
+    else
+#endif // __APPLE__
+    {
+        // Get a temp file location
+        dwRetVal = ::GetTempPathA(MAX_TRANSPORT_NAME_LENGTH, formatBuffer);
+        if (dwRetVal == 0)
+        {
+            ERROR("GetTempPath failed (0x%08x)", ::GetLastError());
+            return;
+        }
+        if (dwRetVal > MAX_TRANSPORT_NAME_LENGTH)
+        {
+            ERROR("GetTempPath returned a path that was larger than MAX_TRANSPORT_NAME_LENGTH");
+            return;
+        }
+    }
+
+    if (strncat_s(formatBuffer, MAX_TRANSPORT_NAME_LENGTH, IpcNameFormat, strlen(IpcNameFormat)) == STRUNCATE)
+    {
+        ERROR("TransportPipeName was larger than MAX_TRANSPORT_NAME_LENGTH");
+        return;
+    }
+
+    int chars = snprintf(name, MAX_TRANSPORT_NAME_LENGTH, formatBuffer, prefix, id, disambiguationKey, suffix);
+    _ASSERTE(chars > 0 && (unsigned int)chars < MAX_TRANSPORT_NAME_LENGTH);
+}
+
+/*++
+ Function:
+  PAL_GetTransportPipeName
+
+  Builds the transport pipe names from the process id.
+--*/
+VOID
+PALAPI
+PAL_GetTransportPipeName(
+    OUT char *name,
+    IN DWORD id,
+    IN const char *applicationGroupId,
+    IN const char *suffix)
+{
+    PAL_GetTransportName(
+        MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH,
+        name,
+        TwoWayNamedPipePrefix,
+        id,
+        applicationGroupId,
+        suffix);
+}
+
+/*++
+Function:
+  OpenProcess
+
+See MSDN doc.
+
+Notes :
+dwDesiredAccess is ignored (all supported operations will be allowed)
+bInheritHandle is ignored (no inheritance)
+--*/
+HANDLE
+PALAPI
+OpenProcess(
+        DWORD dwDesiredAccess,
+        BOOL bInheritHandle,
+        DWORD dwProcessId)
+{
+    PAL_ERROR palError;
+    CPalThread *pThread;
+    IPalObject *pobjProcess = NULL;
+    IPalObject *pobjProcessRegistered = NULL;
+    IDataLock *pDataLock;
+    CProcProcessLocalData *pLocalData;
+    CObjectAttributes oa;
+    HANDLE hProcess = NULL;
+
+    PERF_ENTRY(OpenProcess);
+    ENTRY("OpenProcess(dwDesiredAccess=0x%08x, bInheritHandle=%d, "
+          "dwProcessId = 0x%08x)\n",
+          dwDesiredAccess, bInheritHandle, dwProcessId );
+
+    pThread = InternalGetCurrentThread();
+
+    if (0 == dwProcessId)
+    {
+        palError = ERROR_INVALID_PARAMETER;
+        goto OpenProcessExit;
+    }
+
+    palError = g_pObjectManager->AllocateObject(
+        pThread,
+        &otProcess,
+        &oa,
+        &pobjProcess
+        );
+
+    if (NO_ERROR != palError)
+    {
+        goto OpenProcessExit;
+    }
+
+    palError = pobjProcess->GetProcessLocalData(
+        pThread,
+        WriteLock,
+        &pDataLock,
+        reinterpret_cast<void **>(&pLocalData)
+        );
+
+    if (NO_ERROR != palError)
+    {
+        goto OpenProcessExit;
+    }
+
+    pLocalData->dwProcessId = dwProcessId;
+    pDataLock->ReleaseLock(pThread, TRUE);
+
+    palError = g_pObjectManager->RegisterObject(
+        pThread,
+        pobjProcess,
+        &aotProcess,
+        &hProcess,
+        &pobjProcessRegistered
+        );
+
+    //
+    // pobjProcess was invalidated by the above call, so NULL
+    // it out here
+    //
+
+    pobjProcess = NULL;
+
+    //
+    // TODO: check to see if the process actually exists?
+    //
+
+OpenProcessExit:
+
+    if (NULL != pobjProcess)
+    {
+        pobjProcess->ReleaseReference(pThread);
+    }
+
+    if (NULL != pobjProcessRegistered)
+    {
+        pobjProcessRegistered->ReleaseReference(pThread);
+    }
+
+    if (NO_ERROR != palError)
+    {
+        pThread->SetLastError(palError);
+    }
+
+    LOGEXIT("OpenProcess returns HANDLE %p\n", hProcess);
+    PERF_EXIT(OpenProcess);
+    return hProcess;
+}
+
+/*++
+Function:
+  EnumProcessModules
+
+Abstract
+  Returns a process's module list
+
+Return
+  TRUE if it succeeded, FALSE otherwise
+
+Notes
+  This API is tricky because the module handles are never closed/freed so there can't be any
+  allocations for the module handle or name strings, etc. The "handles" are actually the base
+  addresses of the modules. The module handles should only be used by GetModuleFileNameExW
+  below.
+--*/
+BOOL
+PALAPI
+EnumProcessModules(
+    IN HANDLE hProcess,
+    OUT HMODULE *lphModule,
+    IN DWORD cb,
+    OUT LPDWORD lpcbNeeded)
+{
+    PERF_ENTRY(EnumProcessModules);
+    ENTRY("EnumProcessModules(hProcess=0x%08x, cb=%d)\n", hProcess, cb);
+
+    BOOL result = TRUE;
+    DWORD count = 0;
+    ProcessModules *listHead = GetProcessModulesFromHandle(hProcess, &count);
+    if (listHead != NULL)
+    {
+        for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+        {
+            if (cb <= 0)
+            {
+                break;
+            }
+            cb -= sizeof(HMODULE);
+            *lphModule = (HMODULE)entry->BaseAddress;
+            lphModule++;
+        }
+    }
+    else
+    {
+        result = FALSE;
+    }
+
+    if (lpcbNeeded)
+    {
+        // This return value isn't exactly up to spec because it should return the actual
+        // number of modules in the process even if "cb" isn't big enough but for our use
+        // it works just fine.
+        (*lpcbNeeded) = count * sizeof(HMODULE);
+    }
+
+    LOGEXIT("EnumProcessModules returns %d\n", result);
+    PERF_EXIT(EnumProcessModules);
+    return result;
+}
+
+/*++
+Function:
+  GetModuleFileNameExW
+
+  Used only with module handles returned from EnumProcessModule (for dbgshim).
+
+--*/
+DWORD
+PALAPI
+GetModuleFileNameExW(
+    IN HANDLE hProcess,
+    IN HMODULE hModule,
+    OUT LPWSTR lpFilename,
+    IN DWORD nSize
+)
+{
+    DWORD result = 0;
+    DWORD count = 0;
+
+    ProcessModules *listHead = GetProcessModulesFromHandle(hProcess, &count);
+    if (listHead != NULL)
+    {
+        for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+        {
+            if ((HMODULE)entry->BaseAddress == hModule)
+            {
+                // Convert CHAR string into WCHAR string
+                result = MultiByteToWideChar(CP_ACP, 0, entry->Name, -1, lpFilename, nSize);
+                break;
+            }
+        }
+    }
+
+    return result;
+}
+
+/*++
+Function:
+ GetProcessModulesFromHandle
+
+Abstract
+  Returns a process's module list
+
+Return
+  ProcessModules * list
+
+--*/
+ProcessModules *
+GetProcessModulesFromHandle(
+    IN HANDLE hProcess,
+    OUT LPDWORD lpCount)
+{
+    CPalThread* pThread = InternalGetCurrentThread();
+    CProcProcessLocalData *pLocalData = NULL;
+    ProcessModules *listHead = NULL;
+    IPalObject *pobjProcess = NULL;
+    IDataLock *pDataLock = NULL;
+    PAL_ERROR palError = NO_ERROR;
+    DWORD dwProcessId = 0;
+    DWORD count = 0;
+
+    _ASSERTE(lpCount != NULL);
+
+    if (hPseudoCurrentProcess == hProcess)
+    {
+        pobjProcess = g_pobjProcess;
+        pobjProcess->AddReference();
+    }
+    else
+    {
+        CAllowedObjectTypes aotProcess(otiProcess);
+
+        palError = g_pObjectManager->ReferenceObjectByHandle(
+            pThread,
+            hProcess,
+            &aotProcess,
+            &pobjProcess);
+
+        if (NO_ERROR != palError)
+        {
+            pThread->SetLastError(ERROR_INVALID_HANDLE);
+            goto exit;
+        }
+    }
+
+    palError = pobjProcess->GetProcessLocalData(
+        pThread,
+        WriteLock,
+        &pDataLock,
+        reinterpret_cast<void **>(&pLocalData));
+
+    _ASSERTE(NO_ERROR == palError);
+
+    dwProcessId = pLocalData->dwProcessId;
+    listHead = pLocalData->pProcessModules;
+    count = pLocalData->cProcessModules;
+
+    // If the module list hasn't been created yet, create it now
+    if (listHead == NULL)
+    {
+        listHead = CreateProcessModules(dwProcessId, &count);
+        if (listHead == NULL)
+        {
+            pThread->SetLastError(ERROR_INVALID_PARAMETER);
+            goto exit;
+        }
+
+        if (pLocalData != NULL)
+        {
+            pLocalData->pProcessModules = listHead;
+            pLocalData->cProcessModules = count;
+        }
+    }
+
+exit:
+    if (NULL != pDataLock)
+    {
+        pDataLock->ReleaseLock(pThread, TRUE);
+    }
+    if (NULL != pobjProcess)
+    {
+        pobjProcess->ReleaseReference(pThread);
+    }
+
+    *lpCount = count;
+    return listHead;
+}
+
+/*++
+Function:
+  CreateProcessModules
+
+Abstract
+  Returns a process's module list
+
+Return
+  ProcessModules * list
+
+--*/
+ProcessModules *
+CreateProcessModules(
+    IN DWORD dwProcessId,
+    OUT LPDWORD lpCount)
+{
+    ProcessModules *listHead = NULL;
+    _ASSERTE(lpCount != NULL);
+
+#if defined(__APPLE__)
+
+    // For OS X, the "vmmap" command outputs something similar to the /proc/*/maps file so popen the
+    // command and read the relevant lines:
+    //
+    // ...
+    // ==== regions for process 347  (non-writable and writable regions are interleaved)
+    // REGION TYPE                      START - END             [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
+    // __TEXT                 000000010446d000-0000000104475000 [   32K] r-x/rwx SM=COW  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/corerun
+    // __DATA                 0000000104475000-0000000104476000 [    4K] rw-/rwx SM=PRV  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/corerun
+    // __LINKEDIT             0000000104476000-000000010447a000 [   16K] r--/rwx SM=COW  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/corerun
+    // Kernel Alloc Once      000000010447a000-000000010447b000 [    4K] rw-/rwx SM=PRV
+    // MALLOC (admin)         000000010447b000-000000010447c000 [    4K] r--/rwx SM=ZER
+    // ...
+    // MALLOC (admin)         00000001044ab000-00000001044ac000 [    4K] r--/rwx SM=PRV
+    // __TEXT                 00000001044ac000-0000000104c84000 [ 8032K] r-x/rwx SM=COW  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+    // __TEXT                 0000000104c84000-0000000104c85000 [    4K] rwx/rwx SM=PRV  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+    // __TEXT                 0000000104c85000-000000010513b000 [ 4824K] r-x/rwx SM=COW  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+    // __TEXT                 000000010513b000-000000010513c000 [    4K] rwx/rwx SM=PRV  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+    // __TEXT                 000000010513c000-000000010516f000 [  204K] r-x/rwx SM=COW  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+    // __DATA                 000000010516f000-00000001051ce000 [  380K] rw-/rwx SM=COW  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+    // __DATA                 00000001051ce000-00000001051fa000 [  176K] rw-/rwx SM=PRV  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+    // __LINKEDIT             00000001051fa000-0000000105bac000 [ 9928K] r--/rwx SM=COW  /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+    // VM_ALLOCATE            0000000105bac000-0000000105bad000 [    4K] r--/rw- SM=SHM
+    // MALLOC (admin)         0000000105bad000-0000000105bae000 [    4K] r--/rwx SM=ZER
+    // MALLOC                 0000000105bae000-0000000105baf000 [    4K] rw-/rwx SM=ZER
+
+    // OS X Sierra (10.12.4 Beta)
+    // REGION TYPE                      START - END             [ VSIZE  RSDNT  DIRTY   SWAP] PRT/MAX SHRMOD PURGE    REGION DETAIL
+    // Stack                  00007fff5a930000-00007fff5b130000 [ 8192K    32K    32K     0K] rw-/rwx SM=PRV          thread 0
+    // __TEXT                 00007fffa4a0b000-00007fffa4a0d000 [    8K     8K     0K     0K] r-x/r-x SM=COW          /usr/lib/libSystem.B.dylib
+    // __TEXT                 00007fffa4bbe000-00007fffa4c15000 [  348K   348K     0K     0K] r-x/r-x SM=COW          /usr/lib/libc++.1.dylib
+
+    // NOTE: the module path can have spaces in the name
+    // __TEXT                 0000000196220000-00000001965b4000 [ 3664K  2340K     0K     0K] r-x/rwx SM=COW          /Volumes/Builds/builds/devmain/rawproduct/debug/build/out/Applications/Microsoft Excel.app/Contents/SharedSupport/PowerQuery/libcoreclr.dylib
+
+    // NOTE: Sometimes vmmap hides full paths to some process modules (.dylibs in non-system folders), causing debugger not to work.
+    // __TEXT                 000000010d8bd000-000000010ddce000 [ 5188K  5188K     0K     0K] r-x/rwx SM=COW          /Users/USER/*/libcoreclr.dylib
+    // So now we get modules information by iterating over regions using proc_pidinfo().  See dotnet/runtime#42888.
+    int count = 0;
+
+    uint64_t addr = 0;
+    while (true)
+    {
+        struct proc_regionwithpathinfo rwpi;
+        int sz = proc_pidinfo(dwProcessId, PROC_PIDREGIONPATHINFO, addr, &rwpi, sizeof rwpi);
+        if (sz != sizeof rwpi)
+        {
+            if (sz == 0 && errno == EINVAL)
+                break; // ok
+
+            DestroyProcessModules(listHead);
+            listHead = NULL;
+            count = 0;
+            break; // unknown error
+        }
+
+        const char *moduleName = rwpi.prp_vip.vip_path;
+
+        bool dup = false;
+        for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+        {
+            if (strcmp(moduleName, entry->Name) == 0)
+            {
+                dup = true;
+                break;
+            }
+        }
+
+        if (!dup)
+        {
+            int cbModuleName = strlen(moduleName) + 1;
+            ProcessModules *entry = (ProcessModules *)InternalMalloc(sizeof(ProcessModules) + cbModuleName);
+            if (entry == NULL)
+            {
+                DestroyProcessModules(listHead);
+                listHead = NULL;
+                count = 0;
+                break; // no memory
+            }
+            memcpy_s(entry->Name, cbModuleName, moduleName, cbModuleName);
+            entry->BaseAddress = (void *)rwpi.prp_prinfo.pri_address;
+            entry->Next = listHead;
+            listHead = entry;
+            count++;
+        }
+
+        addr = rwpi.prp_prinfo.pri_address + rwpi.prp_prinfo.pri_size;
+    }
+
+    *lpCount = count;
+
+#elif HAVE_PROCFS_MAPS
+
+    // Here we read /proc/<pid>/maps file in order to parse it and figure out what it says
+    // about a library we are looking for. This file looks something like this:
+    //
+    // [address]      [perms] [offset] [dev] [inode]     [pathname] - HEADER is not preset in an actual file
+    //
+    // 35b1800000-35b1820000 r-xp 00000000 08:02 135522  /usr/lib64/ld-2.15.so
+    // 35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522  /usr/lib64/ld-2.15.so
+    // 35b1a20000-35b1a21000 rw-p 00020000 08:02 135522  /usr/lib64/ld-2.15.so
+    // 35b1a21000-35b1a22000 rw-p 00000000 00:00 0       [heap]
+    // 35b1c00000-35b1dac000 r-xp 00000000 08:02 135870  /usr/lib64/libc-2.15.so
+    // 35b1dac000-35b1fac000 ---p 001ac000 08:02 135870  /usr/lib64/libc-2.15.so
+    // 35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870  /usr/lib64/libc-2.15.so
+    // 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870  /usr/lib64/libc-2.15.so
+
+    // Making something like: /proc/123/maps
+    char mapFileName[100];
+    char *line = NULL;
+    size_t lineLen = 0;
+    int count = 0;
+    ssize_t read;
+
+    INDEBUG(int chars = )
+    snprintf(mapFileName, sizeof(mapFileName), "/proc/%d/maps", dwProcessId);
+    _ASSERTE(chars > 0 && chars <= (int)sizeof(mapFileName));
+
+    FILE *mapsFile = fopen(mapFileName, "r");
+    if (mapsFile == NULL)
+    {
+        goto exit;
+    }
+
+    // Reading maps file line by line
+    while ((read = getline(&line, &lineLen, mapsFile)) != -1)
+    {
+        void *startAddress, *endAddress, *offset;
+        int devHi, devLo, inode;
+        char moduleName[PATH_MAX];
+
+        if (sscanf_s(line, "%p-%p %*[-rwxsp] %p %x:%x %d %s\n", &startAddress, &endAddress, &offset, &devHi, &devLo, &inode, moduleName, ARRAY_SIZE(moduleName)) == 7)
+        {
+            if (inode != 0)
+            {
+                bool dup = false;
+                for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+                {
+                    if (strcmp(moduleName, entry->Name) == 0)
+                    {
+                        dup = true;
+                        break;
+                    }
+                }
+
+                if (!dup)
+                {
+                    int cbModuleName = strlen(moduleName) + 1;
+                    ProcessModules *entry = (ProcessModules *)InternalMalloc(sizeof(ProcessModules) + cbModuleName);
+                    if (entry == NULL)
+                    {
+                        DestroyProcessModules(listHead);
+                        listHead = NULL;
+                        count = 0;
+                        break;
+                    }
+                    strcpy_s(entry->Name, cbModuleName, moduleName);
+                    entry->BaseAddress = startAddress;
+                    entry->Next = listHead;
+                    listHead = entry;
+                    count++;
+                }
+            }
+        }
+    }
+
+    *lpCount = count;
+
+    free(line); // We didn't allocate line, but as per contract of getline we should free it
+    fclose(mapsFile);
+exit:
+
+#else
+    _ASSERTE(!"Not implemented on this platform");
+#endif
+    return listHead;
+}
+
+/*++
+Function:
+    DestroyProcessModules
+
+Abstract
+  Cleans up the process module table.
+
+Return
+  None
+
+--*/
+VOID
+DestroyProcessModules(IN ProcessModules *listHead)
+{
+    for (ProcessModules *entry = listHead; entry != NULL; )
+    {
+        ProcessModules *next = entry->Next;
+        free(entry);
+        entry = next;
+    }
+}
+
+/*++
+Function:
+  PROCAbort()
+
+  Aborts the process after calling the shutdown cleanup handler. This function
+  should be called instead of calling abort() directly.
+
+Parameters:
+  none
+
+  Does not return
+--*/
+PAL_NORETURN
+VOID
+PROCAbort()
+{
+    // Abort the process after waiting for the core dump to complete
+    abort();
+}
+
+/*++
+Function:
+  PROCGetProcessIDFromHandle
+
+Abstract
+  Return the process ID from a process handle
+
+Parameter
+  hProcess:  process handle
+
+Return
+  Return the process ID, or 0 if it's not a valid handle
+--*/
+DWORD
+PROCGetProcessIDFromHandle(
+        HANDLE hProcess)
+{
+    PAL_ERROR palError;
+    IPalObject *pobjProcess = NULL;
+    CPalThread *pThread = InternalGetCurrentThread();
+
+    DWORD dwProcessId = 0;
+
+    if (hPseudoCurrentProcess == hProcess)
+    {
+        dwProcessId = gPID;
+        goto PROCGetProcessIDFromHandleExit;
+    }
+
+
+    palError = g_pObjectManager->ReferenceObjectByHandle(
+        pThread,
+        hProcess,
+        &aotProcess,
+        &pobjProcess
+        );
+
+    if (NO_ERROR == palError)
+    {
+        IDataLock *pDataLock;
+        CProcProcessLocalData *pLocalData;
+
+        palError = pobjProcess->GetProcessLocalData(
+            pThread,
+            ReadLock,
+            &pDataLock,
+            reinterpret_cast<void **>(&pLocalData)
+            );
+
+        if (NO_ERROR == palError)
+        {
+            dwProcessId = pLocalData->dwProcessId;
+            pDataLock->ReleaseLock(pThread, FALSE);
+        }
+
+        pobjProcess->ReleaseReference(pThread);
+    }
+
+PROCGetProcessIDFromHandleExit:
+
+    return dwProcessId;
+}
+
+PAL_ERROR
+CorUnix::InitializeProcessData(
+    void
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    bool fLockInitialized = FALSE;
+
+    pGThreadList = NULL;
+    g_dwThreadCount = 0;
+
+    InternalInitializeCriticalSection(&g_csProcess);
+    fLockInitialized = TRUE;
+
+    if (NO_ERROR != palError)
+    {
+        if (fLockInitialized)
+        {
+            InternalDeleteCriticalSection(&g_csProcess);
+        }
+    }
+
+    return palError;
+}
+
+/*++
+Function:
+  CreateInitialProcessAndThreadObjects
+
+Abstract
+  Creates the IPalObjects that represent the current process
+  and the initial thread
+
+Parameter
+  pThread - the initial thread
+
+Return
+  PAL_ERROR
+--*/
+
+PAL_ERROR
+CorUnix::CreateInitialProcessAndThreadObjects(
+    CPalThread *pThread
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    HANDLE hThread;
+    IPalObject *pobjProcess = NULL;
+    IDataLock *pDataLock;
+    CProcProcessLocalData *pLocalData;
+    CObjectAttributes oa;
+    HANDLE hProcess;
+
+    //
+    // Create initial thread object
+    //
+
+    palError = CreateThreadObject(pThread, pThread, &hThread);
+    if (NO_ERROR != palError)
+    {
+        goto CreateInitialProcessAndThreadObjectsExit;
+    }
+
+    //
+    // This handle isn't needed
+    //
+
+    (void) g_pObjectManager->RevokeHandle(pThread, hThread);
+
+    //
+    // Create and initialize process object
+    //
+
+    palError = g_pObjectManager->AllocateObject(
+        pThread,
+        &otProcess,
+        &oa,
+        &pobjProcess
+        );
+
+    if (NO_ERROR != palError)
+    {
+        ERROR("Unable to allocate process object");
+        goto CreateInitialProcessAndThreadObjectsExit;
+    }
+
+    palError = pobjProcess->GetProcessLocalData(
+        pThread,
+        WriteLock,
+        &pDataLock,
+        reinterpret_cast<void **>(&pLocalData)
+        );
+
+    if (NO_ERROR != palError)
+    {
+        ASSERT("Unable to access local data");
+        goto CreateInitialProcessAndThreadObjectsExit;
+    }
+
+    pLocalData->dwProcessId = gPID;
+    pLocalData->ps = PS_RUNNING;
+    pDataLock->ReleaseLock(pThread, TRUE);
+
+    palError = g_pObjectManager->RegisterObject(
+        pThread,
+        pobjProcess,
+        &aotProcess,
+        &hProcess,
+        &g_pobjProcess
+        );
+
+    //
+    // pobjProcess is invalidated by the call to RegisterObject, so
+    // NULL it out here to prevent it from being released later
+    //
+
+    pobjProcess = NULL;
+
+    if (NO_ERROR != palError)
+    {
+        ASSERT("Failure registering process object");
+        goto CreateInitialProcessAndThreadObjectsExit;
+    }
+
+    //
+    // There's no need to keep this handle around, so revoke
+    // it now
+    //
+
+    g_pObjectManager->RevokeHandle(pThread, hProcess);
+
+CreateInitialProcessAndThreadObjectsExit:
+
+    if (NULL != pobjProcess)
+    {
+        pobjProcess->ReleaseReference(pThread);
+    }
+
+    return palError;
+}
+
+
+/*++
+Function:
+  PROCCleanupInitialProcess
+
+Abstract
+  Cleanup all the structures for the initial process.
+
+Parameter
+  VOID
+
+Return
+  VOID
+
+--*/
+VOID
+PROCCleanupInitialProcess(VOID)
+{
+    CPalThread *pThread = InternalGetCurrentThread();
+
+    InternalEnterCriticalSection(pThread, &g_csProcess);
+
+    /* Free the application directory */
+    free(g_lpwstrAppDir);
+
+    /* Free the stored command line */
+    free(g_lpwstrCmdLine);
+
+    InternalLeaveCriticalSection(pThread, &g_csProcess);
+
+    //
+    // Object manager shutdown will handle freeing the underlying
+    // thread and process data
+    //
+
+}
+
+/*++
+Function:
+  PROCAddThread
+
+Abstract
+  Add a thread to the thread list of the current process
+
+Parameter
+  pThread:   Thread object
+
+--*/
+VOID
+CorUnix::PROCAddThread(
+    CPalThread *pCurrentThread,
+    CPalThread *pTargetThread
+    )
+{
+    /* protect the access of the thread list with critical section for
+       mutithreading access */
+    InternalEnterCriticalSection(pCurrentThread, &g_csProcess);
+
+    pTargetThread->SetNext(pGThreadList);
+    pGThreadList = pTargetThread;
+    g_dwThreadCount += 1;
+
+    TRACE("Thread 0x%p (id %#x) added to the process thread list\n",
+          pTargetThread, pTargetThread->GetThreadId());
+
+    InternalLeaveCriticalSection(pCurrentThread, &g_csProcess);
+}
+
+
+/*++
+Function:
+  PROCRemoveThread
+
+Abstract
+  Remove a thread form the thread list of the current process
+
+Parameter
+  CPalThread *pThread : thread object to remove
+
+(no return value)
+--*/
+VOID
+CorUnix::PROCRemoveThread(
+    CPalThread *pCurrentThread,
+    CPalThread *pTargetThread
+    )
+{
+    CPalThread *curThread, *prevThread;
+
+    /* protect the access of the thread list with critical section for
+       mutithreading access */
+    InternalEnterCriticalSection(pCurrentThread, &g_csProcess);
+
+    curThread = pGThreadList;
+
+    /* if thread list is empty */
+    if (curThread == NULL)
+    {
+        ASSERT("Thread list is empty.\n");
+        goto EXIT;
+    }
+
+    /* do we remove the first thread? */
+    if (curThread == pTargetThread)
+    {
+        pGThreadList =  curThread->GetNext();
+        TRACE("Thread 0x%p (id %#x) removed from the process thread list\n",
+            pTargetThread, pTargetThread->GetThreadId());
+        goto EXIT;
+    }
+
+    prevThread = curThread;
+    curThread = curThread->GetNext();
+    /* find the thread to remove */
+    while (curThread != NULL)
+    {
+        if (curThread == pTargetThread)
+        {
+            /* found, fix the chain list */
+            prevThread->SetNext(curThread->GetNext());
+            g_dwThreadCount -= 1;
+            TRACE("Thread %p removed from the process thread list\n", pTargetThread);
+            goto EXIT;
+        }
+
+        prevThread = curThread;
+        curThread = curThread->GetNext();
+    }
+
+    WARN("Thread %p not removed (it wasn't found in the list)\n", pTargetThread);
+
+EXIT:
+    InternalLeaveCriticalSection(pCurrentThread, &g_csProcess);
+}
+
+
+/*++
+Function:
+  PROCProcessLock
+
+Abstract
+  Enter the critical section associated to the current process
+
+Parameter
+  void
+
+Return
+  void
+--*/
+VOID
+PROCProcessLock(
+    VOID)
+{
+    CPalThread * pThread =
+        (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL);
+
+    InternalEnterCriticalSection(pThread, &g_csProcess);
+}
+
+
+/*++
+Function:
+  PROCProcessUnlock
+
+Abstract
+  Leave the critical section associated to the current process
+
+Parameter
+  void
+
+Return
+  void
+--*/
+VOID
+PROCProcessUnlock(
+    VOID)
+{
+    CPalThread * pThread =
+        (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL);
+
+    InternalLeaveCriticalSection(pThread, &g_csProcess);
+}
+
+
+/*++
+Function:
+  TerminateCurrentProcessNoExit
+
+Abstract:
+    Terminate current Process, but leave the caller alive
+
+Parameters:
+    BOOL bTerminateUnconditionally - If this is set, the PAL will exit as
+    quickly as possible. In particular, it will not unload DLLs.
+
+Return value :
+    No return
+
+Note:
+  This function is used in ExitThread and TerminateProcess
+
+--*/
+VOID
+CorUnix::TerminateCurrentProcessNoExit(BOOL bTerminateUnconditionally)
+{
+    BOOL locked;
+    DWORD old_terminator;
+
+    old_terminator = InterlockedCompareExchange(&terminator, GetCurrentThreadId(), 0);
+
+    if (0 != old_terminator && GetCurrentThreadId() != old_terminator)
+    {
+        /* another thread has already initiated the termination process. we
+           could just block on the PALInitLock critical section, but then
+           PROCSuspendOtherThreads would hang... so sleep forever here, we're
+           terminating anyway
+
+           Update: [TODO] PROCSuspendOtherThreads has been removed. Can this
+           code be changed? */
+
+        /* note that if *this* thread has already started the termination
+           process, we want to proceed. the only way this can happen is if a
+           call to DllMain (from ExitProcess) brought us here (because DllMain
+           called ExitProcess, or TerminateProcess, or ExitThread);
+           TerminateProcess won't call DllMain, so there's no danger to get
+           caught in an infinite loop */
+        WARN("termination already started from another thread; blocking.\n");
+        poll(NULL, 0, INFTIM);
+    }
+
+    /* Try to lock the initialization count to prevent multiple threads from
+       terminating/initializing the PAL simultaneously */
+
+    /* note : it's also important to take this lock before the process lock,
+       because Init/Shutdown take the init lock, and the functions they call
+       may take the process lock. We must do it in the same order to avoid
+       deadlocks */
+
+    locked = PALInitLock();
+    if(locked && PALIsInitialized())
+    {
+        PALCommonCleanup();
+    }
+}
+#ifdef __APPLE__
+bool GetApplicationContainerFolder(PathCharString& buffer, const char *applicationGroupId, int applicationGroupIdLength)
+{
+    const char *homeDir = getpwuid(getuid())->pw_dir;
+    int homeDirLength = strlen(homeDir);
+
+    // The application group container folder is defined as:
+    // /user/{loginname}/Library/Group Containers/{AppGroupId}/
+    return buffer.Set(homeDir, homeDirLength)
+        && buffer.Append(APPLICATION_CONTAINER_BASE_PATH_SUFFIX)
+        && buffer.Append(applicationGroupId, applicationGroupIdLength)
+        && buffer.Append('/');
+}
+#endif // __APPLE__
+
+
+/* Internal function definitions **********************************************/
+
+/*++
+Function:
+  getFileName
+
+Abstract:
+    Helper function for CreateProcessW, it retrieves the executable filename
+    from the application name, and the command line.
+
+Parameters:
+    IN  lpApplicationName:  first parameter from CreateProcessW (an unicode string)
+    IN  lpCommandLine: second parameter from CreateProcessW (an unicode string)
+    OUT lpFileName: file to be executed (the new process)
+
+Return:
+    TRUE: if the file name is retrieved
+    FALSE: otherwise
+
+--*/
+static
+BOOL
+getFileName(
+       LPCWSTR lpApplicationName,
+       LPWSTR lpCommandLine,
+       PathCharString& lpPathFileName)
+{
+    LPWSTR lpEnd;
+    WCHAR wcEnd;
+    char * lpFileName;
+    PathCharString lpFileNamePS;
+    char *lpTemp;
+
+    if (lpApplicationName)
+    {
+        int length = WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1,
+                                            NULL, 0, NULL, NULL);
+
+        /* if only a file name is specified, prefix it with "./" */
+        if ((*lpApplicationName != '.') && (*lpApplicationName != '/') &&
+            (*lpApplicationName != '\\'))
+        {
+            length += 2;
+            lpTemp = lpPathFileName.OpenStringBuffer(length);
+
+            if (strcpy_s(lpTemp, length, "./") != SAFECRT_SUCCESS)
+            {
+                ERROR("strcpy_s failed!\n");
+                return FALSE;
+            }
+            lpTemp+=2;
+
+       }
+       else
+       {
+            lpTemp = lpPathFileName.OpenStringBuffer(length);
+       }
+
+        /* Convert to ASCII */
+        length = WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1,
+                                     lpTemp, length, NULL, NULL);
+        if (length == 0)
+        {
+            lpPathFileName.CloseBuffer(0);
+            ASSERT("WideCharToMultiByte failure\n");
+            return FALSE;
+        }
+
+        lpPathFileName.CloseBuffer(length -1);
+
+        /* Replace '\' by '/' */
+        FILEDosToUnixPathA(lpTemp);
+
+        return TRUE;
+    }
+    else
+    {
+        /* use the Command line */
+
+        /* filename should be the first token of the command line */
+
+        /* first skip all leading whitespace */
+        lpCommandLine = UTIL_inverse_wcspbrk(lpCommandLine,W16_WHITESPACE);
+        if(NULL == lpCommandLine)
+        {
+            ERROR("CommandLine contains only whitespace!\n");
+            return FALSE;
+        }
+
+        /* check if it is starting with a quote (") character */
+        if (*lpCommandLine == 0x0022)
+        {
+            lpCommandLine++; /* skip the quote */
+
+            /* file name ends with another quote */
+            lpEnd = PAL_wcschr(lpCommandLine+1, 0x0022);
+
+            /* if no quotes found, set lpEnd to the end of the Command line */
+            if (lpEnd == NULL)
+                lpEnd = lpCommandLine + PAL_wcslen(lpCommandLine);
+        }
+        else
+        {
+            /* filename is end out by a whitespace */
+            lpEnd = PAL_wcspbrk(lpCommandLine, W16_WHITESPACE);
+
+            /* if no whitespace found, set lpEnd to end of the Command line */
+            if (lpEnd == NULL)
+            {
+                lpEnd = lpCommandLine + PAL_wcslen(lpCommandLine);
+            }
+        }
+
+        if (lpEnd == lpCommandLine)
+        {
+            ERROR("application name and command line are both empty!\n");
+            return FALSE;
+        }
+
+        /* replace the last character by a null */
+        wcEnd = *lpEnd;
+        *lpEnd = 0x0000;
+
+        /* Convert to ASCII */
+        int size = 0;
+        int length = (PAL_wcslen(lpCommandLine)+1) * sizeof(WCHAR);
+        lpFileName = lpFileNamePS.OpenStringBuffer(length);
+        if (NULL == lpFileName)
+        {
+            ERROR("Not Enough Memory!\n");
+            return FALSE;
+        }
+        if (!(size = WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1,
+                                 lpFileName, length, NULL, NULL)))
+        {
+            ASSERT("WideCharToMultiByte failure\n");
+            return FALSE;
+        }
+
+        lpFileNamePS.CloseBuffer(size - 1);
+        /* restore last character */
+        *lpEnd = wcEnd;
+
+        /* Replace '\' by '/' */
+        FILEDosToUnixPathA(lpFileName);
+        if (!getPath(lpFileNamePS, lpPathFileName))
+        {
+            /* file is not in the path */
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/*++
+Function:
+    checkFileType
+
+Abstract:
+    Return the type of the file.
+
+Parameters:
+    IN  lpFileName:  file name
+
+Return:
+    FILE_DIR: Directory
+    FILE_UNIX: Unix executable file
+    FILE_ERROR: Error
+--*/
+static
+int
+checkFileType( LPCSTR lpFileName)
+{
+    struct stat stat_data;
+
+    /* check if the file exist */
+    if ( access(lpFileName, F_OK) != 0 )
+    {
+        return FILE_ERROR;
+    }
+
+    /* if it's not a PE/COFF file, check if it is executable */
+    if ( -1 != stat( lpFileName, &stat_data ) )
+    {
+        if((stat_data.st_mode & S_IFMT) == S_IFDIR )
+        {
+            /*The given file is a directory*/
+            return FILE_DIR;
+        }
+        if ( UTIL_IsExecuteBitsSet( &stat_data ) )
+        {
+            return FILE_UNIX;
+        }
+        else
+        {
+            return FILE_ERROR;
+        }
+    }
+    return FILE_ERROR;
+
+}
+
+
+/*++
+Function:
+  buildArgv
+
+Abstract:
+    Helper function for CreateProcessW, it builds the array of argument in
+    a format than can be passed to execve function.lppArgv is allocated
+    in this function and must be freed by the caller.
+
+Parameters:
+    IN  lpCommandLine: second parameter from CreateProcessW (an unicode string)
+    IN  lpAppPath: cannonical name of the application to launched
+    OUT lppArgv: array of arguments to be passed to the new process
+
+Return:
+    the number of arguments
+
+note: this doesn't yet match precisely the behavior of Windows, but should be
+sufficient.
+what's here:
+1) stripping nonquoted whitespace
+2) handling of quoted parameters and quoted "parts" of parameters, removal of
+   doublequotes (<aaaa"b bbb b"ccc> becomes <aaaab bbb bccc>)
+3) \" as an escaped doublequote, both within doublequoted sequences and out
+what's known missing :
+1) \\ as an escaped backslash, but only if the string of '\'
+   is followed by a " (escaped or not)
+2) "alternate" escape sequence : double-doublequote within a double-quoted
+    argument (<"aaa a""aa aaa">) expands to a single-doublequote(<aaa a"aa aaa>)
+note that there may be other special cases
+--*/
+static
+char **
+buildArgv(
+      LPCWSTR lpCommandLine,
+      PathCharString& lpAppPath,
+      UINT *pnArg)
+{
+    CPalThread *pThread = NULL;
+    UINT iWlen;
+    char *lpAsciiCmdLine;
+    char *pChar;
+    char **lppArgv;
+    char **lppTemp;
+    UINT i,j;
+
+    *pnArg = 0;
+
+    iWlen = WideCharToMultiByte(CP_ACP,0,lpCommandLine,-1,NULL,0,NULL,NULL);
+
+    if(0 == iWlen)
+    {
+        ASSERT("Can't determine length of command line\n");
+        return NULL;
+    }
+
+    pThread = InternalGetCurrentThread();
+    /* make sure to allocate enough space, up for the worst case scenario */
+    int iLength = (iWlen + lpAppPath.GetCount() + 2);
+    lpAsciiCmdLine = (char *) InternalMalloc(iLength);
+
+    if (lpAsciiCmdLine == NULL)
+    {
+        ERROR("Unable to allocate memory\n");
+        return NULL;
+    }
+
+    pChar = lpAsciiCmdLine;
+
+    /* put the cannonical name of the application as the first parameter */
+    if ((strcpy_s(lpAsciiCmdLine, iLength, "\"") != SAFECRT_SUCCESS) ||
+        (strcat_s(lpAsciiCmdLine, iLength, lpAppPath) != SAFECRT_SUCCESS) ||
+        (strcat_s(lpAsciiCmdLine, iLength,  "\"") != SAFECRT_SUCCESS) ||
+        (strcat_s(lpAsciiCmdLine, iLength, " ") != SAFECRT_SUCCESS))
+    {
+        ERROR("strcpy_s/strcat_s failed!\n");
+        return NULL;
+    }
+
+    pChar = lpAsciiCmdLine + strlen (lpAsciiCmdLine);
+
+    /* let's skip the first argument in the command line */
+
+    /* strip leading whitespace; function returns NULL if there's only
+        whitespace, so the if statement below will work correctly */
+    lpCommandLine = UTIL_inverse_wcspbrk((LPWSTR)lpCommandLine, W16_WHITESPACE);
+
+    if (lpCommandLine)
+    {
+        LPCWSTR stringstart = lpCommandLine;
+
+        do
+        {
+            /* find first whitespace or dquote character */
+            lpCommandLine = PAL_wcspbrk(lpCommandLine,W16_WHITESPACE_DQUOTE);
+            if(NULL == lpCommandLine)
+            {
+                /* no whitespace or dquote found : first arg is only arg */
+                break;
+            }
+            else if('"' == *lpCommandLine)
+            {
+                /* got a dquote; skip over it if it's escaped; make sure we
+                    don't try to look before the first character in the
+                    string */
+                if(lpCommandLine > stringstart && '\\' == lpCommandLine[-1])
+                {
+                    lpCommandLine++;
+                    continue;
+                }
+
+                /* found beginning of dquoted sequence, run to the end */
+                /* don't stop if we hit an escaped dquote */
+                lpCommandLine++;
+                while( *lpCommandLine )
+                {
+                    lpCommandLine = PAL_wcschr(lpCommandLine, '"');
+                    if(NULL == lpCommandLine)
+                    {
+                        /* no ending dquote, arg runs to end of string */
+                        break;
+                    }
+                    if('\\' != lpCommandLine[-1])
+                    {
+                        /* dquote is not escaped, dquoted sequence is over*/
+                        break;
+                    }
+                    lpCommandLine++;
+                }
+                if(NULL == lpCommandLine || '\0' == *lpCommandLine)
+                {
+                    /* no terminating dquote */
+                    break;
+                }
+
+                /* step over dquote, keep looking for end of arg */
+                lpCommandLine++;
+            }
+            else
+            {
+                /* found whitespace : end of arg. */
+                lpCommandLine++;
+                break;
+            }
+        }while(lpCommandLine);
+    }
+
+    /* Convert to ASCII */
+    if (lpCommandLine)
+    {
+        if (!WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1,
+                                 pChar, iWlen+1, NULL, NULL))
+        {
+            ASSERT("Unable to convert to a multibyte string\n");
+            free(lpAsciiCmdLine);
+            return NULL;
+        }
+    }
+
+    pChar = lpAsciiCmdLine;
+
+    /* loops through all the arguments, to find out how many arguments there
+       are; while looping replace whitespace by \0 */
+
+    /* skip leading whitespace (and replace by '\0') */
+    /* note : there shouldn't be any, command starts either with PE loader name
+       or computed application path, but this won't hurt */
+    while (*pChar)
+    {
+        if (!isspace((unsigned char) *pChar))
+        {
+           break;
+        }
+        WARN("unexpected whitespace in command line!\n");
+        *pChar++ = '\0';
+    }
+
+    while (*pChar)
+    {
+        (*pnArg)++;
+
+        /* find end of current arg */
+        while(*pChar && !isspace((unsigned char) *pChar))
+        {
+            if('"' == *pChar)
+            {
+                /* skip over dquote if it's escaped; make sure we don't try to
+                   look before the start of the string for the \ */
+                if(pChar > lpAsciiCmdLine && '\\' == pChar[-1])
+                {
+                    pChar++;
+                    continue;
+                }
+
+                /* found leading dquote : look for ending dquote */
+                pChar++;
+                while (*pChar)
+                {
+                    pChar = strchr(pChar,'"');
+                    if(NULL == pChar)
+                    {
+                        /* no ending dquote found : argument extends to the end
+                           of the string*/
+                        break;
+                    }
+                    if('\\' != pChar[-1])
+                    {
+                        /* found a dquote, and it's not escaped : quoted
+                           sequence is over*/
+                        break;
+                    }
+                    /* found a dquote, but it was escaped : skip over it, keep
+                       looking */
+                    pChar++;
+                }
+                if(NULL == pChar || '\0' == *pChar)
+                {
+                    /* reached the end of the string : we're done */
+                    break;
+                }
+            }
+            pChar++;
+        }
+        if(NULL == pChar)
+        {
+            /* reached the end of the string : we're done */
+            break;
+        }
+        /* reached end of arg; replace trailing whitespace by '\0', to split
+           arguments into separate strings */
+        while (isspace((unsigned char) *pChar))
+        {
+            *pChar++ = '\0';
+        }
+    }
+
+    /* allocate lppargv according to the number of arguments
+       in the command line */
+    lppArgv = (char **) InternalMalloc((((*pnArg)+1) * sizeof(char *)));
+
+    if (lppArgv == NULL)
+    {
+        free(lpAsciiCmdLine);
+        return NULL;
+    }
+
+    lppTemp = lppArgv;
+
+    /* at this point all parameters are separated by NULL
+       we need to fill the array of arguments; we must also remove all dquotes
+       from arguments (new process shouldn't see them) */
+    for (i = *pnArg, pChar = lpAsciiCmdLine; i; i--)
+    {
+        /* skip NULLs */
+        while (!*pChar)
+        {
+            pChar++;
+        }
+
+        *lppTemp = pChar;
+
+        /* go to the next parameter, removing dquotes as we go along */
+        j = 0;
+        while (*pChar)
+        {
+            /* copy character if it's not a dquote */
+            if('"' != *pChar)
+            {
+                /* if it's the \ of an escaped dquote, skip over it, we'll
+                   copy the " instead */
+                if( '\\' == pChar[0] && '"' == pChar[1] )
+                {
+                    pChar++;
+                }
+                (*lppTemp)[j++] = *pChar;
+            }
+            pChar++;
+        }
+        /* re-NULL terminate the argument */
+        (*lppTemp)[j] = '\0';
+
+        lppTemp++;
+    }
+
+    *lppTemp = NULL;
+
+    return lppArgv;
+}
+
+
+/*++
+Function:
+  getPath
+
+Abstract:
+    Helper function for CreateProcessW, it looks in the path environment
+    variable to find where the process to executed is.
+
+Parameters:
+    IN  lpFileName: file name to search in the path
+    OUT lpPathFileName: returned string containing the path and the filename
+
+Return:
+    TRUE if found
+    FALSE otherwise
+--*/
+static
+BOOL
+getPath(
+      PathCharString& lpFileNameString,
+      PathCharString& lpPathFileName)
+{
+    LPSTR lpPath;
+    LPSTR lpNext;
+    LPSTR lpCurrent;
+    LPWSTR lpwstr;
+    INT n;
+    INT nextLen;
+    INT slashLen;
+    CPalThread *pThread = NULL;
+    LPCSTR lpFileName = lpFileNameString.GetString();
+
+    /* if a path is specified, only look there */
+    if(strchr(lpFileName, '/'))
+    {
+        if (access (lpFileName, F_OK) == 0)
+        {
+            if (!lpPathFileName.Set(lpFileNameString))
+            {
+                TRACE("Set of StackString failed!\n");
+                return FALSE;
+            }
+
+            TRACE("file %s exists\n", lpFileName);
+            return TRUE;
+        }
+        else
+        {
+            TRACE("file %s doesn't exist.\n", lpFileName);
+            return FALSE;
+        }
+    }
+
+    /* first look in directory from which the application loaded */
+    lpwstr = g_lpwstrAppDir;
+
+    if (lpwstr)
+    {
+        /* convert path to multibyte, check buffer size */
+        n = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, NULL, 0,
+            NULL, NULL);
+
+        if (!lpPathFileName.Reserve(n + lpFileNameString.GetCount() + 1 ))
+        {
+            ERROR("StackString Reserve failed!\n");
+            return FALSE;
+        }
+
+        lpPath = lpPathFileName.OpenStringBuffer(n);
+
+        n = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, lpPath, n,
+            NULL, NULL);
+
+        if (n == 0)
+        {
+            lpPathFileName.CloseBuffer(0);
+            ASSERT("WideCharToMultiByte failure!\n");
+            return FALSE;
+        }
+
+        lpPathFileName.CloseBuffer(n - 1);
+
+        lpPathFileName.Append("/", 1);
+        lpPathFileName.Append(lpFileNameString);
+
+        if (access(lpPathFileName, F_OK) == 0)
+        {
+            TRACE("found %s in application directory (%s)\n", lpFileName, lpPathFileName.GetString());
+            return TRUE;
+        }
+    }
+
+    /* then try the current directory */
+    if (!lpPathFileName.Reserve(lpFileNameString.GetCount()  + 2))
+    {
+        ERROR("StackString Reserve failed!\n");
+        return FALSE;
+    }
+
+    lpPathFileName.Set("./", 2);
+    lpPathFileName.Append(lpFileNameString);
+
+    if (access (lpPathFileName, R_OK) == 0)
+    {
+        TRACE("found %s in current directory.\n", lpFileName);
+        return TRUE;
+    }
+
+    pThread = InternalGetCurrentThread();
+
+    /* Then try to look in the path */
+    lpPath = EnvironGetenv("PATH");
+
+    if (!lpPath)
+    {
+        ERROR("EnvironGetenv returned NULL for $PATH\n");
+        return FALSE;
+    }
+
+    lpNext = lpPath;
+
+    /* search in every path directory */
+    TRACE("looking for file %s in $PATH (%s)\n", lpFileName, lpPath);
+    while (lpNext)
+    {
+        /* skip all leading ':' */
+        while(*lpNext==':')
+        {
+            lpNext++;
+        }
+
+        /* search for ':' */
+        lpCurrent = strchr(lpNext, ':');
+        if (lpCurrent)
+        {
+            *lpCurrent++ = '\0';
+        }
+
+        nextLen = strlen(lpNext);
+        slashLen = (lpNext[nextLen-1] == '/') ? 0:1;
+
+        if (!lpPathFileName.Reserve(nextLen + lpFileNameString.GetCount() + 1))
+        {
+            free(lpPath);
+            ERROR("StackString ran out of memory for full path\n");
+            return FALSE;
+        }
+
+        lpPathFileName.Set(lpNext, nextLen);
+
+        if( slashLen == 1)
+        {
+            /* append a '/' if there's no '/' at the end of the path */
+            lpPathFileName.Append("/", 1);
+        }
+
+        lpPathFileName.Append(lpFileNameString);
+
+        if ( access (lpPathFileName, F_OK) == 0)
+        {
+            TRACE("Found %s in $PATH element %s\n", lpFileName, lpNext);
+            free(lpPath);
+            return TRUE;
+        }
+
+        lpNext = lpCurrent;  /* search in the next directory */
+    }
+
+    free(lpPath);
+    TRACE("File %s not found in $PATH\n", lpFileName);
+    return FALSE;
+}
+
+/*++
+Function:
+    ~CProcProcessLocalData
+
+Process data destructor
+--*/
+CorUnix::CProcProcessLocalData::~CProcProcessLocalData()
+{
+    if (pProcessModules != NULL)
+    {
+        DestroyProcessModules(pProcessModules);
+    }
+}
+
diff --git a/src/pal/src/thread/procprivate.hpp b/src/pal/src/thread/procprivate.hpp
new file mode 100644 (file)
index 0000000..4f3af27
--- /dev/null
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*++
+
+
+
+Module Name:
+
+    thread/procprivate.hpp
+
+Abstract:
+
+    Private process structures and routines
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_PROCPRIVATE_HPP_
+#define _PAL_PROCPRIVATE_HPP_
+
+#include "pal/thread.hpp"
+
+namespace CorUnix
+{
+
+    /*++
+    Function:
+      PROCAddThread
+
+    Abstract
+      Add a thread to the thread list of the current process
+    --*/
+    void PROCAddThread(CPalThread *pCurrentThread, CPalThread *pTargetThread);
+
+    extern CPalThread *pGThreadList;
+
+    /*++
+    Function:
+      PROCRemoveThread
+
+    Abstract
+      Remove a thread form the thread list of the current process
+    --*/
+    void PROCRemoveThread(CPalThread *pCurrentThread, CPalThread *pTargetThread);
+
+    /*++
+    Function:
+      PROCGetNumberOfThreads
+
+    Abstract
+      Return the number of threads in the thread list.
+    --*/
+    INT PROCGetNumberOfThreads(void);
+
+
+    /*++
+    Function:
+      TerminateCurrentProcessNoExit
+
+    Parameters:
+        BOOL bTerminateUnconditionally - If this is set, the PAL will exit as
+        quickly as possible. In particular, it will not unload DLLs.
+
+    Abstract:
+        Terminate Current Process, but leave the caller alive
+    --*/
+    void TerminateCurrentProcessNoExit(BOOL bTerminateUnconditionally);
+
+}
+
+#endif //_PAL_PROCPRIVATE_HPP_
+
+
index 47b6819b426a965c3631017f59f41325dfc8113c..638058620c76bf2a81e45422ba0dfe71d8646bce 100644 (file)
@@ -22,13 +22,16 @@ SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do
 
 #include "pal/corunix.hpp"
 #include "pal/thread.hpp"
+#include "pal/mutex.hpp"
 #include "pal/handlemgr.hpp"
 #include "pal/cs.hpp"
+#include "procprivate.hpp"
 #include "pal/process.h"
 #include "pal/module.h"
 #include "pal/environ.h"
 #include "pal/init.h"
 #include "pal/utils.h"
+#include "pal/virtual.h"
 
 #if defined(__NetBSD__) && !HAVE_PTHREAD_GETCPUCLOCKID
 #include <sys/cdefs.h>
@@ -78,6 +81,46 @@ extern "C" int _lwp_self ();
 
 using namespace CorUnix;
 
+void
+ThreadCleanupRoutine(
+    CPalThread *pThread,
+    IPalObject *pObjectToCleanup,
+    bool fShutdown,
+    bool fCleanupSharedState
+    );
+
+PAL_ERROR
+ThreadInitializationRoutine(
+    CPalThread *pThread,
+    CObjectType *pObjectType,
+    void *pImmutableData,
+    void *pSharedData,
+    void *pProcessLocalData
+    );
+
+CObjectType CorUnix::otThread(
+                otiThread,
+                ThreadCleanupRoutine,
+                ThreadInitializationRoutine,
+                0,      // sizeof(CThreadImmutableData),
+                NULL,   // No immutable data copy routine
+                NULL,   // No immutable data cleanup routine
+                sizeof(CThreadProcessLocalData),
+                NULL,   // No process local data cleanup routine
+                0,      // sizeof(CThreadSharedData),
+                0,      // THREAD_ALL_ACCESS,
+                CObjectType::SecuritySupported,
+                CObjectType::SecurityInfoNotPersisted,
+                CObjectType::UnnamedObject,
+                CObjectType::LocalDuplicationOnly,
+                CObjectType::WaitableObject,
+                CObjectType::SingleTransitionObject,
+                CObjectType::ThreadReleaseHasNoSideEffects,
+                CObjectType::NoOwner
+                );
+
+CAllowedObjectTypes aotThread(otiThread);
+
 /*++
 Function:
   InternalEndCurrentThreadWrapper
@@ -105,6 +148,7 @@ static void InternalEndCurrentThreadWrapper(void *arg)
        will lock its own critical section */
     LOADCallDllMain(DLL_THREAD_DETACH, NULL);
 
+    InternalEndCurrentThread(pThread);
     pthread_setspecific(thObjKey, NULL);
 }
 
@@ -177,7 +221,546 @@ static void FreeTHREAD(CPalThread *pThread)
 
     free(pThread);
 }
+/*++
+Function:
+  GetCurrentThreadId
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetCurrentThreadId(
+            VOID)
+{
+    DWORD dwThreadId;
+
+    PERF_ENTRY(GetCurrentThreadId);
+    ENTRY("GetCurrentThreadId()\n");
+
+    //
+    // TODO: should do perf test to see how this compares
+    // with calling InternalGetCurrentThread (i.e., is our lookaside
+    // cache faster on average than pthread_self?)
+    //
+
+    dwThreadId = (DWORD)THREADSilentGetCurrentThreadId();
+
+    LOGEXIT("GetCurrentThreadId returns DWORD %#x\n", dwThreadId);
+    PERF_EXIT(GetCurrentThreadId);
+
+    return dwThreadId;
+}
+
+PAL_ERROR
+CorUnix::InternalCreateThread(
+    CPalThread *pThread,
+    LPSECURITY_ATTRIBUTES lpThreadAttributes,
+    DWORD dwStackSize,
+    LPTHREAD_START_ROUTINE lpStartAddress,
+    LPVOID lpParameter,
+    DWORD dwCreationFlags,
+    PalThreadType eThreadType,
+    SIZE_T* pThreadId,
+    HANDLE *phThread
+    )
+{
+    PAL_ERROR palError;
+    CPalThread *pNewThread = NULL;
+    CObjectAttributes oa;
+    bool fAttributesInitialized = FALSE;
+    bool fThreadDataAddedToProcessList = FALSE;
+    HANDLE hNewThread = NULL;
+
+    pthread_t pthread;
+    pthread_attr_t pthreadAttr;
+#if PTHREAD_CREATE_MODIFIES_ERRNO
+    int storedErrno;
+#endif  // PTHREAD_CREATE_MODIFIES_ERRNO
+    BOOL fHoldingProcessLock = FALSE;
+    int iError = 0;
+    size_t alignedStackSize;
+
+    /* Validate parameters */
+
+    if (lpThreadAttributes != NULL)
+    {
+        ASSERT("lpThreadAttributes parameter must be NULL (%p)\n",
+               lpThreadAttributes);
+        palError = ERROR_INVALID_PARAMETER;
+        goto EXIT;
+    }
+
+    alignedStackSize = dwStackSize;
+    if (alignedStackSize != 0)
+    {
+        // Some systems require the stack size to be aligned to the page size
+        if (sizeof(alignedStackSize) <= sizeof(dwStackSize) && alignedStackSize + (GetVirtualPageSize() - 1) < alignedStackSize)
+        {
+            // When coming here from the public API surface, the incoming value is originally a nonnegative signed int32, so
+            // this shouldn't happen
+            ASSERT(
+                "Couldn't align the requested stack size (%Iu) to the page size because the stack size was too large\n",
+                alignedStackSize);
+            palError = ERROR_INVALID_PARAMETER;
+            goto EXIT;
+        }
+        alignedStackSize = ALIGN_UP(alignedStackSize, GetVirtualPageSize());
+    }
+
+    // Ignore the STACK_SIZE_PARAM_IS_A_RESERVATION flag
+    dwCreationFlags &= ~STACK_SIZE_PARAM_IS_A_RESERVATION;
+
+    if ((dwCreationFlags != 0) && (dwCreationFlags != CREATE_SUSPENDED))
+    {
+        ASSERT("dwCreationFlags parameter is invalid (%#x)\n", dwCreationFlags);
+        palError = ERROR_INVALID_PARAMETER;
+        goto EXIT;
+    }
+
+    //
+    // Create the CPalThread for the thread
+    //
+
+    pNewThread = AllocTHREAD();
+    if (NULL == pNewThread)
+    {
+        palError = ERROR_OUTOFMEMORY;
+        goto EXIT;
+    }
+
+    palError = pNewThread->RunPreCreateInitializers();
+    if (NO_ERROR != palError)
+    {
+        goto EXIT;
+    }
+
+    pNewThread->m_lpStartAddress = lpStartAddress;
+    pNewThread->m_lpStartParameter = lpParameter;
+    pNewThread->m_bCreateSuspended = (dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED;
+    pNewThread->m_eThreadType = eThreadType;
+
+    if (0 != pthread_attr_init(&pthreadAttr))
+    {
+        ERROR("couldn't initialize pthread attributes\n");
+        palError = ERROR_INTERNAL_ERROR;
+        goto EXIT;
+    }
+
+    fAttributesInitialized = TRUE;
+
+    if (alignedStackSize == 0)
+    {
+        // The thread is to be created with default stack size. Use the default stack size
+        // override that was determined during the PAL initialization.
+        alignedStackSize = g_defaultStackSize;
+    }
+
+    /* adjust the stack size if necessary */
+    if (alignedStackSize != 0)
+    {
+#ifdef PTHREAD_STACK_MIN
+        size_t MinStackSize = ALIGN_UP(PTHREAD_STACK_MIN, GetVirtualPageSize());
+#else // !PTHREAD_STACK_MIN
+        size_t MinStackSize = 64 * 1024; // this value is typically accepted by pthread_attr_setstacksize()
+#endif // PTHREAD_STACK_MIN
+        if (alignedStackSize < MinStackSize)
+        {
+            // Adjust the stack size to a minimum value that is likely to be accepted by pthread_attr_setstacksize(). If this
+            // function fails, typically the caller will end up throwing OutOfMemoryException under the assumption that the
+            // requested stack size is too large or the system does not have sufficient memory to create a thread. Try to
+            // prevent failing just just because the stack size value is too low.
+            alignedStackSize = MinStackSize;
+        }
+
+        TRACE("setting thread stack size to %Iu\n", alignedStackSize);
+        if (0 != pthread_attr_setstacksize(&pthreadAttr, alignedStackSize))
+        {
+            ERROR("couldn't set pthread stack size to %Iu\n", alignedStackSize);
+            palError = ERROR_INTERNAL_ERROR;
+            goto EXIT;
+        }
+    }
+    else
+    {
+        TRACE("using the system default thread stack size\n");
+    }
+
+#if HAVE_THREAD_SELF || HAVE__LWP_SELF
+    /* Create new threads as "bound", so each pthread is permanently bound
+       to an LWP.  Get/SetThreadContext() depend on this 1:1 mapping. */
+    pthread_attr_setscope(&pthreadAttr, PTHREAD_SCOPE_SYSTEM);
+#endif // HAVE_THREAD_SELF || HAVE__LWP_SELF
+
+    //
+    // We never call pthread_join, so create the new thread as detached
+    //
+
+    iError = pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED);
+    _ASSERTE(0 == iError);
+
+    //
+    // Create the IPalObject for the thread and store it in the object
+    //
+
+    palError = CreateThreadObject(
+        pThread,
+        pNewThread,
+        &hNewThread);
+
+    if (NO_ERROR != palError)
+    {
+        goto EXIT;
+    }
+
+    //
+    // Add the thread to the process list
+    //
+
+    //
+    // We use the process lock to ensure that we're not interrupted
+    // during the creation process. After adding the CPalThread reference
+    // to the process list, we want to make sure the actual thread has been
+    // started. Otherwise, there's a window where the thread can be found
+    // in the process list but doesn't yet exist in the system.
+    //
+
+    PROCProcessLock();
+    fHoldingProcessLock = TRUE;
+
+    PROCAddThread(pThread, pNewThread);
+    fThreadDataAddedToProcessList = TRUE;
+
+    //
+    // Spawn the new pthread
+    //
+
+#if PTHREAD_CREATE_MODIFIES_ERRNO
+    storedErrno = errno;
+#endif  // PTHREAD_CREATE_MODIFIES_ERRNO
+
+    iError = pthread_create(&pthread, &pthreadAttr, CPalThread::ThreadEntry, pNewThread);
+
+#if PTHREAD_CREATE_MODIFIES_ERRNO
+    if (iError == 0)
+    {
+        // Restore errno if pthread_create succeeded.
+        errno = storedErrno;
+    }
+#endif  // PTHREAD_CREATE_MODIFIES_ERRNO
+
+    if (0 != iError)
+    {
+        ERROR("pthread_create failed, error is %d (%s)\n", iError, strerror(iError));
+        palError = ERROR_NOT_ENOUGH_MEMORY;
+        goto EXIT;
+    }
+
+    //
+    // Wait for the new thread to finish its initial startup tasks
+    // (i.e., the ones that might fail)
+    //
+    if (pNewThread->WaitForStartStatus())
+    {
+        //
+        // Everything succeeded. Store the handle for the new thread and
+        // the thread's ID in the out params
+        //
+        *phThread = hNewThread;
+
+        if (NULL != pThreadId)
+        {
+            *pThreadId = pNewThread->GetThreadId();
+        }
+    }
+    else
+    {
+        ERROR("error occurred in THREADEntry, thread creation failed.\n");
+        palError = ERROR_INTERNAL_ERROR;
+        goto EXIT;
+    }
+
+    //
+    // If we're here, then we've locked the process list and both pthread_create
+    // and WaitForStartStatus succeeded. Thus, we can now unlock the process list.
+    // Since palError == NO_ERROR, we won't call this again in the exit block.
+    //
+    PROCProcessUnlock();
+    fHoldingProcessLock = FALSE;
+
+EXIT:
+
+    if (fAttributesInitialized)
+    {
+        if (0 != pthread_attr_destroy(&pthreadAttr))
+        {
+            WARN("pthread_attr_destroy() failed\n");
+        }
+    }
+
+    if (NO_ERROR != palError)
+    {
+        //
+        // We either were not able to create the new thread, or a failure
+        // occurred in the new thread's entry routine. Free up the associated
+        // resources here
+        //
+
+        if (fThreadDataAddedToProcessList)
+        {
+            PROCRemoveThread(pThread, pNewThread);
+        }
+        //
+        // Once we remove the thread from the process list, we can call
+        // PROCProcessUnlock.
+        //
+        if (fHoldingProcessLock)
+        {
+            PROCProcessUnlock();
+        }
+        fHoldingProcessLock = FALSE;
+    }
+
+    _ASSERT_MSG(!fHoldingProcessLock, "Exiting InternalCreateThread while still holding the process critical section.\n");
+
+    return palError;
+}
+
+/*++
+Function:
+  InternalEndCurrentThread
+
+Does any necessary memory clean up, signals waiting threads, and then forces
+the current thread to exit.
+--*/
+
+VOID
+CorUnix::InternalEndCurrentThread(
+    CPalThread *pThread
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    ISynchStateController *pSynchStateController = NULL;
+
+#ifdef PAL_PERF
+    PERFDisableThreadProfile(UserCreatedThread != pThread->GetThreadType());
+#endif
+
+    //
+    // Abandon any objects owned by this thread
+    //
+
+    palError = g_pSynchronizationManager->AbandonObjectsOwnedByThread(
+        pThread,
+        pThread
+        );
+
+    if (NO_ERROR != palError)
+    {
+        ERROR("Failure abandoning owned objects");
+    }
+
+    //
+    // Need to synchronize setting the thread state to TS_DONE since
+    // this is checked for in InternalSuspendThreadFromData.
+    // TODO: Is this still needed after removing InternalSuspendThreadFromData?
+    //
+
+    pThread->suspensionInfo.AcquireSuspensionLock(pThread);
+    pThread->synchronizationInfo.SetThreadState(TS_DONE);
+    pThread->suspensionInfo.ReleaseSuspensionLock(pThread);
+
+    //
+    // Mark the thread object as signaled
+    //
+
+    palError = pThread->GetThreadObject()->GetSynchStateController(
+        pThread,
+        &pSynchStateController
+        );
+
+    if (NO_ERROR == palError)
+    {
+        palError = pSynchStateController->SetSignalCount(1);
+        if (NO_ERROR != palError)
+        {
+            ASSERT("Unable to mark thread object as signaled");
+        }
+
+        pSynchStateController->ReleaseController();
+    }
+    else
+    {
+        ASSERT("Unable to obtain state controller for thread");
+    }
+
+    //
+    // Add a reference to the thread data before releasing the
+    // thread object, so we can still use it
+    //
+
+    pThread->AddThreadReference();
+
+    //
+    // Release the reference to the IPalObject for this thread
+    //
+
+    pThread->GetThreadObject()->ReleaseReference(pThread);
+
+    /* Remove thread for the thread list of the process
+        (don't do if this is the last thread -> gets handled by
+        TerminateProcess->PROCCleanupProcess->PROCTerminateOtherThreads) */
+
+    PROCRemoveThread(pThread, pThread);
+
+    //
+    // Now release our reference to the thread data. We cannot touch
+    // it after this point
+    //
+
+    pThread->ReleaseThreadReference();
+}
+
     
+void *
+CPalThread::ThreadEntry(
+    void *pvParam
+    )
+{
+    PAL_ERROR palError;
+    CPalThread *pThread;
+    PTHREAD_START_ROUTINE pfnStartRoutine;
+    LPVOID pvPar;
+    DWORD retValue;
+#if HAVE_SCHED_GETAFFINITY && HAVE_SCHED_SETAFFINITY
+    cpu_set_t cpuSet;
+    int st;
+#endif
+
+    pThread = reinterpret_cast<CPalThread*>(pvParam);
+
+    if (NULL == pThread)
+    {
+        ASSERT("THREAD pointer is NULL!\n");
+        goto fail;
+    }
+
+#if HAVE_SCHED_GETAFFINITY && HAVE_SCHED_SETAFFINITY
+    // Threads inherit their parent's affinity mask on Linux. This is not desired, so we reset
+    // the current thread's affinity mask to the mask of the current process.
+    //
+    // Typically, we would use pthread_attr_setaffinity_np() and have pthread_create() create the thread with the specified
+    // affinity. At least one implementation of pthread_create() following a pthread_attr_setaffinity_np() calls
+    // sched_setaffinity(<newThreadPid>, ...), which is not allowed under Snap's default strict confinement without manually
+    // connecting the process-control plug. To work around that, have the thread set the affinity after it starts.
+    // sched_setaffinity(<currentThreadPid>, ...) is also currently not allowed, only sched_setaffinity(0, ...).
+    // pthread_setaffinity_np(pthread_self(), ...) seems to call sched_setaffinity(<currentThreadPid>, ...) in at least one
+    // implementation, and does not work. Use sched_setaffinity(0, ...) instead. See the following for more information:
+    // - https://github.com/dotnet/runtime/pull/38795
+    // - https://github.com/dotnet/runtime/issues/1634
+    // - https://forum.snapcraft.io/t/requesting-autoconnect-for-interfaces-in-pigmeat-process-control-home/17987/13
+
+    CPU_ZERO(&cpuSet);
+
+    st = sched_getaffinity(gPID, sizeof(cpu_set_t), &cpuSet);
+    if (st != 0)
+    {
+        ASSERT("sched_getaffinity failed!\n");
+        // The sched_getaffinity should never fail for getting affinity of the current process
+        palError = ERROR_INTERNAL_ERROR;
+        goto fail;
+    }
+
+    st = sched_setaffinity(0, sizeof(cpu_set_t), &cpuSet);
+    if (st != 0)
+    {
+        ASSERT("sched_setaffinity failed!\n");
+        // The sched_setaffinity should never fail when passed the mask extracted using sched_getaffinity
+        palError = ERROR_INTERNAL_ERROR;
+        goto fail;
+    }
+#endif // HAVE_SCHED_GETAFFINITY && HAVE_SCHED_SETAFFINITY
+
+    pThread->m_threadId = THREADSilentGetCurrentThreadId();
+    pThread->m_pthreadSelf = pthread_self();
+#if HAVE_THREAD_SELF
+    pThread->m_dwLwpId = (DWORD) thread_self();
+#elif HAVE__LWP_SELF
+    pThread->m_dwLwpId = (DWORD) _lwp_self();
+#else
+    pThread->m_dwLwpId = 0;
+#endif
+
+    palError = pThread->RunPostCreateInitializers();
+    if (NO_ERROR != palError)
+    {
+        ASSERT("Error %i initializing thread data (post creation)\n", palError);
+        goto fail;
+    }
+
+    // Check if the thread should be started suspended.
+    if (pThread->GetCreateSuspended())
+    {
+        palError = pThread->suspensionInfo.InternalSuspendNewThreadFromData(pThread);
+        if (NO_ERROR != palError)
+        {
+            ASSERT("Error %i attempting to suspend new thread\n", palError);
+            goto fail;
+        }
+    }
+    else
+    {
+        //
+        // All startup operations that might have failed have succeeded,
+        // so thread creation is successful. Let CreateThread return.
+        //
+
+        pThread->SetStartStatus(TRUE);
+    }
+
+    pThread->synchronizationInfo.SetThreadState(TS_RUNNING);
+
+    if (UserCreatedThread == pThread->GetThreadType())
+    {
+        /* Inform all loaded modules that a thread has been created */
+        /* note : no need to take a critical section to serialize here; the loader
+           will take the module critical section */
+        LOADCallDllMain(DLL_THREAD_ATTACH, NULL);
+    }
+
+#ifdef PAL_PERF
+    PERFAllocThreadInfo();
+    PERFEnableThreadProfile(UserCreatedThread != pThread->GetThreadType());
+#endif
+
+    /* call the startup routine */
+    pfnStartRoutine = pThread->GetStartAddress();
+    pvPar = pThread->GetStartParameter();
+
+    retValue = (*pfnStartRoutine)(pvPar);
+
+    TRACE("Thread exited (%u)\n", retValue);
+    pThread->SetExitCode(retValue);
+
+    return NULL;
+
+fail:
+
+    //
+    // Notify InternalCreateThread that a failure occurred
+    //
+
+    if (NULL != pThread)
+    {
+        pThread->synchronizationInfo.SetThreadState(TS_FAILED);
+        pThread->SetStartStatus(FALSE);
+    }
+
+    /* do not call ExitThread : we don't want to call DllMain(), and the thread
+       isn't in a clean state (e.g. lpThread isn't in TLS). the cleanup work
+       above should release all resources */
+    return NULL;
+}
+
 /*++
 Function:
     CreateThreadData
@@ -251,6 +834,316 @@ CreateThreadDataExit:
     return palError;
 }
 
+/*++
+Function:
+    CreateThreadData
+
+Abstract:
+    Creates the IPalObject for a thread, storing
+    the reference in the CPalThread
+
+Parameters:
+    pThread - the thread data for the creating thread
+    pNewThread - the thread data for the thread being initialized
+
+Return:
+   PAL_ERROR
+--*/
+
+PAL_ERROR
+CorUnix::CreateThreadObject(
+    CPalThread *pThread,
+    CPalThread *pNewThread,
+    HANDLE *phThread
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    IPalObject *pobjThread = NULL;
+    IDataLock *pDataLock;
+    HANDLE hThread = NULL;
+    CThreadProcessLocalData *pLocalData = NULL;
+    CObjectAttributes oa;
+    BOOL fThreadDataStoredInObject = FALSE;
+    IPalObject *pobjRegisteredThread = NULL;
+
+    //
+    // Create the IPalObject for the thread
+    //
+
+    palError = g_pObjectManager->AllocateObject(
+        pThread,
+        &otThread,
+        &oa,
+        &pobjThread
+        );
+
+    if (NO_ERROR != palError)
+    {
+        goto CreateThreadObjectExit;
+    }
+
+    //
+    // Store the CPalThread inside of the IPalObject
+    //
+
+    palError = pobjThread->GetProcessLocalData(
+        pThread,
+        WriteLock,
+        &pDataLock,
+        reinterpret_cast<void **>(&pLocalData)
+        );
+
+    if (NO_ERROR != palError)
+    {
+        goto CreateThreadObjectExit;
+    }
+
+    pLocalData->pThread = pNewThread;
+    pDataLock->ReleaseLock(pThread, TRUE);
+    fThreadDataStoredInObject = TRUE;
+
+    //
+    // Register the IPalObject (obtaining a handle)
+    //
+
+    palError = g_pObjectManager->RegisterObject(
+        pThread,
+        pobjThread,
+        &aotThread,
+        &hThread,
+        &pobjRegisteredThread
+        );
+
+    //
+    // pobjThread is invalidated by the call to RegisterObject, so NULL
+    // it out here to prevent it from being released
+    //
+
+    pobjThread = NULL;
+
+    if (NO_ERROR != palError)
+    {
+        goto CreateThreadObjectExit;
+    }
+
+    //
+    // Store the registered object inside of the thread object,
+    // adding a reference for the thread itself
+    //
+
+    pNewThread->m_pThreadObject = pobjRegisteredThread;
+    pNewThread->m_pThreadObject->AddReference();
+
+    *phThread = hThread;
+
+CreateThreadObjectExit:
+
+    if (NO_ERROR != palError)
+    {
+        if (NULL != hThread)
+        {
+            g_pObjectManager->RevokeHandle(pThread, hThread);
+        }
+
+        if (NULL != pNewThread->m_pThreadObject)
+        {
+            //
+            // Release the new thread's reference on the underlying thread
+            // object
+            //
+
+            pNewThread->m_pThreadObject->ReleaseReference(pThread);
+        }
+
+        if (!fThreadDataStoredInObject)
+        {
+            //
+            // The CPalThread for the new thread was never stored in
+            // an IPalObject instance, so we need to release the initial
+            // reference here. (If it has been stored it will get freed in
+            // the owning object's cleanup routine)
+            //
+
+            pNewThread->ReleaseThreadReference();
+        }
+    }
+
+    if (NULL != pobjThread)
+    {
+        pobjThread->ReleaseReference(pThread);
+    }
+
+    if (NULL != pobjRegisteredThread)
+    {
+        pobjRegisteredThread->ReleaseReference(pThread);
+    }
+
+    return palError;
+}
+
+PAL_ERROR
+CorUnix::InternalCreateDummyThread(
+    CPalThread *pThread,
+    LPSECURITY_ATTRIBUTES lpThreadAttributes,
+    CPalThread **ppDummyThread,
+    HANDLE *phThread
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    CPalThread *pDummyThread = NULL;
+    IPalObject *pobjThread = NULL;
+    IPalObject *pobjThreadRegistered = NULL;
+    IDataLock *pDataLock;
+    CThreadProcessLocalData *pLocalData;
+    CObjectAttributes oa(NULL, lpThreadAttributes);
+    bool fThreadDataStoredInObject = FALSE;
+
+    pDummyThread = AllocTHREAD();
+    if (NULL == pDummyThread)
+    {
+        palError = ERROR_OUTOFMEMORY;
+        goto InternalCreateDummyThreadExit;
+    }
+
+    pDummyThread->m_fIsDummy = TRUE;
+
+    palError = g_pObjectManager->AllocateObject(
+        pThread,
+        &otThread,
+        &oa,
+        &pobjThread
+        );
+
+    if (NO_ERROR != palError)
+    {
+        goto InternalCreateDummyThreadExit;
+    }
+
+    palError = pobjThread->GetProcessLocalData(
+        pThread,
+        WriteLock,
+        &pDataLock,
+        reinterpret_cast<void **>(&pLocalData)
+        );
+
+    if (NO_ERROR != palError)
+    {
+        goto InternalCreateDummyThreadExit;
+    }
+
+    pLocalData->pThread = pDummyThread;
+    pDataLock->ReleaseLock(pThread, TRUE);
+    fThreadDataStoredInObject = TRUE;
+
+    palError = g_pObjectManager->RegisterObject(
+        pThread,
+        pobjThread,
+        &aotThread,
+        phThread,
+        &pobjThreadRegistered
+        );
+
+    //
+    // pobjThread is invalidated by the above call, so NULL
+    // it out here
+    //
+
+    pobjThread = NULL;
+
+    if (NO_ERROR != palError)
+    {
+        goto InternalCreateDummyThreadExit;
+    }
+
+    //
+    // Note the we do NOT store the registered object for the
+    // thread w/in pDummyThread. Since this thread is not actually
+    // executing that reference would never be released (and thus
+    // the thread object would never be cleaned up...)
+    //
+
+    *ppDummyThread = pDummyThread;
+
+InternalCreateDummyThreadExit:
+
+    if (NULL != pobjThreadRegistered)
+    {
+        pobjThreadRegistered->ReleaseReference(pThread);
+    }
+
+    if (NULL != pobjThread)
+    {
+        pobjThread->ReleaseReference(pThread);
+    }
+
+    if (NO_ERROR != palError
+        && NULL != pDummyThread
+        && !fThreadDataStoredInObject)
+    {
+        pDummyThread->ReleaseThreadReference();
+    }
+
+    return palError;
+}
+
+PAL_ERROR
+CorUnix::InternalGetThreadDataFromHandle(
+    CPalThread *pThread,
+    HANDLE hThread,
+    CPalThread **ppTargetThread,
+    IPalObject **ppobjThread
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    IPalObject *pobj;
+    IDataLock *pLock;
+    CThreadProcessLocalData *pData;
+
+    *ppobjThread = NULL;
+
+    if (hPseudoCurrentThread == hThread)
+    {
+        *ppTargetThread = pThread;
+    }
+    else
+    {
+        palError = g_pObjectManager->ReferenceObjectByHandle(
+            pThread,
+            hThread,
+            &aotThread,
+            &pobj
+            );
+
+        if (NO_ERROR == palError)
+        {
+            palError = pobj->GetProcessLocalData(
+                pThread,
+                ReadLock,
+                &pLock,
+                reinterpret_cast<void**>(&pData)
+                );
+
+            if (NO_ERROR == palError)
+            {
+                *ppTargetThread = pData->pThread;
+                pLock->ReleaseLock(pThread, FALSE);
+
+                //
+                // Transfer object reference to out param
+                //
+
+                *ppobjThread = pobj;
+            }
+            else
+            {
+                pobj->ReleaseReference(pThread);
+            }
+        }
+    }
+
+    return palError;
+}
+
 PAL_ERROR
 CPalThread::RunPreCreateInitializers(
     void
@@ -266,10 +1159,37 @@ CPalThread::RunPreCreateInitializers(
     InternalInitializeCriticalSection(&m_csLock);
     m_fLockInitialized = TRUE;
 
+    iError = pthread_mutex_init(&m_startMutex, NULL);
+    if (0 != iError)
+    {
+        goto RunPreCreateInitializersExit;
+    }
+
+    iError = pthread_cond_init(&m_startCond, NULL);
+    if (0 != iError)
+    {
+        pthread_mutex_destroy(&m_startMutex);
+        goto RunPreCreateInitializersExit;
+    }
+
+    m_fStartItemsInitialized = TRUE;
+
     //
     // Call the pre-create initializers for embedded classes
     //
 
+    palError = synchronizationInfo.InitializePreCreate();
+    if (NO_ERROR != palError)
+    {
+        goto RunPreCreateInitializersExit;
+    }
+
+    palError = suspensionInfo.InitializePreCreate();
+    if (NO_ERROR != palError)
+    {
+        goto RunPreCreateInitializersExit;
+    }
+
     palError = crtInfo.InitializePreCreate();
     if (NO_ERROR != palError)
     {
@@ -297,6 +1217,17 @@ CPalThread::~CPalThread()
     {
         InternalDeleteCriticalSection(&m_csLock);
     }
+
+    if (m_fStartItemsInitialized)
+    {
+        int iError;
+
+        iError = pthread_cond_destroy(&m_startCond);
+        _ASSERTE(0 == iError);
+
+        iError = pthread_mutex_destroy(&m_startMutex);
+        _ASSERTE(0 == iError);
+    }
 }
 
 void
@@ -332,6 +1263,25 @@ CPalThread::RunPostCreateInitializers(
     // Call the post-create initializers for embedded classes
     //
 
+    if (pthread_setspecific(thObjKey, reinterpret_cast<void*>(this)))
+    {
+        ASSERT("Unable to set the thread object key's value\n");
+        palError = ERROR_INTERNAL_ERROR;
+        goto RunPostCreateInitializersExit;
+    }
+
+    palError = synchronizationInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
+    if (NO_ERROR != palError)
+    {
+        goto RunPostCreateInitializersExit;
+    }
+
+    palError = suspensionInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
+    if (NO_ERROR != palError)
+    {
+        goto RunPostCreateInitializersExit;
+    }
+
     palError = crtInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
     if (NO_ERROR != palError)
     {
@@ -343,3 +1293,146 @@ RunPostCreateInitializersExit:
     return palError;
 }
 
+void
+CPalThread::SetStartStatus(
+    bool fStartSucceeded
+    )
+{
+    int iError;
+
+#if _DEBUG
+    if (m_fStartStatusSet)
+    {
+        ASSERT("Multiple calls to CPalThread::SetStartStatus\n");
+    }
+#endif
+
+    //
+    // This routine may get called from CPalThread::ThreadEntry
+    //
+    // If we've reached this point there are no further thread
+    // suspensions that happen at creation time, so reset
+    // m_bCreateSuspended
+    //
+
+    m_bCreateSuspended = FALSE;
+
+    iError = pthread_mutex_lock(&m_startMutex);
+    if (0 != iError)
+    {
+        ASSERT("pthread primitive failure\n");
+        // bugcheck?
+    }
+
+    m_fStartStatus = fStartSucceeded;
+    m_fStartStatusSet = TRUE;
+
+    iError = pthread_cond_signal(&m_startCond);
+    if (0 != iError)
+    {
+        ASSERT("pthread primitive failure\n");
+        // bugcheck?
+    }
+
+    iError = pthread_mutex_unlock(&m_startMutex);
+    if (0 != iError)
+    {
+        ASSERT("pthread primitive failure\n");
+        // bugcheck?
+    }
+}
+
+bool
+CPalThread::WaitForStartStatus(
+    void
+    )
+{
+    int iError;
+
+    iError = pthread_mutex_lock(&m_startMutex);
+    if (0 != iError)
+    {
+        ASSERT("pthread primitive failure\n");
+        // bugcheck?
+    }
+
+    while (!m_fStartStatusSet)
+    {
+        iError = pthread_cond_wait(&m_startCond, &m_startMutex);
+        if (0 != iError)
+        {
+            ASSERT("pthread primitive failure\n");
+            // bugcheck?
+        }
+    }
+
+    iError = pthread_mutex_unlock(&m_startMutex);
+    if (0 != iError)
+    {
+        ASSERT("pthread primitive failure\n");
+        // bugcheck?
+    }
+
+    return m_fStartStatus;
+}
+
+void
+ThreadCleanupRoutine(
+    CPalThread *pThread,
+    IPalObject *pObjectToCleanup,
+    bool fShutdown,
+    bool fCleanupSharedState
+    )
+{
+    CThreadProcessLocalData *pThreadData = NULL;
+    CPalThread *pThreadToCleanup = NULL;
+    IDataLock *pDataLock = NULL;
+    PAL_ERROR palError = NO_ERROR;
+
+    //
+    // Free the CPalThread data for the passed in thread
+    //
+
+    palError = pObjectToCleanup->GetProcessLocalData(
+        pThread,
+        WriteLock,
+        &pDataLock,
+        reinterpret_cast<void**>(&pThreadData)
+        );
+
+    if (NO_ERROR == palError)
+    {
+        //
+        // Note that we may be cleaning up the data for the calling
+        // thread (i.e., pThread == pThreadToCleanup), so the release
+        // of the thread reference needs to be the last thing that
+        // we do (though in that case it's very likely that the person
+        // calling us will be holding an extra reference to allow
+        // for the thread data to be available while the rest of the
+        // object cleanup takes place).
+        //
+
+        pThreadToCleanup = pThreadData->pThread;
+        pThreadData->pThread = NULL;
+        pDataLock->ReleaseLock(pThread, TRUE);
+        pThreadToCleanup->ReleaseThreadReference();
+    }
+    else
+    {
+        ASSERT("Unable to obtain thread data");
+    }
+
+}
+
+PAL_ERROR
+ThreadInitializationRoutine(
+    CPalThread *pThread,
+    CObjectType *pObjectType,
+    void *pImmutableData,
+    void *pSharedData,
+    void *pProcessLocalData
+    )
+{
+    return NO_ERROR;
+}
+
diff --git a/src/pal/src/thread/threadsusp.cpp b/src/pal/src/thread/threadsusp.cpp
new file mode 100644 (file)
index 0000000..6c8fc1e
--- /dev/null
@@ -0,0 +1,823 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+/*++
+
+
+
+Module Name:
+
+    threadsusp.cpp
+
+Abstract:
+
+    Implementation of functions related to threads.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+#include "pal/mutex.hpp"
+#include "pal/init.h"
+#include "pal/dbgmsg.h"
+
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <debugmacrosext.h>
+
+using namespace CorUnix;
+
+/* ------------------- Definitions ------------------------------*/
+SET_DEFAULT_DEBUG_CHANNEL(THREAD);
+
+/* This code is written to the blocking pipe of a thread that was created
+   in suspended state in order to resume it. */
+CONST BYTE WAKEUPCODE=0x2A;
+
+// #define USE_GLOBAL_LOCK_FOR_SUSPENSION // Uncomment this define to use the global suspension lock.
+/* The global suspension lock can be used in place of each thread having its own
+suspension mutex or spinlock. The downside is that it restricts us to only
+performing one suspension or resumption in the PAL at a time. */
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+static LONG g_ssSuspensionLock = 0;
+#endif
+
+/*++
+Function:
+  InternalSuspendNewThreadFromData
+
+  On platforms where we use pipes for starting threads suspended, this
+  function sets the blocking pipe for the thread and blocks until the
+  wakeup code is written to the pipe by ResumeThread.
+
+--*/
+PAL_ERROR
+CThreadSuspensionInfo::InternalSuspendNewThreadFromData(
+    CPalThread *pThread
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+
+    AcquireSuspensionLock(pThread);
+    pThread->suspensionInfo.SetSelfSusp(TRUE);
+    ReleaseSuspensionLock(pThread);
+
+    int pipe_descs[2];
+    int pipeRv =
+#if HAVE_PIPE2
+        pipe2(pipe_descs, O_CLOEXEC);
+#else
+        pipe(pipe_descs);
+#endif // HAVE_PIPE2
+    if (pipeRv == -1)
+    {
+        ERROR("pipe() failed! error is %d (%s)\n", errno, strerror(errno));
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+#if !HAVE_PIPE2
+    fcntl(pipe_descs[0], F_SETFD, FD_CLOEXEC); // make pipe non-inheritable, if possible
+    fcntl(pipe_descs[1], F_SETFD, FD_CLOEXEC);
+#endif // !HAVE_PIPE2
+
+    // [0] is the read end of the pipe, and [1] is the write end.
+    pThread->suspensionInfo.SetBlockingPipe(pipe_descs[1]);
+    pThread->SetStartStatus(TRUE);
+
+    BYTE resume_code = 0;
+    ssize_t read_ret;
+
+    // Block until ResumeThread writes something to the pipe
+    while ((read_ret = read(pipe_descs[0], &resume_code, sizeof(resume_code))) != sizeof(resume_code))
+    {
+        if (read_ret != -1 || EINTR != errno)
+        {
+            // read might return 0 (with EAGAIN) if the other end of the pipe gets closed
+            palError = ERROR_INTERNAL_ERROR;
+            break;
+        }
+    }
+
+    if (palError == NO_ERROR && resume_code != WAKEUPCODE)
+    {
+        // If we did read successfully but the byte didn't match WAKEUPCODE, we treat it as a failure.
+        palError = ERROR_INTERNAL_ERROR;
+    }
+
+    if (palError == NO_ERROR)
+    {
+        AcquireSuspensionLock(pThread);
+        pThread->suspensionInfo.SetSelfSusp(FALSE);
+        ReleaseSuspensionLock(pThread);
+    }
+
+    // Close the pipes regardless of whether we were successful.
+    close(pipe_descs[0]);
+    close(pipe_descs[1]);
+
+    return palError;
+}
+
+/*++
+Function:
+
+  ResumeThread
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+ResumeThread(
+         IN HANDLE hThread
+         )
+{
+    PAL_ERROR palError;
+    CPalThread *pthrResumer;
+    DWORD dwSuspendCount = (DWORD)-1;
+
+    PERF_ENTRY(ResumeThread);
+    ENTRY("ResumeThread(hThread=%p)\n", hThread);
+
+    pthrResumer = InternalGetCurrentThread();
+    palError = InternalResumeThread(
+        pthrResumer,
+        hThread,
+        &dwSuspendCount
+        );
+
+    if (NO_ERROR != palError)
+    {
+        pthrResumer->SetLastError(palError);
+        dwSuspendCount = (DWORD) -1;
+    }
+    else
+    {
+        _ASSERT_MSG(dwSuspendCount != static_cast<DWORD>(-1), "InternalResumeThread returned success but dwSuspendCount did not change.\n");
+    }
+
+    LOGEXIT("ResumeThread returns DWORD %u\n", dwSuspendCount);
+    PERF_EXIT(ResumeThread);
+    return dwSuspendCount;
+}
+
+/*++
+Function:
+  InternalResumeThread
+
+InternalResumeThread converts the handle of the target thread to a
+CPalThread, and passes both the resumer and target thread references
+to InternalResumeThreadFromData. A reference to the suspend count from
+the resumption attempt is passed back to the caller of this function.
+--*/
+PAL_ERROR
+CorUnix::InternalResumeThread(
+    CPalThread *pthrResumer,
+    HANDLE hTargetThread,
+    DWORD *pdwSuspendCount
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+    CPalThread *pthrTarget = NULL;
+    IPalObject *pobjThread = NULL;
+
+    palError = InternalGetThreadDataFromHandle(
+        pthrResumer,
+        hTargetThread,
+        &pthrTarget,
+        &pobjThread
+        );
+
+    if (NO_ERROR == palError)
+    {
+        palError = pthrResumer->suspensionInfo.InternalResumeThreadFromData(
+            pthrResumer,
+            pthrTarget,
+            pdwSuspendCount
+            );
+    }
+
+    if (NULL != pobjThread)
+    {
+        pobjThread->ReleaseReference(pthrResumer);
+    }
+
+    return palError;
+}
+
+/*++
+Function:
+  InternalResumeThreadFromData
+
+InternalResumeThreadFromData resumes the target thread. First, the suspension
+mutexes of the threads are acquired. Next, there's a check to ensure that the
+target thread was actually suspended. Finally, the resume attempt is made
+and the suspension mutexes are released. The suspend count of the
+target thread is passed back to the caller of this function.
+
+Note that ReleaseSuspensionLock(s) is called before hitting ASSERTs in error
+paths. Currently, this seems unnecessary since asserting within
+InternalResumeThreadFromData will not cause cleanup to occur. However,
+this may change since it would be preferable to perform cleanup. Thus, calls
+to release suspension locks remain in the error paths.
+--*/
+PAL_ERROR
+CThreadSuspensionInfo::InternalResumeThreadFromData(
+    CPalThread *pthrResumer,
+    CPalThread *pthrTarget,
+    DWORD *pdwSuspendCount
+    )
+{
+    PAL_ERROR palError = NO_ERROR;
+
+    int nWrittenBytes = -1;
+
+    if (SignalHandlerThread == pthrTarget->GetThreadType())
+    {
+        ASSERT("Attempting to resume the signal handling thread, which can never be suspended.\n");
+        palError = ERROR_INVALID_HANDLE;
+        goto InternalResumeThreadFromDataExit;
+    }
+
+    // Acquire suspension mutex
+    AcquireSuspensionLocks(pthrResumer, pthrTarget);
+
+    // Check target thread's state to ensure it hasn't died.
+    // Setting a thread's state to TS_DONE is protected by the
+    // target's suspension mutex.
+    if (pthrTarget->synchronizationInfo.GetThreadState() == TS_DONE)
+    {
+        palError = ERROR_INVALID_HANDLE;
+        ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+        goto InternalResumeThreadFromDataExit;
+    }
+
+    // If this is a dummy thread, then it represents a process that was created with CREATE_SUSPENDED
+    // and it should have a blocking pipe set. If GetBlockingPipe returns -1 for a dummy thread, then
+    // something is wrong - either CREATE_SUSPENDED wasn't used or the process was already resumed.
+    if (pthrTarget->IsDummy() && -1 == pthrTarget->suspensionInfo.GetBlockingPipe())
+    {
+        palError = ERROR_INVALID_HANDLE;
+        ERROR("Tried to wake up dummy thread without a blocking pipe.\n");
+        ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+        goto InternalResumeThreadFromDataExit;
+    }
+
+    // If there is a blocking pipe on this thread, resume it by writing the wake up code to that pipe.
+    if (-1 != pthrTarget->suspensionInfo.GetBlockingPipe())
+    {
+        // If write() is interrupted by a signal before writing data,
+        // it returns -1 and sets errno to EINTR. In this case, we
+        // attempt the write() again.
+        writeAgain:
+        nWrittenBytes = write(pthrTarget->suspensionInfo.GetBlockingPipe(), &WAKEUPCODE, sizeof(WAKEUPCODE));
+
+        // The size of WAKEUPCODE is 1 byte. If write returns 0, we'll treat it as an error.
+        if (sizeof(WAKEUPCODE) != nWrittenBytes)
+        {
+            // If we are here during process creation, this is most likely caused by the target
+            // process dying before reaching this point and thus breaking the pipe.
+            if (nWrittenBytes == -1 && EPIPE == errno)
+            {
+                palError = ERROR_INVALID_HANDLE;
+                ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+                ERROR("Write failed with EPIPE\n");
+                goto InternalResumeThreadFromDataExit;
+            }
+            else if (nWrittenBytes == 0 || (nWrittenBytes == -1 && EINTR == errno))
+            {
+                TRACE("write() failed with EINTR; re-attempting write\n");
+                goto writeAgain;
+            }
+            else
+            {
+                // Some other error occurred; need to release suspension mutexes before leaving ResumeThread.
+                palError = ERROR_INTERNAL_ERROR;
+                ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+                ASSERT("Write() failed; error is %d (%s)\n", errno, strerror(errno));
+                goto InternalResumeThreadFromDataExit;
+            }
+        }
+
+        // Reset blocking pipe to -1 since we're done using it.
+        pthrTarget->suspensionInfo.SetBlockingPipe(-1);
+
+        ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+        goto InternalResumeThreadFromDataExit;
+    }
+    else
+    {
+        *pdwSuspendCount = 0;
+        palError = ERROR_BAD_COMMAND;
+    }
+
+InternalResumeThreadFromDataExit:
+
+    if (NO_ERROR == palError)
+    {
+        *pdwSuspendCount = 1;
+    }
+
+    return palError;
+}
+
+/*++
+Function:
+  TryAcquireSuspensionLock
+
+TryAcquireSuspensionLock is a utility function that tries to acquire a thread's
+suspension mutex or spinlock. If it succeeds, the function returns TRUE.
+Otherwise, it returns FALSE. This function is used in AcquireSuspensionLocks.
+Note that the global lock cannot be acquired in this function since it makes
+no sense to do so. A thread holding the global lock is the only thread that
+can perform suspend or resume operations so it doesn't need to acquire
+a second lock.
+--*/
+BOOL
+CThreadSuspensionInfo::TryAcquireSuspensionLock(
+    CPalThread* pthrTarget
+    )
+{
+    int iPthreadRet = 0;
+#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+{
+    iPthreadRet = SPINLOCKTryAcquire(pthrTarget->suspensionInfo.GetSuspensionSpinlock());
+}
+#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+{
+    iPthreadRet = pthread_mutex_trylock(pthrTarget->suspensionInfo.GetSuspensionMutex());
+    _ASSERT_MSG(iPthreadRet == 0 || iPthreadRet == EBUSY, "pthread_mutex_trylock returned %d\n", iPthreadRet);
+}
+#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+
+    // If iPthreadRet is 0, lock acquisition was successful. Otherwise, it failed.
+    return (iPthreadRet == 0);
+}
+
+/*++
+Function:
+  AcquireSuspensionLock
+
+AcquireSuspensionLock acquires a thread's suspension mutex or spinlock.
+If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it will acquire the global lock.
+A thread in this function blocks until it acquires
+its lock, unlike in TryAcquireSuspensionLock.
+--*/
+void
+CThreadSuspensionInfo::AcquireSuspensionLock(
+    CPalThread* pthrCurrent
+    )
+{
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+{
+    SPINLOCKAcquire(&g_ssSuspensionLock, 0);
+}
+#else // USE_GLOBAL_LOCK_FOR_SUSPENSION
+{
+    #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+    {
+        SPINLOCKAcquire(&pthrCurrent->suspensionInfo.m_nSpinlock, 0);
+    }
+    #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+    {
+        INDEBUG(int iPthreadError = )
+        pthread_mutex_lock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex);
+        _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_lock returned %d\n", iPthreadError);
+    }
+    #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+}
+#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
+}
+
+/*++
+Function:
+  ReleaseSuspensionLock
+
+ReleaseSuspensionLock is a function that releases a thread's suspension mutex
+or spinlock. If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined,
+it will release the global lock.
+--*/
+void
+CThreadSuspensionInfo::ReleaseSuspensionLock(
+    CPalThread* pthrCurrent
+    )
+{
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+{
+    SPINLOCKRelease(&g_ssSuspensionLock);
+}
+#else // USE_GLOBAL_LOCK_FOR_SUSPENSION
+{
+    #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+    {
+        SPINLOCKRelease(&pthrCurrent->suspensionInfo.m_nSpinlock);
+    }
+    #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+    {
+        INDEBUG(int iPthreadError = )
+        pthread_mutex_unlock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex);
+        _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_unlock returned %d\n", iPthreadError);
+    }
+    #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+}
+#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
+}
+
+/*++
+Function:
+  AcquireSuspensionLocks
+
+AcquireSuspensionLocks is used to acquire the suspension locks
+of a suspender (or resumer) and target thread. The thread will
+perform a blocking call to acquire its own suspension lock
+and will then try to acquire the target thread's lock without blocking.
+If it fails to acquire the target's lock, it releases its own lock
+and the thread will try to acquire both locks again. The key
+is that both locks must be acquired together.
+
+Originally, only blocking calls were used to acquire the suspender
+and the target lock. However, this was problematic since a thread
+could acquire its own lock and then block on acquiring the target
+lock. In the meantime, the target could have already acquired its
+own lock and be attempting to suspend the suspender thread. This
+clearly causes deadlock. A second approach used locking hierarchies,
+where locks were acquired use thread id ordering. This was better but
+suffered from the scenario where thread A acquires thread B's
+suspension mutex first. In the meantime, thread C acquires thread A's
+suspension mutex and its own. Thus, thread A is suspended while
+holding thread B's mutex. This is problematic if thread C now wants
+to suspend thread B. The issue here is that a thread can be
+suspended while holding someone else's mutex but not holding its own.
+In the end, the correct approach is to always acquire your suspension
+mutex first. This prevents you from being suspended while holding the
+target's mutex. Then, attempt to acquire the target's mutex. If the mutex
+cannot be acquired, release your own and try again. This all or nothing
+approach is the safest and avoids nasty race conditions.
+
+If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, the calling thread
+will acquire the global lock when possible.
+--*/
+VOID
+CThreadSuspensionInfo::AcquireSuspensionLocks(
+    CPalThread *pthrSuspender,
+    CPalThread *pthrTarget
+    )
+{
+    BOOL fReacquire = FALSE;
+
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+    AcquireSuspensionLock(pthrSuspender);
+#else // USE_GLOBAL_LOCK_FOR_SUSPENSION
+    do
+    {
+        fReacquire = FALSE;
+        AcquireSuspensionLock(pthrSuspender);
+        if (!TryAcquireSuspensionLock(pthrTarget))
+        {
+            // pthread_mutex_trylock returned EBUSY so release the first lock and try again.
+            ReleaseSuspensionLock(pthrSuspender);
+            fReacquire = TRUE;
+            sched_yield();
+        }
+    } while (fReacquire);
+#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
+
+    // Whenever the native implementation for the wait subsystem's thread
+    // blocking requires a lock as protection (as pthread conditions do with
+    // the associated mutex), we need to grab that lock to prevent the target
+    // thread from being suspended while holding the lock.
+    // Failing to do so can lead to a multiple threads deadlocking such as the
+    // one described in VSW 363793.
+    // In general, in similar scenarios, we need to grab the protecting lock
+    // every time suspension safety/unsafety is unbalanced on the two sides
+    // using the same condition (or any other native blocking support which
+    // needs an associated native lock), i.e. when either the signaling
+    // thread(s) is(are) signaling from an unsafe area and the waiting
+    // thread(s) is(are) waiting from a safe one, or vice versa (the scenario
+    // described in VSW 363793 is a good example of the first type of
+    // unbalanced suspension safety/unsafety).
+    // Instead, whenever signaling and waiting sides are both marked safe or
+    // unsafe, the deadlock cannot take place since either the suspending
+    // thread will suspend them anyway (regardless of the native lock), or it
+    // won't suspend any of them, since they are both marked unsafe.
+    // Such a balanced scenario applies, for instance, to critical sections
+    // where depending on whether the target CS is internal or not, both the
+    // signaling and the waiting side will access the mutex/condition from
+    // respectively an unsafe or safe region.
+
+    pthrTarget->AcquireNativeWaitLock();
+}
+
+/*++
+Function:
+  ReleaseSuspensionLocks
+
+ReleaseSuspensionLocks releases both thread's suspension mutexes.
+Note that the locks are released in the opposite order they're acquired.
+This prevents a suspending or resuming thread from being suspended
+while holding the target's lock.
+If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it simply releases the global lock.
+--*/
+VOID
+CThreadSuspensionInfo::ReleaseSuspensionLocks(
+    CPalThread *pthrSuspender,
+    CPalThread *pthrTarget
+    )
+{
+    // See comment in AcquireSuspensionLocks
+    pthrTarget->ReleaseNativeWaitLock();
+
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+    ReleaseSuspensionLock(pthrSuspender);
+#else // USE_GLOBAL_LOCK_FOR_SUSPENSION
+    ReleaseSuspensionLock(pthrTarget);
+    ReleaseSuspensionLock(pthrSuspender);
+#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
+}
+
+/*++
+Function:
+  InitializeSuspensionLock
+
+InitializeSuspensionLock initializes a thread's suspension spinlock
+or suspension mutex. It is called from the CThreadSuspensionInfo
+constructor.
+--*/
+VOID
+CThreadSuspensionInfo::InitializeSuspensionLock()
+{
+#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+    SPINLOCKInit(&m_nSpinlock);
+#else
+    int iError = pthread_mutex_init(&m_ptmSuspmutex, NULL);
+    if (0 != iError )
+    {
+        ASSERT("pthread_mutex_init(&suspmutex) returned %d\n", iError);
+        return;
+    }
+    m_fSuspmutexInitialized = TRUE;
+#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+}
+
+/*++
+Function:
+  InitializePreCreate
+
+InitializePreCreate initializes the semaphores and signal masks used
+for thread suspension. At the end, it sets the calling thread's
+signal mask to the default signal mask.
+--*/
+PAL_ERROR
+CThreadSuspensionInfo::InitializePreCreate()
+{
+    PAL_ERROR palError = ERROR_INTERNAL_ERROR;
+    int iError = 0;
+#if SEM_INIT_MODIFIES_ERRNO
+    int nStoredErrno;
+#endif  // SEM_INIT_MODIFIES_ERRNO
+
+#if USE_POSIX_SEMAPHORES
+
+#if SEM_INIT_MODIFIES_ERRNO
+    nStoredErrno = errno;
+#endif  // SEM_INIT_MODIFIES_ERRNO
+
+    // initialize suspension semaphore
+    iError = sem_init(&m_semSusp, 0, 0);
+
+#if SEM_INIT_MODIFIES_ERRNO
+    if (iError == 0)
+    {
+        // Restore errno if sem_init succeeded.
+        errno = nStoredErrno;
+    }
+#endif  // SEM_INIT_MODIFIES_ERRNO
+
+    if (0 != iError )
+    {
+        ASSERT("sem_init(&suspsem) returned %d\n", iError);
+        goto InitializePreCreateExit;
+    }
+
+#if SEM_INIT_MODIFIES_ERRNO
+    nStoredErrno = errno;
+#endif  // SEM_INIT_MODIFIES_ERRNO
+
+    // initialize resume semaphore
+    iError = sem_init(&m_semResume, 0, 0);
+
+#if SEM_INIT_MODIFIES_ERRNO
+    if (iError == 0)
+    {
+        // Restore errno if sem_init succeeded.
+        errno = nStoredErrno;
+    }
+#endif  // SEM_INIT_MODIFIES_ERRNO
+
+    if (0 != iError )
+    {
+        ASSERT("sem_init(&suspsem) returned %d\n", iError);
+        sem_destroy(&m_semSusp);
+        goto InitializePreCreateExit;
+    }
+
+    m_fSemaphoresInitialized = TRUE;
+
+#elif USE_SYSV_SEMAPHORES
+    // preparing to initialize the SysV semaphores.
+    union semun semunData;
+    m_nSemsuspid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
+    if (m_nSemsuspid == -1)
+    {
+        ASSERT("semget for suspension sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+        goto InitializePreCreateExit;
+    }
+
+    m_nSemrespid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
+    if (m_nSemrespid == -1)
+    {
+        ASSERT("semget for resumption sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+        goto InitializePreCreateExit;
+    }
+
+    if (m_nSemsuspid == m_nSemrespid)
+    {
+        ASSERT("Suspension and Resumption Semaphores have the same id\n");
+        goto InitializePreCreateExit;
+    }
+
+    semunData.val = 0;
+    iError = semctl(m_nSemsuspid, 0, SETVAL, semunData);
+    if (iError == -1)
+    {
+        ASSERT("semctl for suspension sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+        goto InitializePreCreateExit;
+    }
+
+    semunData.val = 0;
+    iError = semctl(m_nSemrespid, 0, SETVAL, semunData);
+    if (iError == -1)
+    {
+        ASSERT("semctl for resumption sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+        goto InitializePreCreateExit;
+    }
+
+    // initialize suspend semaphore
+    m_sbSemwait.sem_num = 0;
+    m_sbSemwait.sem_op = -1;
+    m_sbSemwait.sem_flg = 0;
+
+    // initialize resume semaphore
+    m_sbSempost.sem_num = 0;
+    m_sbSempost.sem_op = 1;
+    m_sbSempost.sem_flg = 0;
+#elif USE_PTHREAD_CONDVARS
+    iError = pthread_cond_init(&m_condSusp, NULL);
+    if (iError != 0)
+    {
+        ASSERT("pthread_cond_init for suspension returned %d (%s)\n", iError, strerror(iError));
+        goto InitializePreCreateExit;
+    }
+
+    iError = pthread_mutex_init(&m_mutexSusp, NULL);
+    if (iError != 0)
+    {
+        ASSERT("pthread_mutex_init for suspension returned %d (%s)\n", iError, strerror(iError));
+        goto InitializePreCreateExit;
+    }
+
+    iError = pthread_cond_init(&m_condResume, NULL);
+    if (iError != 0)
+    {
+        ASSERT("pthread_cond_init for resume returned %d (%s)\n", iError, strerror(iError));
+        goto InitializePreCreateExit;
+    }
+
+    iError = pthread_mutex_init(&m_mutexResume, NULL);
+    if (iError != 0)
+    {
+        ASSERT("pthread_mutex_init for resume returned %d (%s)\n", iError, strerror(iError));
+        goto InitializePreCreateExit;
+    }
+
+    m_fSemaphoresInitialized = TRUE;
+#endif // USE_POSIX_SEMAPHORES
+
+    // Initialization was successful.
+    palError = NO_ERROR;
+
+InitializePreCreateExit:
+
+    if (NO_ERROR == palError && 0 != iError)
+    {
+        switch (iError)
+        {
+            case ENOMEM:
+            case EAGAIN:
+            {
+                palError = ERROR_OUTOFMEMORY;
+                break;
+            }
+            default:
+            {
+                ASSERT("A pthrSuspender init call returned %d (%s)\n", iError, strerror(iError));
+                palError = ERROR_INTERNAL_ERROR;
+            }
+        }
+    }
+
+    return palError;
+}
+
+CThreadSuspensionInfo::~CThreadSuspensionInfo()
+{
+#if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+    if (m_fSuspmutexInitialized)
+    {
+        INDEBUG(int iError = )
+        pthread_mutex_destroy(&m_ptmSuspmutex);
+        _ASSERT_MSG(0 == iError, "pthread_mutex_destroy returned %d (%s)\n", iError, strerror(iError));
+    }
+#endif
+
+#if USE_POSIX_SEMAPHORES
+    if (m_fSemaphoresInitialized)
+    {
+        int iError;
+
+        iError = sem_destroy(&m_semSusp);
+        _ASSERT_MSG(0 == iError, "sem_destroy failed and set errno to %d (%s)\n", errno, strerror(errno));
+
+        iError = sem_destroy(&m_semResume);
+        _ASSERT_MSG(0 == iError, "sem_destroy failed and set errno to %d (%s)\n", errno, strerror(errno));
+    }
+#elif USE_SYSV_SEMAPHORES
+    DestroySemaphoreIds();
+#elif USE_PTHREAD_CONDVARS
+    if (m_fSemaphoresInitialized)
+    {
+        int iError;
+
+        iError = pthread_cond_destroy(&m_condSusp);
+        _ASSERT_MSG(0 == iError, "pthread_cond_destroy failed with %d (%s)\n", iError, strerror(iError));
+
+        iError = pthread_mutex_destroy(&m_mutexSusp);
+        _ASSERT_MSG(0 == iError, "pthread_mutex_destroy failed with %d (%s)\n", iError, strerror(iError));
+
+        iError = pthread_cond_destroy(&m_condResume);
+        _ASSERT_MSG(0 == iError, "pthread_cond_destroy failed with %d (%s)\n", iError, strerror(iError));
+
+        iError = pthread_mutex_destroy(&m_mutexResume);
+        _ASSERT_MSG(0 == iError, "pthread_mutex_destroy failed with %d (%s)\n", iError, strerror(iError));
+    }
+#endif  // USE_POSIX_SEMAPHORES
+}
+
+#if USE_SYSV_SEMAPHORES
+/*++
+Function:
+  DestroySemaphoreIds
+
+DestroySemaphoreIds is called from the CThreadSuspensionInfo destructor and
+from PROCCleanupThreadSemIds. If a thread exits before shutdown or is suspended
+during shutdown, its destructor will be invoked and the semaphore ids destroyed.
+In assert or exceptions situations that are suspension unsafe,
+PROCCleanupThreadSemIds is called, which uses DestroySemaphoreIds.
+--*/
+void
+CThreadSuspensionInfo::DestroySemaphoreIds()
+{
+    union semun semunData;
+    if (m_nSemsuspid != 0)
+    {
+        semunData.val = 0;
+        if (0 != semctl(m_nSemsuspid, 0, IPC_RMID, semunData))
+        {
+            ERROR("semctl(Semsuspid) failed and set errno to %d (%s)\n", errno, strerror(errno));
+        }
+        else
+        {
+            m_nSemsuspid = 0;
+        }
+    }
+    if (this->m_nSemrespid)
+    {
+        semunData.val = 0;
+        if (0 != semctl(m_nSemrespid, 0, IPC_RMID, semunData))
+        {
+            ERROR("semctl(Semrespid) failed and set errno to %d (%s)\n", errno, strerror(errno));
+        }
+        else
+        {
+            m_nSemrespid = 0;
+        }
+    }
+}
+#endif // USE_SYSV_SEMAPHORES
index 4ca96bc4584d02ce30114d3d57ff6a0e30437da6..68151fa2aed2296364cb2a14d1c189e3104210b9 100644 (file)
@@ -2,18 +2,6 @@
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
 include_directories(${ROOT_DIR}/src)
-include_directories(${ROOT_DIR}/src/pal/inc)
-include_directories(${ROOT_DIR}/src/pal/inc/rt)
-
-# Include the dummy c++ include files
-include_directories(${ROOT_DIR}/src/pal/inc/rt/cpp)
-
-# This prevents inclusion of standard C compiler headers
-add_compile_options(-nostdinc)
-
-add_compile_options(-fPIC)
-add_definitions(-DUNICODE)
-add_definitions(-D_UNICODE)
 
 set(PALRT_SOURCES
     bstr.cpp
diff --git a/src/utilcode/CMakeLists.txt b/src/utilcode/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6f0f6d4
--- /dev/null
@@ -0,0 +1,46 @@
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_definitions(-D_BLD_CLR)
+
+set(UTILCODE_COMMON_SOURCES
+  clrhost_nodependencies.cpp
+  ex.cpp
+  sbuffer.cpp
+  sstring_com.cpp
+  fstring.cpp
+  namespaceutil.cpp
+  check.cpp
+  sstring.cpp
+  safewrap.cpp
+  debug.cpp
+  pedecoder.cpp
+  longfilepathwrappers.cpp
+)
+
+# These source file do not yet compile on Linux.
+# They should be moved out from here into the declaration
+# of UTILCODE_SOURCES above after fixing compiler errors.
+if(CLR_CMAKE_TARGET_WIN32)
+  list(APPEND UTILCODE_COMMON_SOURCES
+    dlwrap.cpp
+    securitywrapper.cpp
+    securityutil.cpp
+  )
+endif(CLR_CMAKE_TARGET_WIN32)
+
+set(UTILCODE_STATICNOHOST_SOURCES
+  ${UTILCODE_COMMON_SOURCES}
+  hostimpl.cpp
+)
+
+convert_to_absolute_path(UTILCODE_STATICNOHOST_SOURCES ${UTILCODE_STATICNOHOST_SOURCES})
+
+add_library_clr(utilcodestaticnohost STATIC ${UTILCODE_STATICNOHOST_SOURCES})
+
+if(CLR_CMAKE_HOST_WIN32)
+  target_compile_definitions(utilcodestaticnohost PRIVATE _CRTIMP=) # use static version of crt
+endif(CLR_CMAKE_HOST_WIN32)
+
+target_compile_definitions(utilcodestaticnohost PRIVATE FEATURE_UTILCODE_NO_DEPENDENCIES)
+target_compile_definitions(utilcodestaticnohost PRIVATE SELF_NO_HOST)
+target_precompile_headers(utilcodestaticnohost PRIVATE [["stdafx.h"]])
diff --git a/src/utilcode/check.cpp b/src/utilcode/check.cpp
new file mode 100644 (file)
index 0000000..4d7a0c7
--- /dev/null
@@ -0,0 +1,281 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//================================================================================
+// Assertion checking infrastructure
+//================================================================================
+
+#include "stdafx.h"
+#include <check.h>
+#include <sstring.h>
+#include <ex.h>
+#include <contract.h>
+
+#ifdef _DEBUG
+size_t CHECK::s_cLeakedBytes = 0;
+size_t CHECK::s_cNumFailures = 0;
+
+thread_local LONG CHECK::t_count;
+#endif
+
+BOOL CHECK::s_neverEnforceAsserts = 0;
+
+
+// Currently used for scan SPECIAL_HOLDER_* trickery
+DEBUG_NOINLINE BOOL CHECK::EnforceAssert_StaticCheckOnly()
+{
+    return s_neverEnforceAsserts;
+}
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// Need a place to stick this, there is no contract.cpp...
+BOOL BaseContract::s_alwaysEnforceContracts = 1;
+
+#define SPECIALIZE_CONTRACT_VIOLATION_HOLDER(mask)                              \
+template<> void ContractViolationHolder<mask>::Enter()                          \
+{                                                                               \
+    SCAN_SCOPE_BEGIN;                                                           \
+    ANNOTATION_VIOLATION(mask);                                                 \
+    EnterInternal(mask);                                                        \
+};
+
+#define SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER(mask)                                                 \
+template<> AutoCleanupContractViolationHolder<mask>::AutoCleanupContractViolationHolder(BOOL fEnterViolation)   \
+{                                                                                                               \
+    SCAN_SCOPE_BEGIN;                                                                                           \
+    ANNOTATION_VIOLATION(mask);                                                                                 \
+    EnterInternal(fEnterViolation ? mask : 0);                                                                  \
+};
+
+#define SPECIALIZED_VIOLATION(mask)                                             \
+    SPECIALIZE_CONTRACT_VIOLATION_HOLDER(mask);                                 \
+    SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER(mask)
+
+// There is a special case that requires 0... Why??? Who knows, let's fix that case.
+
+SPECIALIZED_VIOLATION(0);
+
+// Basic Specializations
+
+SPECIALIZED_VIOLATION(AllViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation);
+SPECIALIZED_VIOLATION(GCViolation);
+SPECIALIZED_VIOLATION(ModeViolation);
+SPECIALIZED_VIOLATION(FaultViolation);
+SPECIALIZED_VIOLATION(FaultNotFatal);
+SPECIALIZED_VIOLATION(HostViolation);
+SPECIALIZED_VIOLATION(TakesLockViolation);
+SPECIALIZED_VIOLATION(LoadsTypeViolation);
+
+// Other Specializations used by the RUNTIME, if you get a compile time error you need
+// to add the specific specialization that you are using here.
+
+SPECIALIZED_VIOLATION(ThrowsViolation|GCViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|GCViolation|TakesLockViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|ModeViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|FaultNotFatal);
+SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|TakesLockViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|TakesLockViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation|TakesLockViolation|LoadsTypeViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation|ModeViolation);
+SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation|ModeViolation|FaultNotFatal);
+SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation|ModeViolation|FaultNotFatal|TakesLockViolation);
+SPECIALIZED_VIOLATION(GCViolation|FaultViolation);
+SPECIALIZED_VIOLATION(GCViolation|FaultNotFatal|ModeViolation);
+SPECIALIZED_VIOLATION(GCViolation|FaultNotFatal|TakesLockViolation);
+SPECIALIZED_VIOLATION(GCViolation|FaultNotFatal|TakesLockViolation|ModeViolation);
+SPECIALIZED_VIOLATION(GCViolation|ModeViolation);
+SPECIALIZED_VIOLATION(FaultViolation|FaultNotFatal);
+SPECIALIZED_VIOLATION(FaultNotFatal|TakesLockViolation);
+
+
+
+#undef SPECIALIZED_VIOLATION
+#undef SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER
+#undef SPECIALIZE_CONTRACT_VIOLATION_HOLDER
+
+#endif
+
+// Trigger triggers the actual check failure.  The trigger may provide a reason
+// to include in the failure message.
+
+void CHECK::Trigger(LPCSTR reason)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    const char *messageString = NULL;
+    NewHolder<StackScratchBuffer> pScratch(NULL);
+    NewHolder<StackSString> pMessage(NULL);
+
+    EX_TRY
+    {
+        FAULT_NOT_FATAL();
+
+        pScratch = new StackScratchBuffer();
+        pMessage = new StackSString();
+
+        pMessage->AppendASCII(reason);
+        pMessage->AppendASCII(": ");
+        if (m_message != NULL)
+            pMessage->AppendASCII((m_message != (LPCSTR)1) ? m_message : "<runtime check failure>");
+
+#if _DEBUG
+        pMessage->AppendASCII("FAILED: ");
+        pMessage->AppendASCII(m_condition);
+#endif
+
+        messageString = pMessage->GetANSI(*pScratch);
+    }
+    EX_CATCH
+    {
+        messageString = "<exception occurred while building failure description>";
+    }
+    EX_END_CATCH(SwallowAllExceptions);
+
+#if _DEBUG
+    DbgAssertDialog((char*)m_file, m_line, (char *)messageString);
+#else
+    OutputDebugStringA(messageString);
+    DebugBreak();
+#endif
+
+}
+
+#ifdef _DEBUG
+// Setup records context info after a failure.
+
+void CHECK::Setup(LPCSTR message, LPCSTR condition, LPCSTR file, INT line)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+
+    //
+    // It might be nice to collect all of the message here.  But for now, we will just
+    // retain the innermost one.
+    //
+
+    if (m_message == NULL)
+    {
+        m_message = message;
+        m_condition = condition;
+        m_file = file;
+        m_line = line;
+    }
+
+#ifdef _DEBUG
+    else if (IsInAssert())
+    {
+        EX_TRY
+        {
+            FAULT_NOT_FATAL();
+            // Try to build a stack of condition failures
+
+            StackSString context;
+            context.Printf("%s\n\t%s%s FAILED: %s\n\t\t%s, line: %d",
+                           m_condition,
+                           message && *message ? message : "",
+                           message && *message ? ": " : "",
+                           condition,
+                           file, line);
+
+            m_condition = AllocateDynamicMessage(context);
+        }
+        EX_CATCH
+        {
+            // If anything goes wrong, we don't push extra context
+        }
+        EX_END_CATCH(SwallowAllExceptions)
+    }
+#endif
+
+#if defined(_DEBUG_IMPL)
+    if (IsInAssert() && IsDebuggerPresent())
+    {
+        DebugBreak();
+    }
+#endif
+}
+
+LPCSTR CHECK::FormatMessage(LPCSTR messageFormat, ...)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    LPCSTR result = NULL;
+
+    // We never delete this allocated string. A dtor would conflict with places
+    // we use this around SEH stuff. We could have some fancy stack-based allocator,
+    // but that's too much work for now. In fact we believe that leaking is a reasonable
+    // policy, since allocations will only happen on a failed assert, and a failed assert
+    // will generally be fatal to the process.
+
+    // The most common place for format strings will be in an assert; in
+    // which case we don't care about leaking.
+    // But to be safe, if we're not-inside an assert, then we'll just use
+    // the format string literal to avoid allocated (and leaking) any memory.
+
+    CHECK chk;
+    if (!chk.IsInAssert())
+        result = messageFormat;
+    else
+    {
+        // This path is only run in debug.  TakesLockViolation suppresses
+        // problems with SString below.
+        CONTRACT_VIOLATION(FaultNotFatal|TakesLockViolation);
+
+        EX_TRY
+        {
+            SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
+
+            // Format it.
+            va_list args;
+            va_start( args, messageFormat);
+
+            SString s;
+            s.VPrintf(messageFormat, args);
+
+            va_end(args);
+
+            result = AllocateDynamicMessage(s);
+
+        }
+        EX_CATCH
+        {
+            // If anything goes wrong, just use the format string.
+            result = messageFormat;
+        }
+        EX_END_CATCH(SwallowAllExceptions)
+    }
+
+    return result;
+}
+
+LPCSTR CHECK::AllocateDynamicMessage(const SString &s)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    // Make a copy of it.
+    StackScratchBuffer buffer;
+    const char * pMsg = s.GetANSI(buffer);
+
+    // Must copy that into our own field.
+    size_t len = strlen(pMsg) + 1;
+    char * p = new char[len];
+    strcpy(p, pMsg);
+
+    // But we'll keep counters of how much we're leaking for diagnostic purposes.
+    s_cLeakedBytes += len;
+    s_cNumFailures ++;
+
+    // This should never fire.
+    // Note use an ASSERTE (not a check) to avoid a recursive deadlock.
+    _ASSERTE(s_cLeakedBytes < 10000 || !"Warning - check misuse - leaked over 10,000B due to unexpected usage pattern");
+    return p;
+}
+
+#endif
diff --git a/src/utilcode/clrhost_nodependencies.cpp b/src/utilcode/clrhost_nodependencies.cpp
new file mode 100644 (file)
index 0000000..ecba72b
--- /dev/null
@@ -0,0 +1,537 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+//
+
+#include "stdafx.h"
+
+#include "clrhost.h"
+#include "utilcode.h"
+#include "ex.h"
+#include "clrnt.h"
+#include "contract.h"
+
+#if defined __llvm__
+#  if defined(__has_feature) && __has_feature(address_sanitizer)
+#    define HAS_ADDRESS_SANITIZER
+#  endif
+#endif
+
+#ifdef _DEBUG_IMPL
+
+//
+// I'd very much like for this to go away. Its used to disable all THROWS contracts within whatever DLL this
+// function is called from. That's obviously very, very bad, since there's no validation of those macros. But it
+// can be difficult to remove this without actually fixing every violation at the same time.
+//
+// When this flag is finally removed, remove RealCLRThrowsExceptionWorker() too and put CONTRACT_THROWS() in place
+// of it.
+//
+//
+static BOOL dbg_fDisableThrowCheck = FALSE;
+
+void DisableThrowCheck()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    dbg_fDisableThrowCheck = TRUE;
+}
+
+#ifdef HAS_ADDRESS_SANITIZER
+// use the functionality from address santizier (which does not throw exceptions)
+#else
+
+#define CLRThrowsExceptionWorker() RealCLRThrowsExceptionWorker(__FUNCTION__, __FILE__, __LINE__)
+
+static void RealCLRThrowsExceptionWorker(_In_z_ const char *szFunction,
+                                         _In_z_ const char *szFile,
+                                         int lineNum)
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (dbg_fDisableThrowCheck)
+    {
+        return;
+    }
+
+    CONTRACT_THROWSEX(szFunction, szFile, lineNum);
+}
+
+#endif // HAS_ADDRESS_SANITIZER
+#endif //_DEBUG_IMPL
+
+#if defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
+
+thread_local ClrDebugState* t_pClrDebugState;
+
+// Fls callback to deallocate ClrDebugState when our FLS block goes away.
+void FreeClrDebugState(LPVOID pTlsData)
+{
+    ClrDebugState *pClrDebugState = (ClrDebugState*)pTlsData;
+
+    // Make sure the ClrDebugState was initialized by a compatible version of
+    // utilcode.lib. If it was initialized by an older version, we just let it leak.
+    if (pClrDebugState && (pClrDebugState->ViolationMask() & CanFreeMe) && !(pClrDebugState->ViolationMask() & BadDebugState))
+    {
+        // Since "!(pClrDebugState->m_violationmask & BadDebugState)", we know we have
+        // a valid m_pLockData
+        _ASSERTE(pClrDebugState->GetDbgStateLockData() != NULL);
+        HeapFree(GetProcessHeap(), 0, pClrDebugState->GetDbgStateLockData());
+
+        HeapFree(GetProcessHeap(), 0, pClrDebugState);
+    }
+}
+
+//=============================================================================================
+// Used to initialize the per-thread ClrDebugState. This is called once per thread (with
+// possible exceptions for OOM scenarios.)
+//
+// No matter what, this function will not return NULL. If it can't do its job because of OOM reasons,
+// it will return a pointer to &gBadClrDebugState which effectively disables contracts for
+// this thread.
+//=============================================================================================
+ClrDebugState *CLRInitDebugState()
+{
+    // This is our global "bad" debug state that thread use when they OOM on CLRInitDebugState.
+    // We really only need to initialize it once but initializing each time is convenient
+    // and has low perf impact.
+    static ClrDebugState gBadClrDebugState;
+    gBadClrDebugState.ViolationMaskSet( AllViolation );
+    gBadClrDebugState.SetOkToThrow();
+
+    ClrDebugState *pNewClrDebugState = NULL;
+    ClrDebugState *pClrDebugState = NULL;
+    DbgStateLockData *pNewLockData = NULL;
+
+    // Yuck. We cannot call the hosted allocator for ClrDebugState (it is impossible to maintain a guarantee
+    // that none of code paths, many of them called conditionally, don't themselves trigger a ClrDebugState creation.)
+    // We have to call the OS directly for this.
+    pNewClrDebugState = (ClrDebugState*)HeapAlloc(GetProcessHeap(), 0, sizeof(ClrDebugState));
+    if (pNewClrDebugState != NULL)
+    {
+        // Only allocate a DbgStateLockData if its owning ClrDebugState was successfully allocated
+        pNewLockData  = (DbgStateLockData *)HeapAlloc(GetProcessHeap(), 0, sizeof(DbgStateLockData));
+    }
+
+    if ((pNewClrDebugState != NULL) && (pNewLockData != NULL))
+    {
+        // Both allocations succeeded, so initialize the structures, and have
+        // pNewClrDebugState point to pNewLockData.  If either of the allocations
+        // failed, we'll use gBadClrDebugState for this thread, and free whichever of
+        // pNewClrDebugState or pNewLockData actually did get allocated (if either did).
+        // (See code in this function below, outside this block.)
+
+        pNewClrDebugState->SetStartingValues();
+        pNewClrDebugState->ViolationMaskSet( CanFreeMe );
+        _ASSERTE(!(pNewClrDebugState->ViolationMask() & BadDebugState));
+
+        pNewLockData->SetStartingValues();
+        pNewClrDebugState->SetDbgStateLockData(pNewLockData);
+    }
+
+
+    // This is getting really diseased. All the one-time host init stuff inside the ClrFlsStuff could actually
+    // have caused mscorwks contracts to be executed since the last time we actually checked to see if the ClrDebugState
+    // needed creating.
+    //
+    // So we must make one last check to see if the ClrDebugState still needs creating.
+    //
+    ClrDebugState *pTmp = t_pClrDebugState;
+    if (pTmp != NULL)
+    {
+        // Recursive call set up ClrDebugState for us
+        pClrDebugState = pTmp;
+    }
+    else if ((pNewClrDebugState != NULL) && (pNewLockData != NULL))
+    {
+        // Normal case: our new ClrDebugState will be the one we just allocated.
+        // Note that we require BOTH the ClrDebugState and the DbgStateLockData
+        // structures to have been successfully allocated for contracts to be
+        // enabled for this thread.
+        _ASSERTE(!(pNewClrDebugState->ViolationMask() & BadDebugState));
+        _ASSERTE(pNewClrDebugState->GetDbgStateLockData() == pNewLockData);
+        pClrDebugState = pNewClrDebugState;
+    }
+    else
+    {
+        // OOM case: HeapAlloc of newClrDebugState failed.
+        pClrDebugState = &gBadClrDebugState;
+    }
+
+    _ASSERTE(pClrDebugState != NULL);
+
+    t_pClrDebugState = pClrDebugState;
+
+    // The ClrDebugState we allocated above made it into FLS iff
+    //      the DbgStateLockData we allocated above made it into
+    //      the FLS's ClrDebugState::m_pLockData
+    // These debug-only checks enforce this invariant
+
+    if (pClrDebugState != NULL)
+    {
+        // If we're here, then typically pClrDebugState is what's in FLS.  However,
+        // it's possible that pClrDebugState is gBadClrDebugState, and FLS is NULL
+        // (if the last ClrFlsSetValue() failed).  Either way, our checks below
+        // are valid ones to make.
+
+        if (pClrDebugState == pNewClrDebugState)
+        {
+            // ClrDebugState we allocated above made it into FLS, so DbgStateLockData
+            // must be there, too
+            _ASSERTE(pNewLockData != NULL);
+            _ASSERTE(pClrDebugState->GetDbgStateLockData() == pNewLockData);
+        }
+        else
+        {
+            // ClrDebugState we allocated above did NOT make it into FLS,
+            // so the DbgStateLockData we allocated must not be there, either
+            _ASSERTE(pClrDebugState->GetDbgStateLockData() == NULL || pClrDebugState->GetDbgStateLockData() != pNewLockData);
+        }
+    }
+
+    // One more invariant:  Because of ordering & conditions around the HeapAllocs above,
+    // we'll never have a DbgStateLockData without a ClrDebugState
+    _ASSERTE((pNewLockData == NULL) || (pNewClrDebugState != NULL));
+
+    if (pNewClrDebugState != NULL && pClrDebugState != pNewClrDebugState)
+    {
+        // We allocated a ClrDebugState which didn't make it into FLS, so free it.
+        HeapFree(GetProcessHeap(), 0, pNewClrDebugState);
+        if (pNewLockData != NULL)
+        {
+            // We also allocated a DbgStateLockData that didn't make it into FLS, so
+            // free it, too.  (Remember, we asserted above that we can only have
+            // this unused DbgStateLockData if we had an unused ClrDebugState
+            // as well (which we just freed).)
+            HeapFree(GetProcessHeap(), 0, pNewLockData);
+        }
+    }
+
+    return pClrDebugState;
+} // CLRInitDebugState
+
+#endif //defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
+
+const NoThrow nothrow = { 0 };
+
+#if defined(HAS_ADDRESS_SANITIZER) || defined(DACCESS_COMPILE)
+// use standard heap functions for address santizier
+#else
+
+#ifdef _DEBUG
+#ifdef TARGET_X86
+#define OS_HEAP_ALIGN 8
+#else
+#define OS_HEAP_ALIGN 16
+#endif
+#define CLRALLOC_TAG 0x2ce145f1
+#endif
+
+#ifdef HOST_WINDOWS
+static HANDLE g_hProcessHeap;
+#endif
+
+FORCEINLINE void* ClrMalloc(size_t size)
+{
+    STATIC_CONTRACT_NOTHROW;
+
+#ifdef FAILPOINTS_ENABLED
+    if (RFS_HashStack())
+        return NULL;
+#endif
+
+    void* p;
+
+#ifdef _DEBUG
+    size += OS_HEAP_ALIGN;
+#endif
+
+#ifdef HOST_WINDOWS
+    HANDLE hHeap = g_hProcessHeap;
+    if (hHeap == NULL)
+    {
+        InterlockedCompareExchangeT(&g_hProcessHeap, ::GetProcessHeap(), NULL);
+        hHeap = g_hProcessHeap;
+    }
+
+    p = HeapAlloc(hHeap, 0, size);
+#else
+    p = malloc(size);
+#endif
+
+#ifdef _DEBUG
+    // Store the tag to detect heap contamination
+    if (p != NULL)
+    {
+        *((DWORD*)p) = CLRALLOC_TAG;
+        p = (BYTE*)p + OS_HEAP_ALIGN;
+    }
+#endif
+
+#ifndef SELF_NO_HOST
+    if (p == NULL
+        // If we have not created StressLog ring buffer, we should not try to use it.
+        // StressLog is going to do a memory allocation.  We may enter an endless loop.
+        && StressLog::t_pCurrentThreadLog != NULL)
+    {
+        STRESS_LOG_OOM_STACK(size);
+    }
+#endif
+
+    return p;
+}
+
+FORCEINLINE void ClrFree(void* p)
+{
+    STATIC_CONTRACT_NOTHROW;
+
+#ifdef _DEBUG
+    if (p != NULL)
+    {
+        // Check the heap handle to detect heap contamination
+        p = (BYTE*)p - OS_HEAP_ALIGN;
+        if (*((DWORD*)p) != CLRALLOC_TAG)
+            _ASSERTE(!"Heap contamination detected! HeapFree was called on a heap other than the one that memory was allocated from.\n"
+                "Possible cause: you used new (executable) to allocate the memory, but didn't use DeleteExecutable() to free it.");
+    }
+#endif
+
+#ifdef HOST_WINDOWS
+    if (p != NULL)
+        HeapFree(g_hProcessHeap, 0, p);
+#else
+    free(p);
+#endif
+}
+
+void * __cdecl
+operator new(size_t n)
+{
+#ifdef _DEBUG_IMPL
+    CLRThrowsExceptionWorker();
+#endif
+
+    STATIC_CONTRACT_THROWS;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+
+    void* result = ClrMalloc(n);
+    if (result == NULL) {
+        ThrowOutOfMemory();
+    }
+    TRASH_LASTERROR;
+    return result;
+}
+
+void * __cdecl
+operator new[](size_t n)
+{
+#ifdef _DEBUG_IMPL
+    CLRThrowsExceptionWorker();
+#endif
+
+    STATIC_CONTRACT_THROWS;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+
+    void* result = ClrMalloc(n);
+    if (result == NULL) {
+        ThrowOutOfMemory();
+    }
+    TRASH_LASTERROR;
+    return result;
+};
+
+#endif // HAS_ADDRESS_SANITIZER || DACCESS_COMPILE
+
+void * __cdecl operator new(size_t n, const NoThrow&) NOEXCEPT
+{
+#if defined(HAS_ADDRESS_SANITIZER) || defined(DACCESS_COMPILE)
+    // use standard heap functions for address santizier (which doesn't provide for NoThrow)
+       void * result = operator new(n);
+#else
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+
+    INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
+
+    void* result = ClrMalloc(n);
+#endif // HAS_ADDRESS_SANITIZER || DACCESS_COMPILE
+       TRASH_LASTERROR;
+    return result;
+}
+
+void * __cdecl operator new[](size_t n, const NoThrow&) NOEXCEPT
+{
+#if defined(HAS_ADDRESS_SANITIZER) || defined(DACCESS_COMPILE)
+    // use standard heap functions for address santizier (which doesn't provide for NoThrow)
+       void * result = operator new[](n);
+#else
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+
+    INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
+
+    void* result = ClrMalloc(n);
+#endif // HAS_ADDRESS_SANITIZER || DACCESS_COMPILE
+       TRASH_LASTERROR;
+    return result;
+}
+
+#if defined(HAS_ADDRESS_SANITIZER) || defined(DACCESS_COMPILE)
+// use standard heap functions for address santizier
+#else
+void __cdecl
+operator delete(void *p) NOEXCEPT
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+
+    ClrFree(p);
+
+    TRASH_LASTERROR;
+}
+
+void __cdecl
+operator delete[](void *p) NOEXCEPT
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+
+    ClrFree(p);
+    TRASH_LASTERROR;
+}
+
+#endif // HAS_ADDRESS_SANITIZER || DACCESS_COMPILE
+
+/* ------------------------------------------------------------------------ *
+ * New operator overloading for the executable heap
+ * ------------------------------------------------------------------------ */
+
+#ifdef HOST_WINDOWS
+
+HANDLE ClrGetProcessExecutableHeap()
+{
+    // Note: this can be called a little early for real contracts, so we use static contracts instead.
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    static HANDLE g_ExecutableHeapHandle;
+
+    //
+    // Create the executable heap lazily
+    //
+    if (g_ExecutableHeapHandle == NULL)
+    {
+
+        HANDLE ExecutableHeapHandle = HeapCreate(
+            HEAP_CREATE_ENABLE_EXECUTE,                 // heap allocation attributes
+            0,                                          // initial heap size
+            0                                           // maximum heap size; 0 == growable
+        );
+
+        if (ExecutableHeapHandle == NULL)
+            return NULL;
+
+        HANDLE ExistingValue = InterlockedCompareExchangeT(&g_ExecutableHeapHandle, ExecutableHeapHandle, NULL);
+        if (ExistingValue != NULL)
+        {
+            HeapDestroy(ExecutableHeapHandle);
+        }
+    }
+
+    return g_ExecutableHeapHandle;
+}
+
+const CExecutable executable = { 0 };
+
+void * __cdecl operator new(size_t n, const CExecutable&)
+{
+#if defined(_DEBUG_IMPL)
+    CLRThrowsExceptionWorker();
+#endif
+
+    STATIC_CONTRACT_THROWS;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
+    if (hExecutableHeap == NULL) {
+        ThrowOutOfMemory();
+    }
+
+    void * result = HeapAlloc(hExecutableHeap, 0, n);
+    if (result == NULL) {
+        ThrowOutOfMemory();
+    }
+    TRASH_LASTERROR;
+    return result;
+}
+
+void * __cdecl operator new[](size_t n, const CExecutable&)
+{
+#if defined(_DEBUG_IMPL)
+    CLRThrowsExceptionWorker();
+#endif
+
+    STATIC_CONTRACT_THROWS;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
+    if (hExecutableHeap == NULL) {
+        ThrowOutOfMemory();
+    }
+
+    void * result = HeapAlloc(hExecutableHeap, 0, n);
+    if (result == NULL) {
+        ThrowOutOfMemory();
+    }
+    TRASH_LASTERROR;
+    return result;
+}
+
+void * __cdecl operator new(size_t n, const CExecutable&, const NoThrow&)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
+
+    HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
+    if (hExecutableHeap == NULL)
+        return NULL;
+
+    void * result = HeapAlloc(hExecutableHeap, 0, n);
+    TRASH_LASTERROR;
+    return result;
+}
+
+void * __cdecl operator new[](size_t n, const CExecutable&, const NoThrow&)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
+
+    HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
+    if (hExecutableHeap == NULL)
+        return NULL;
+
+    void * result = HeapAlloc(hExecutableHeap, 0, n);
+    TRASH_LASTERROR;
+    return result;
+}
+
+#endif // HOST_WINDOWS
diff --git a/src/utilcode/debug.cpp b/src/utilcode/debug.cpp
new file mode 100644 (file)
index 0000000..85a71f8
--- /dev/null
@@ -0,0 +1,299 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// Debug.cpp
+//
+// Helper code for debugging.
+//*****************************************************************************
+//
+
+
+#include "stdafx.h"
+#include "utilcode.h"
+#include "ex.h"
+#include "corexcep.h"
+
+#include "log.h"
+
+extern "C" _CRTIMP int __cdecl _flushall(void);
+
+Volatile<LONG> g_DbgSuppressAllocationAsserts = 0;
+
+#ifdef _DEBUG
+
+VOID LogAssert(
+    LPCSTR      szFile,
+    int         iLine,
+    LPCSTR      szExpr
+)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_DEBUG_ONLY;
+
+    // Log asserts to the stress log. Note that we can't include the szExpr b/c that
+    // may not be a string literal (particularly for formatt-able asserts).
+    STRESS_LOG2(LF_ASSERT, LL_ALWAYS, "ASSERT:%s, line:%d\n", szFile, iLine);
+
+    SYSTEMTIME st;
+#ifndef TARGET_UNIX
+    GetLocalTime(&st);
+#else
+    GetSystemTime(&st);
+#endif
+
+    PathString exename;
+    WszGetModuleFileName(NULL, exename);
+
+    LOG((LF_ASSERT,
+         LL_FATALERROR,
+         "FAILED ASSERT(PID %d [0x%08x], Thread: %d [0x%x]) (%lu/%lu/%lu: %02lu:%02lu:%02lu %s): File: %s, Line %d : %s\n",
+         GetCurrentProcessId(),
+         GetCurrentProcessId(),
+         GetCurrentThreadId(),
+         GetCurrentThreadId(),
+         (ULONG)st.wMonth,
+         (ULONG)st.wDay,
+         (ULONG)st.wYear,
+         1 + (( (ULONG)st.wHour + 11 ) % 12),
+         (ULONG)st.wMinute,
+         (ULONG)st.wSecond,
+         (st.wHour < 12) ? "am" : "pm",
+         szFile,
+         iLine,
+         szExpr));
+    LOG((LF_ASSERT, LL_FATALERROR, "RUNNING EXE: %ws\n", exename.GetUnicode()));
+}
+
+//*****************************************************************************
+// This function is called in order to ultimately return an out of memory
+// failed hresult.  But this code will check what environment you are running
+// in and give an assert for running in a debug build environment.  Usually
+// out of memory on a dev machine is a bogus allocation, and this allows you
+// to catch such errors.  But when run in a stress envrionment where you are
+// trying to get out of memory, assert behavior stops the tests.
+//*****************************************************************************
+HRESULT _OutOfMemory(LPCSTR szFile, int iLine)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_DEBUG_ONLY;
+    return (E_OUTOFMEMORY);
+}
+
+int _DbgBreakCount = 0;
+static const char * szLowMemoryAssertMessage = "Assert failure (unable to format)";
+
+//*****************************************************************************
+// This function will handle ignore codes and tell the user what is happening.
+//*****************************************************************************
+bool _DbgBreakCheck(
+    LPCSTR      szFile,
+    int         iLine,
+    LPCSTR      szExpr,
+    BOOL        fConstrained)
+{
+    STATIC_CONTRACT_THROWS;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+    STATIC_CONTRACT_DEBUG_ONLY;
+
+    CONTRACT_VIOLATION(FaultNotFatal | GCViolation | TakesLockViolation);
+
+    SString debugOutput;
+    SString dialogOutput;
+    SString modulePath;
+    SString dialogTitle;
+    SString dialogIgnoreMessage;
+    BOOL formattedMessages = FALSE;
+
+    // If we are low on memory we cannot even format a message. If this happens we want to
+    // contain the exception here but display as much information as we can about the exception.
+    if (!fConstrained)
+    {
+        EX_TRY
+        {
+            ClrGetModuleFileName(0, modulePath);
+            debugOutput.Printf(
+                W("\nAssert failure(PID %d [0x%08x], Thread: %d [0x%04x]): %hs\n")
+                W("    File: %hs Line: %d\n")
+                W("    Image: "),
+                GetCurrentProcessId(), GetCurrentProcessId(),
+                GetCurrentThreadId(), GetCurrentThreadId(),
+                szExpr, szFile, iLine);
+            debugOutput.Append(modulePath);
+            debugOutput.Append(W("\n\n"));
+
+            // Change format for message box.  The extra spaces in the title
+            // are there to get around format truncation.
+            dialogOutput.Printf(
+                W("%hs\n\n%hs, Line: %d\n\nAbort - Kill program\nRetry - Debug\nIgnore - Keep running\n")
+                W("\n\nImage:\n"), szExpr, szFile, iLine);
+            dialogOutput.Append(modulePath);
+            dialogOutput.Append(W("\n"));
+            dialogTitle.Printf(W("Assert Failure (PID %d, Thread %d/0x%04x)"),
+                GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId());
+
+            dialogIgnoreMessage.Printf(W("Ignore the assert for the rest of this run?\nYes - Assert will never fire again.\nNo - Assert will continue to fire.\n\n%hs\nLine: %d\n"),
+                szFile, iLine);
+
+            formattedMessages = TRUE;
+        }
+        EX_CATCH
+        {
+        }
+        EX_END_CATCH(SwallowAllExceptions);
+    }
+
+    // Emit assert in debug output and console for easy access.
+    if (formattedMessages)
+    {
+        WszOutputDebugString(debugOutput);
+        fwprintf(stderr, W("%s"), (const WCHAR*)debugOutput);
+    }
+    else
+    {
+        // Note: we cannot convert to unicode or concatenate in this situation.
+        OutputDebugStringA(szLowMemoryAssertMessage);
+        OutputDebugStringA("\n");
+        OutputDebugStringA(szFile);
+        OutputDebugStringA("\n");
+        OutputDebugStringA(szExpr);
+        OutputDebugStringA("\n");
+        printf(szLowMemoryAssertMessage);
+        printf("\n");
+        printf(szFile);
+        printf("\n");
+        printf("%s", szExpr);
+        printf("\n");
+    }
+
+    LogAssert(szFile, iLine, szExpr);
+    FlushLogging();         // make certain we get the last part of the log
+    _flushall();
+
+    if (IsDebuggerPresent())
+    {
+        return true;       // like a retry
+    }
+
+    TerminateProcess(GetCurrentProcess(), 1);
+    return false;
+}
+
+bool _DbgBreakCheckNoThrow(
+    LPCSTR      szFile,
+    int         iLine,
+    LPCSTR      szExpr,
+    BOOL        fConstrained)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+    STATIC_CONTRACT_DEBUG_ONLY;
+
+    bool failed = false;
+    bool result = false;
+    EX_TRY
+    {
+        result = _DbgBreakCheck(szFile, iLine, szExpr, fConstrained);
+    }
+    EX_CATCH
+    {
+        failed = true;
+    }
+    EX_END_CATCH(SwallowAllExceptions);
+
+    if (failed)
+    {
+        return true;
+    }
+    return result;
+}
+
+// Called from within the IfFail...() macros.  Set a breakpoint here to break on
+// errors.
+VOID DebBreak()
+{
+  STATIC_CONTRACT_LEAF;
+  static int i = 0;  // add some code here so that we'll be able to set a BP
+  i++;
+}
+
+VOID DebBreakHr(HRESULT hr)
+{
+  STATIC_CONTRACT_LEAF;
+  static int i = 0;  // add some code here so that we'll be able to set a BP
+  _ASSERTE(hr != (HRESULT) 0xcccccccc);
+  i++;
+}
+void *dbgForceToMemory;     // dummy pointer that pessimises enregistration
+
+int g_BufferLock = -1;
+
+VOID DbgAssertDialog(const char *szFile, int iLine, const char *szExpr)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+    STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+
+    DEBUG_ONLY_FUNCTION;
+
+#ifdef DACCESS_COMPILE
+    // In the DAC case, asserts can mean one of two things.
+    // Either there is a bug in the DAC infrastructure itself (a real assert), or just
+    // that the target is corrupt or being accessed at an inconsistent state (a "target
+    // consistency failure").  For target consistency failures, we need a mechanism to disable them
+    // (without affecting other asserts) so that we can test corrupt / inconsistent targets.
+
+    // @dbgtodo  DAC: For now we're treating all asserts as if they are target consistency checks.
+    // In the future we should differentiate the two so that real asserts continue to fire, even when
+    // we expect the target to be inconsistent.  See DevDiv Bugs 31674.
+    if( !DacTargetConsistencyAssertsEnabled() )
+    {
+        return;
+    }
+#endif // #ifndef DACCESS_COMPILE
+
+    // We increment this every time we use the SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE
+    // macro below.  If it is a big number it means either a lot of threads are asserting
+    // or we have a recursion in the Assert logic (usually the latter).  At least with this
+    // code in place, we don't get stack overflow (and the process torn down).
+    // the correct fix is to avoid calling asserting when allocating memory with an assert.
+    if (g_DbgSuppressAllocationAsserts > 16)
+        DebugBreak();
+
+    SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
+
+    // Raising the assert dialog can cause us to re-enter the host when allocating
+    // memory for the string.  Since this is debug-only code, we can safely skip
+    // violation asserts here, particularly since they can also cause infinite
+    // recursion.
+    PERMANENT_CONTRACT_VIOLATION(HostViolation, ReasonDebugOnly);
+
+    dbgForceToMemory = &szFile;     //make certain these args are available in the debugger
+    dbgForceToMemory = &iLine;
+    dbgForceToMemory = &szExpr;
+
+    LONG lAlreadyOwned = InterlockedExchange((LPLONG)&g_BufferLock, 1);
+    if (lAlreadyOwned == 1)
+    {
+        if (_DbgBreakCheckNoThrow(szFile, iLine, szExpr, FALSE))
+        {
+            _DbgBreak();
+        }
+    }
+    else
+    {
+        char *szExprToDisplay = (char*)szExpr;
+        if (_DbgBreakCheckNoThrow(szFile, iLine, szExprToDisplay, FALSE))
+        {
+            _DbgBreak();
+        }
+
+        g_BufferLock = 0;
+    }
+} // DbgAssertDialog
+
+#endif // _DEBUG
diff --git a/src/utilcode/dlwrap.cpp b/src/utilcode/dlwrap.cpp
new file mode 100644 (file)
index 0000000..8cb312f
--- /dev/null
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#include "stdafx.h"                     // Precompiled header key.
+#include "utilcode.h"
+#include "metadata.h"
+#include "ex.h"
+#include "pedecoder.h"
+
+#include <wininet.h>
+#include <urlmon.h>
+
+DWORD
+GetFileVersionInfoSizeW_NoThrow(
+        LPCWSTR lptstrFilename, /* Filename of version stamped file */
+        LPDWORD lpdwHandle
+        )
+{
+    WRAPPER_NO_CONTRACT;
+    HRESULT hr=S_OK;
+    DWORD dwRet=0;
+    EX_TRY
+    {
+        dwRet=GetFileVersionInfoSize( (LPWSTR)lptstrFilename,  lpdwHandle );
+    }
+    EX_CATCH_HRESULT(hr);
+    if (hr!=S_OK)
+        SetLastError(hr);
+    return dwRet;
+
+}
+
+BOOL
+GetFileVersionInfoW_NoThrow(
+        LPCWSTR lptstrFilename, /* Filename of version stamped file */
+        DWORD dwHandle,         /* Information from GetFileVersionSize */
+        DWORD dwLen,            /* Length of buffer for info */
+        LPVOID lpData
+        )
+{
+    WRAPPER_NO_CONTRACT;
+    HRESULT hr=S_OK;
+    BOOL bRet=FALSE;
+    EX_TRY
+    {
+        bRet=GetFileVersionInfo( (LPWSTR)lptstrFilename, dwHandle,dwLen,lpData );
+    }
+    EX_CATCH_HRESULT(hr);
+    if (hr!=S_OK)
+        SetLastError(hr);
+    return bRet;
+
+}
+
+BOOL
+VerQueryValueW_NoThrow(
+        const LPVOID pBlock,
+        LPCWSTR lpSubBlock,
+        LPVOID * lplpBuffer,
+        PUINT puLen
+        )
+{
+    WRAPPER_NO_CONTRACT;
+    HRESULT hr=S_OK;
+    BOOL bRet=FALSE;
+    EX_TRY
+    {
+        bRet=VerQueryValueW( pBlock, (LPWSTR)lpSubBlock,lplpBuffer,puLen );
+    }
+    EX_CATCH_HRESULT(hr);
+    if (hr!=S_OK)
+        SetLastError(hr);
+    return bRet;
+
+}
+
diff --git a/src/utilcode/ex.cpp b/src/utilcode/ex.cpp
new file mode 100644 (file)
index 0000000..47cb488
--- /dev/null
@@ -0,0 +1,1324 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+//
+// ---------------------------------------------------------------------------
+// Ex.cpp
+// ---------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "string.h"
+#include "ex.h"
+#include "holder.h"
+
+// error codes
+#include "corerror.h"
+
+#include "resource.h"
+
+#include "olectl.h"
+
+#include "corexcep.h"
+
+#define MAX_EXCEPTION_MSG   200
+
+// Set if fatal error (like stack overflow or out of memory) occurred in this process.
+GVAL_IMPL_INIT(HRESULT, g_hrFatalError, S_OK);
+
+// Helper function to get an exception object from outside the exception.  In
+//  the CLR, it may be from the Thread object.  Non-CLR users have no thread object,
+//  and it will do nothing.
+void GetLastThrownObjectExceptionFromThread(Exception **ppException);
+
+// Helper function to get pointer to clr module base
+void* GetClrModuleBase();
+
+Exception *Exception::g_OOMException = NULL;
+
+// avoid global constructors
+static BYTE g_OOMExceptionInstance[sizeof(OutOfMemoryException)];
+
+Exception * Exception::GetOOMException()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    if (!g_OOMException) {
+        // Create a local copy on the stack and then copy it over to the static instance.
+        // This avoids race conditions caused by multiple initializations of vtable in the constructor
+
+        OutOfMemoryException local(TRUE);  // Construct a "preallocated" instance.
+        memcpy((void*)&g_OOMExceptionInstance, (void*)&local, sizeof(OutOfMemoryException));
+
+        g_OOMException = (OutOfMemoryException*)&g_OOMExceptionInstance;
+    }
+
+    return g_OOMException;
+}
+
+/*virtual*/ Exception *OutOfMemoryException::Clone()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return GetOOMException();
+}
+
+//------------------------------------------------------------------------------
+void Exception::Delete(Exception* pvMemory)
+{
+    CONTRACTL
+    {
+        GC_NOTRIGGER;
+        NOTHROW;
+        SUPPORTS_DAC_HOST_ONLY;   // Exceptions aren't currently marshalled by DAC - just used in the host
+    }
+    CONTRACTL_END;
+
+    if ((pvMemory == 0) || pvMemory->IsPreallocatedException())
+    {
+        return;
+    }
+
+    ::delete((Exception *) pvMemory);
+}
+
+void Exception::GetMessage(SString &result)
+{
+    WRAPPER_NO_CONTRACT;
+
+    return GenerateTopLevelHRExceptionMessage(GetHR(), result);
+}
+
+void HRMsgException::GetMessage(SString &result)
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (m_msg.IsEmpty())
+        HRException::GetMessage(result);
+    else
+        result = m_msg;
+}
+
+Exception *Exception::Clone()
+{
+    CONTRACTL
+    {
+        GC_NOTRIGGER;
+        THROWS;
+    }
+    CONTRACTL_END;
+
+    NewHolder<Exception> retExcep(CloneHelper());
+    if (m_innerException)
+    {
+        retExcep->m_innerException = m_innerException->Clone();
+    }
+
+    retExcep.SuppressRelease();
+    return retExcep;
+}
+
+Exception *Exception::CloneHelper()
+{
+    StackSString s;
+    GetMessage(s);
+    return new HRMsgException(GetHR(), s);
+}
+
+Exception *Exception::DomainBoundClone()
+{
+    CONTRACTL
+    {
+        // Because we may call DomainBoundCloneHelper() of ObjrefException or CLRLastThrownObjectException
+        // this should be GC_TRIGGERS, but we can not include EE contracts in Utilcode.
+        THROWS;
+    }
+    CONTRACTL_END;
+
+    NewHolder<Exception> retExcep(DomainBoundCloneHelper());
+    if (m_innerException)
+    {
+        retExcep->m_innerException = m_innerException->DomainBoundClone();
+    }
+
+    retExcep.SuppressRelease();
+    return retExcep;
+}
+
+BOOL Exception::IsTerminal()
+{
+    CONTRACTL
+    {
+        GC_NOTRIGGER;
+        NOTHROW;
+
+        // CLRException::GetHR() can eventually call BaseDomain::CreateHandle(),
+        // which can indirectly cause a lock if we get a miss in the handle table
+        // cache (TableCacheMissOnAlloc).  Since CLRException::GetHR() is virtual,
+        // SCAN won't find this for you (though 40 minutes of one of the sql stress
+        // tests will :-))
+        CAN_TAKE_LOCK;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = GetHR();
+    return (COR_E_THREADABORTED == hr);
+}
+
+BOOL Exception::IsTransient()
+{
+    WRAPPER_NO_CONTRACT;
+
+    return IsTransient(GetHR());
+}
+
+/* static */
+BOOL Exception::IsTransient(HRESULT hr)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (hr == COR_E_THREADABORTED
+            || hr == COR_E_THREADINTERRUPTED
+            || hr == COR_E_THREADSTOP
+            || hr == COR_E_APPDOMAINUNLOADED
+            || hr == E_OUTOFMEMORY
+            || hr == HRESULT_FROM_WIN32(ERROR_COMMITMENT_LIMIT) // ran out of room in pagefile
+            || hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY)
+            || hr == (HRESULT)STATUS_NO_MEMORY
+            || hr == COR_E_STACKOVERFLOW
+            || hr == MSEE_E_ASSEMBLYLOADINPROGRESS);
+}
+
+//------------------------------------------------------------------------------
+// Functions to manage the preallocated exceptions.
+// Virtual
+BOOL Exception::IsPreallocatedException()
+{   // Most exceptions can't be preallocated.  If they can be, their class
+    //  should provide a virtual override of this function.
+    return FALSE;
+}
+
+BOOL Exception::IsPreallocatedOOMException()
+{   // This is the preallocated OOM if it is preallocated and is OOM.
+    return IsPreallocatedException() && (GetInstanceType() == OutOfMemoryException::GetType());
+}
+
+//------------------------------------------------------------------------------
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+LPCSTR Exception::GetHRSymbolicName(HRESULT hr)
+{
+    LIMITED_METHOD_CONTRACT;
+
+#define CASE_HRESULT(hrname) case hrname: return #hrname;
+
+    switch (hr)
+    {
+        CASE_HRESULT(S_OK)//                             0x00000000L
+        CASE_HRESULT(S_FALSE)//                          0x00000001L
+
+        CASE_HRESULT(E_UNEXPECTED)//                     0x8000FFFFL
+        CASE_HRESULT(E_NOTIMPL)//                        0x80004001L
+        CASE_HRESULT(E_OUTOFMEMORY)//                    0x8007000EL
+        CASE_HRESULT(E_INVALIDARG)//                     0x80070057L
+        CASE_HRESULT(E_NOINTERFACE)//                    0x80004002L
+        CASE_HRESULT(E_POINTER)//                        0x80004003L
+        CASE_HRESULT(E_HANDLE)//                         0x80070006L
+        CASE_HRESULT(E_ABORT)//                          0x80004004L
+        CASE_HRESULT(E_FAIL)//                           0x80004005L
+        CASE_HRESULT(E_ACCESSDENIED)//                   0x80070005L
+
+#ifdef FEATURE_COMINTEROP
+        CASE_HRESULT(CO_E_INIT_TLS)//                    0x80004006L
+        CASE_HRESULT(CO_E_INIT_SHARED_ALLOCATOR)//       0x80004007L
+        CASE_HRESULT(CO_E_INIT_MEMORY_ALLOCATOR)//       0x80004008L
+        CASE_HRESULT(CO_E_INIT_CLASS_CACHE)//            0x80004009L
+        CASE_HRESULT(CO_E_INIT_RPC_CHANNEL)//            0x8000400AL
+        CASE_HRESULT(CO_E_INIT_TLS_SET_CHANNEL_CONTROL)// 0x8000400BL
+        CASE_HRESULT(CO_E_INIT_TLS_CHANNEL_CONTROL)//    0x8000400CL
+        CASE_HRESULT(CO_E_INIT_UNACCEPTED_USER_ALLOCATOR)// 0x8000400DL
+        CASE_HRESULT(CO_E_INIT_SCM_MUTEX_EXISTS)//       0x8000400EL
+        CASE_HRESULT(CO_E_INIT_SCM_FILE_MAPPING_EXISTS)// 0x8000400FL
+        CASE_HRESULT(CO_E_INIT_SCM_MAP_VIEW_OF_FILE)//   0x80004010L
+        CASE_HRESULT(CO_E_INIT_SCM_EXEC_FAILURE)//       0x80004011L
+        CASE_HRESULT(CO_E_INIT_ONLY_SINGLE_THREADED)//   0x80004012L
+
+// ******************
+// FACILITY_ITF
+// ******************
+
+        CASE_HRESULT(OLE_E_OLEVERB)//                    0x80040000L
+        CASE_HRESULT(OLE_E_ADVF)//                       0x80040001L
+        CASE_HRESULT(OLE_E_ENUM_NOMORE)//                0x80040002L
+        CASE_HRESULT(OLE_E_ADVISENOTSUPPORTED)//         0x80040003L
+        CASE_HRESULT(OLE_E_NOCONNECTION)//               0x80040004L
+        CASE_HRESULT(OLE_E_NOTRUNNING)//                 0x80040005L
+        CASE_HRESULT(OLE_E_NOCACHE)//                    0x80040006L
+        CASE_HRESULT(OLE_E_BLANK)//                      0x80040007L
+        CASE_HRESULT(OLE_E_CLASSDIFF)//                  0x80040008L
+        CASE_HRESULT(OLE_E_CANT_GETMONIKER)//            0x80040009L
+        CASE_HRESULT(OLE_E_CANT_BINDTOSOURCE)//          0x8004000AL
+        CASE_HRESULT(OLE_E_STATIC)//                     0x8004000BL
+        CASE_HRESULT(OLE_E_PROMPTSAVECANCELLED)//        0x8004000CL
+        CASE_HRESULT(OLE_E_INVALIDRECT)//                0x8004000DL
+        CASE_HRESULT(OLE_E_WRONGCOMPOBJ)//               0x8004000EL
+        CASE_HRESULT(OLE_E_INVALIDHWND)//                0x8004000FL
+        CASE_HRESULT(OLE_E_NOT_INPLACEACTIVE)//          0x80040010L
+        CASE_HRESULT(OLE_E_CANTCONVERT)//                0x80040011L
+        CASE_HRESULT(OLE_E_NOSTORAGE)//                  0x80040012L
+        CASE_HRESULT(DV_E_FORMATETC)//                   0x80040064L
+        CASE_HRESULT(DV_E_DVTARGETDEVICE)//              0x80040065L
+        CASE_HRESULT(DV_E_STGMEDIUM)//                   0x80040066L
+        CASE_HRESULT(DV_E_STATDATA)//                    0x80040067L
+        CASE_HRESULT(DV_E_LINDEX)//                      0x80040068L
+        CASE_HRESULT(DV_E_TYMED)//                       0x80040069L
+        CASE_HRESULT(DV_E_CLIPFORMAT)//                  0x8004006AL
+        CASE_HRESULT(DV_E_DVASPECT)//                    0x8004006BL
+        CASE_HRESULT(DV_E_DVTARGETDEVICE_SIZE)//         0x8004006CL
+        CASE_HRESULT(DV_E_NOIVIEWOBJECT)//               0x8004006DL
+        CASE_HRESULT(DRAGDROP_E_NOTREGISTERED)//         0x80040100L
+        CASE_HRESULT(DRAGDROP_E_ALREADYREGISTERED)//     0x80040101L
+        CASE_HRESULT(DRAGDROP_E_INVALIDHWND)//           0x80040102L
+        CASE_HRESULT(CLASS_E_NOAGGREGATION)//            0x80040110L
+        CASE_HRESULT(CLASS_E_CLASSNOTAVAILABLE)//        0x80040111L
+        CASE_HRESULT(VIEW_E_DRAW)//                      0x80040140L
+        CASE_HRESULT(REGDB_E_READREGDB)//                0x80040150L
+        CASE_HRESULT(REGDB_E_WRITEREGDB)//               0x80040151L
+        CASE_HRESULT(REGDB_E_KEYMISSING)//               0x80040152L
+        CASE_HRESULT(REGDB_E_INVALIDVALUE)//             0x80040153L
+        CASE_HRESULT(REGDB_E_CLASSNOTREG)//              0x80040154L
+        CASE_HRESULT(CACHE_E_NOCACHE_UPDATED)//          0x80040170L
+        CASE_HRESULT(OLEOBJ_E_NOVERBS)//                 0x80040180L
+        CASE_HRESULT(INPLACE_E_NOTUNDOABLE)//            0x800401A0L
+        CASE_HRESULT(INPLACE_E_NOTOOLSPACE)//            0x800401A1L
+        CASE_HRESULT(CONVERT10_E_OLESTREAM_GET)//        0x800401C0L
+        CASE_HRESULT(CONVERT10_E_OLESTREAM_PUT)//        0x800401C1L
+        CASE_HRESULT(CONVERT10_E_OLESTREAM_FMT)//        0x800401C2L
+        CASE_HRESULT(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB)// 0x800401C3L
+        CASE_HRESULT(CONVERT10_E_STG_FMT)//              0x800401C4L
+        CASE_HRESULT(CONVERT10_E_STG_NO_STD_STREAM)//    0x800401C5L
+        CASE_HRESULT(CONVERT10_E_STG_DIB_TO_BITMAP)//    0x800401C6L
+        CASE_HRESULT(CLIPBRD_E_CANT_OPEN)//              0x800401D0L
+        CASE_HRESULT(CLIPBRD_E_CANT_EMPTY)//             0x800401D1L
+        CASE_HRESULT(CLIPBRD_E_CANT_SET)//               0x800401D2L
+        CASE_HRESULT(CLIPBRD_E_BAD_DATA)//               0x800401D3L
+        CASE_HRESULT(CLIPBRD_E_CANT_CLOSE)//             0x800401D4L
+        CASE_HRESULT(MK_E_CONNECTMANUALLY)//             0x800401E0L
+        CASE_HRESULT(MK_E_EXCEEDEDDEADLINE)//            0x800401E1L
+        CASE_HRESULT(MK_E_NEEDGENERIC)//                 0x800401E2L
+        CASE_HRESULT(MK_E_UNAVAILABLE)//                 0x800401E3L
+        CASE_HRESULT(MK_E_SYNTAX)//                      0x800401E4L
+        CASE_HRESULT(MK_E_NOOBJECT)//                    0x800401E5L
+        CASE_HRESULT(MK_E_INVALIDEXTENSION)//            0x800401E6L
+        CASE_HRESULT(MK_E_INTERMEDIATEINTERFACENOTSUPPORTED)// 0x800401E7L
+        CASE_HRESULT(MK_E_NOTBINDABLE)//                 0x800401E8L
+        CASE_HRESULT(MK_E_NOTBOUND)//                    0x800401E9L
+        CASE_HRESULT(MK_E_CANTOPENFILE)//                0x800401EAL
+        CASE_HRESULT(MK_E_MUSTBOTHERUSER)//              0x800401EBL
+        CASE_HRESULT(MK_E_NOINVERSE)//                   0x800401ECL
+        CASE_HRESULT(MK_E_NOSTORAGE)//                   0x800401EDL
+        CASE_HRESULT(MK_E_NOPREFIX)//                    0x800401EEL
+        CASE_HRESULT(MK_E_ENUMERATION_FAILED)//          0x800401EFL
+        CASE_HRESULT(CO_E_NOTINITIALIZED)//              0x800401F0L
+        CASE_HRESULT(CO_E_ALREADYINITIALIZED)//          0x800401F1L
+        CASE_HRESULT(CO_E_CANTDETERMINECLASS)//          0x800401F2L
+        CASE_HRESULT(CO_E_CLASSSTRING)//                 0x800401F3L
+        CASE_HRESULT(CO_E_IIDSTRING)//                   0x800401F4L
+        CASE_HRESULT(CO_E_APPNOTFOUND)//                 0x800401F5L
+        CASE_HRESULT(CO_E_APPSINGLEUSE)//                0x800401F6L
+        CASE_HRESULT(CO_E_ERRORINAPP)//                  0x800401F7L
+        CASE_HRESULT(CO_E_DLLNOTFOUND)//                 0x800401F8L
+        CASE_HRESULT(CO_E_ERRORINDLL)//                  0x800401F9L
+        CASE_HRESULT(CO_E_WRONGOSFORAPP)//               0x800401FAL
+        CASE_HRESULT(CO_E_OBJNOTREG)//                   0x800401FBL
+        CASE_HRESULT(CO_E_OBJISREG)//                    0x800401FCL
+        CASE_HRESULT(CO_E_OBJNOTCONNECTED)//             0x800401FDL
+        CASE_HRESULT(CO_E_APPDIDNTREG)//                 0x800401FEL
+        CASE_HRESULT(CO_E_RELEASED)//                    0x800401FFL
+
+        CASE_HRESULT(OLE_S_USEREG)//                     0x00040000L
+        CASE_HRESULT(OLE_S_STATIC)//                     0x00040001L
+        CASE_HRESULT(OLE_S_MAC_CLIPFORMAT)//             0x00040002L
+        CASE_HRESULT(DRAGDROP_S_DROP)//                  0x00040100L
+        CASE_HRESULT(DRAGDROP_S_CANCEL)//                0x00040101L
+        CASE_HRESULT(DRAGDROP_S_USEDEFAULTCURSORS)//     0x00040102L
+        CASE_HRESULT(DATA_S_SAMEFORMATETC)//             0x00040130L
+        CASE_HRESULT(VIEW_S_ALREADY_FROZEN)//            0x00040140L
+        CASE_HRESULT(CACHE_S_FORMATETC_NOTSUPPORTED)//   0x00040170L
+        CASE_HRESULT(CACHE_S_SAMECACHE)//                0x00040171L
+        CASE_HRESULT(CACHE_S_SOMECACHES_NOTUPDATED)//    0x00040172L
+        CASE_HRESULT(OLEOBJ_S_INVALIDVERB)//             0x00040180L
+        CASE_HRESULT(OLEOBJ_S_CANNOT_DOVERB_NOW)//       0x00040181L
+        CASE_HRESULT(OLEOBJ_S_INVALIDHWND)//             0x00040182L
+        CASE_HRESULT(INPLACE_S_TRUNCATED)//              0x000401A0L
+        CASE_HRESULT(CONVERT10_S_NO_PRESENTATION)//      0x000401C0L
+        CASE_HRESULT(MK_S_REDUCED_TO_SELF)//             0x000401E2L
+        CASE_HRESULT(MK_S_ME)//                          0x000401E4L
+        CASE_HRESULT(MK_S_HIM)//                         0x000401E5L
+        CASE_HRESULT(MK_S_US)//                          0x000401E6L
+        CASE_HRESULT(MK_S_MONIKERALREADYREGISTERED)//    0x000401E7L
+
+// ******************
+// FACILITY_WINDOWS
+// ******************
+
+        CASE_HRESULT(CO_E_CLASS_CREATE_FAILED)//         0x80080001L
+        CASE_HRESULT(CO_E_SCM_ERROR)//                   0x80080002L
+        CASE_HRESULT(CO_E_SCM_RPC_FAILURE)//             0x80080003L
+        CASE_HRESULT(CO_E_BAD_PATH)//                    0x80080004L
+        CASE_HRESULT(CO_E_SERVER_EXEC_FAILURE)//         0x80080005L
+        CASE_HRESULT(CO_E_OBJSRV_RPC_FAILURE)//          0x80080006L
+        CASE_HRESULT(MK_E_NO_NORMALIZED)//               0x80080007L
+        CASE_HRESULT(CO_E_SERVER_STOPPING)//             0x80080008L
+        CASE_HRESULT(MEM_E_INVALID_ROOT)//               0x80080009L
+        CASE_HRESULT(MEM_E_INVALID_LINK)//               0x80080010L
+        CASE_HRESULT(MEM_E_INVALID_SIZE)//               0x80080011L
+
+// ******************
+// FACILITY_DISPATCH
+// ******************
+
+        CASE_HRESULT(DISP_E_UNKNOWNINTERFACE)//          0x80020001L
+        CASE_HRESULT(DISP_E_MEMBERNOTFOUND)//            0x80020003L
+        CASE_HRESULT(DISP_E_PARAMNOTFOUND)//             0x80020004L
+        CASE_HRESULT(DISP_E_TYPEMISMATCH)//              0x80020005L
+        CASE_HRESULT(DISP_E_UNKNOWNNAME)//               0x80020006L
+        CASE_HRESULT(DISP_E_NONAMEDARGS)//               0x80020007L
+        CASE_HRESULT(DISP_E_BADVARTYPE)//                0x80020008L
+        CASE_HRESULT(DISP_E_EXCEPTION)//                 0x80020009L
+        CASE_HRESULT(DISP_E_OVERFLOW)//                  0x8002000AL
+        CASE_HRESULT(DISP_E_BADINDEX)//                  0x8002000BL
+        CASE_HRESULT(DISP_E_UNKNOWNLCID)//               0x8002000CL
+        CASE_HRESULT(DISP_E_ARRAYISLOCKED)//             0x8002000DL
+        CASE_HRESULT(DISP_E_BADPARAMCOUNT)//             0x8002000EL
+        CASE_HRESULT(DISP_E_PARAMNOTOPTIONAL)//          0x8002000FL
+        CASE_HRESULT(DISP_E_BADCALLEE)//                 0x80020010L
+        CASE_HRESULT(DISP_E_NOTACOLLECTION)//            0x80020011L
+        CASE_HRESULT(TYPE_E_BUFFERTOOSMALL)//            0x80028016L
+        CASE_HRESULT(TYPE_E_INVDATAREAD)//               0x80028018L
+        CASE_HRESULT(TYPE_E_UNSUPFORMAT)//               0x80028019L
+        CASE_HRESULT(TYPE_E_REGISTRYACCESS)//            0x8002801CL
+        CASE_HRESULT(TYPE_E_LIBNOTREGISTERED)//          0x8002801DL
+        CASE_HRESULT(TYPE_E_UNDEFINEDTYPE)//             0x80028027L
+        CASE_HRESULT(TYPE_E_QUALIFIEDNAMEDISALLOWED)//   0x80028028L
+        CASE_HRESULT(TYPE_E_INVALIDSTATE)//              0x80028029L
+        CASE_HRESULT(TYPE_E_WRONGTYPEKIND)//             0x8002802AL
+        CASE_HRESULT(TYPE_E_ELEMENTNOTFOUND)//           0x8002802BL
+        CASE_HRESULT(TYPE_E_AMBIGUOUSNAME)//             0x8002802CL
+        CASE_HRESULT(TYPE_E_NAMECONFLICT)//              0x8002802DL
+        CASE_HRESULT(TYPE_E_UNKNOWNLCID)//               0x8002802EL
+        CASE_HRESULT(TYPE_E_DLLFUNCTIONNOTFOUND)//       0x8002802FL
+        CASE_HRESULT(TYPE_E_BADMODULEKIND)//             0x800288BDL
+        CASE_HRESULT(TYPE_E_SIZETOOBIG)//                0x800288C5L
+        CASE_HRESULT(TYPE_E_DUPLICATEID)//               0x800288C6L
+        CASE_HRESULT(TYPE_E_INVALIDID)//                 0x800288CFL
+        CASE_HRESULT(TYPE_E_TYPEMISMATCH)//              0x80028CA0L
+        CASE_HRESULT(TYPE_E_OUTOFBOUNDS)//               0x80028CA1L
+        CASE_HRESULT(TYPE_E_IOERROR)//                   0x80028CA2L
+        CASE_HRESULT(TYPE_E_CANTCREATETMPFILE)//         0x80028CA3L
+        CASE_HRESULT(TYPE_E_CANTLOADLIBRARY)//           0x80029C4AL
+        CASE_HRESULT(TYPE_E_INCONSISTENTPROPFUNCS)//     0x80029C83L
+        CASE_HRESULT(TYPE_E_CIRCULARTYPE)//              0x80029C84L
+
+// ******************
+// FACILITY_STORAGE
+// ******************
+
+        CASE_HRESULT(STG_E_INVALIDFUNCTION)//            0x80030001L
+        CASE_HRESULT(STG_E_FILENOTFOUND)//               0x80030002L
+        CASE_HRESULT(STG_E_PATHNOTFOUND)//               0x80030003L
+        CASE_HRESULT(STG_E_TOOMANYOPENFILES)//           0x80030004L
+        CASE_HRESULT(STG_E_ACCESSDENIED)//               0x80030005L
+        CASE_HRESULT(STG_E_INVALIDHANDLE)//              0x80030006L
+        CASE_HRESULT(STG_E_INSUFFICIENTMEMORY)//         0x80030008L
+        CASE_HRESULT(STG_E_INVALIDPOINTER)//             0x80030009L
+        CASE_HRESULT(STG_E_NOMOREFILES)//                0x80030012L
+        CASE_HRESULT(STG_E_DISKISWRITEPROTECTED)//       0x80030013L
+        CASE_HRESULT(STG_E_SEEKERROR)//                  0x80030019L
+        CASE_HRESULT(STG_E_WRITEFAULT)//                 0x8003001DL
+        CASE_HRESULT(STG_E_READFAULT)//                  0x8003001EL
+        CASE_HRESULT(STG_E_SHAREVIOLATION)//             0x80030020L
+        CASE_HRESULT(STG_E_LOCKVIOLATION)//              0x80030021L
+        CASE_HRESULT(STG_E_FILEALREADYEXISTS)//          0x80030050L
+        CASE_HRESULT(STG_E_INVALIDPARAMETER)//           0x80030057L
+        CASE_HRESULT(STG_E_MEDIUMFULL)//                 0x80030070L
+        CASE_HRESULT(STG_E_ABNORMALAPIEXIT)//            0x800300FAL
+        CASE_HRESULT(STG_E_INVALIDHEADER)//              0x800300FBL
+        CASE_HRESULT(STG_E_INVALIDNAME)//                0x800300FCL
+        CASE_HRESULT(STG_E_UNKNOWN)//                    0x800300FDL
+        CASE_HRESULT(STG_E_UNIMPLEMENTEDFUNCTION)//      0x800300FEL
+        CASE_HRESULT(STG_E_INVALIDFLAG)//                0x800300FFL
+        CASE_HRESULT(STG_E_INUSE)//                      0x80030100L
+        CASE_HRESULT(STG_E_NOTCURRENT)//                 0x80030101L
+        CASE_HRESULT(STG_E_REVERTED)//                   0x80030102L
+        CASE_HRESULT(STG_E_CANTSAVE)//                   0x80030103L
+        CASE_HRESULT(STG_E_OLDFORMAT)//                  0x80030104L
+        CASE_HRESULT(STG_E_OLDDLL)//                     0x80030105L
+        CASE_HRESULT(STG_E_SHAREREQUIRED)//              0x80030106L
+        CASE_HRESULT(STG_E_NOTFILEBASEDSTORAGE)//        0x80030107L
+        CASE_HRESULT(STG_S_CONVERTED)//                  0x00030200L
+
+// ******************
+// FACILITY_RPC
+// ******************
+
+        CASE_HRESULT(RPC_E_CALL_REJECTED)//              0x80010001L
+        CASE_HRESULT(RPC_E_CALL_CANCELED)//              0x80010002L
+        CASE_HRESULT(RPC_E_CANTPOST_INSENDCALL)//        0x80010003L
+        CASE_HRESULT(RPC_E_CANTCALLOUT_INASYNCCALL)//    0x80010004L
+        CASE_HRESULT(RPC_E_CANTCALLOUT_INEXTERNALCALL)// 0x80010005L
+        CASE_HRESULT(RPC_E_CONNECTION_TERMINATED)//      0x80010006L
+        CASE_HRESULT(RPC_E_SERVER_DIED)//                0x80010007L
+        CASE_HRESULT(RPC_E_CLIENT_DIED)//                0x80010008L
+        CASE_HRESULT(RPC_E_INVALID_DATAPACKET)//         0x80010009L
+        CASE_HRESULT(RPC_E_CANTTRANSMIT_CALL)//          0x8001000AL
+        CASE_HRESULT(RPC_E_CLIENT_CANTMARSHAL_DATA)//    0x8001000BL
+        CASE_HRESULT(RPC_E_CLIENT_CANTUNMARSHAL_DATA)//  0x8001000CL
+        CASE_HRESULT(RPC_E_SERVER_CANTMARSHAL_DATA)//    0x8001000DL
+        CASE_HRESULT(RPC_E_SERVER_CANTUNMARSHAL_DATA)//  0x8001000EL
+        CASE_HRESULT(RPC_E_INVALID_DATA)//               0x8001000FL
+        CASE_HRESULT(RPC_E_INVALID_PARAMETER)//          0x80010010L
+        CASE_HRESULT(RPC_E_CANTCALLOUT_AGAIN)//          0x80010011L
+        CASE_HRESULT(RPC_E_SERVER_DIED_DNE)//            0x80010012L
+        CASE_HRESULT(RPC_E_SYS_CALL_FAILED)//            0x80010100L
+        CASE_HRESULT(RPC_E_OUT_OF_RESOURCES)//           0x80010101L
+        CASE_HRESULT(RPC_E_ATTEMPTED_MULTITHREAD)//      0x80010102L
+        CASE_HRESULT(RPC_E_NOT_REGISTERED)//             0x80010103L
+        CASE_HRESULT(RPC_E_FAULT)//                      0x80010104L
+        CASE_HRESULT(RPC_E_SERVERFAULT)//                0x80010105L
+        CASE_HRESULT(RPC_E_CHANGED_MODE)//               0x80010106L
+        CASE_HRESULT(RPC_E_INVALIDMETHOD)//              0x80010107L
+        CASE_HRESULT(RPC_E_DISCONNECTED)//               0x80010108L
+        CASE_HRESULT(RPC_E_RETRY)//                      0x80010109L
+        CASE_HRESULT(RPC_E_SERVERCALL_RETRYLATER)//      0x8001010AL
+        CASE_HRESULT(RPC_E_SERVERCALL_REJECTED)//        0x8001010BL
+        CASE_HRESULT(RPC_E_INVALID_CALLDATA)//           0x8001010CL
+        CASE_HRESULT(RPC_E_CANTCALLOUT_ININPUTSYNCCALL)// 0x8001010DL
+        CASE_HRESULT(RPC_E_WRONG_THREAD)//               0x8001010EL
+        CASE_HRESULT(RPC_E_THREAD_NOT_INIT)//            0x8001010FL
+        CASE_HRESULT(RPC_E_UNEXPECTED)//                 0x8001FFFFL
+
+// ******************
+// FACILITY_CTL
+// ******************
+
+        CASE_HRESULT(CTL_E_ILLEGALFUNCTIONCALL)
+        CASE_HRESULT(CTL_E_OVERFLOW)
+        CASE_HRESULT(CTL_E_OUTOFMEMORY)
+        CASE_HRESULT(CTL_E_DIVISIONBYZERO)
+        CASE_HRESULT(CTL_E_OUTOFSTRINGSPACE)
+        CASE_HRESULT(CTL_E_OUTOFSTACKSPACE)
+        CASE_HRESULT(CTL_E_BADFILENAMEORNUMBER)
+        CASE_HRESULT(CTL_E_FILENOTFOUND)
+        CASE_HRESULT(CTL_E_BADFILEMODE)
+        CASE_HRESULT(CTL_E_FILEALREADYOPEN)
+        CASE_HRESULT(CTL_E_DEVICEIOERROR)
+        CASE_HRESULT(CTL_E_FILEALREADYEXISTS)
+        CASE_HRESULT(CTL_E_BADRECORDLENGTH)
+        CASE_HRESULT(CTL_E_DISKFULL)
+        CASE_HRESULT(CTL_E_BADRECORDNUMBER)
+        CASE_HRESULT(CTL_E_BADFILENAME)
+        CASE_HRESULT(CTL_E_TOOMANYFILES)
+        CASE_HRESULT(CTL_E_DEVICEUNAVAILABLE)
+        CASE_HRESULT(CTL_E_PERMISSIONDENIED)
+        CASE_HRESULT(CTL_E_DISKNOTREADY)
+        CASE_HRESULT(CTL_E_PATHFILEACCESSERROR)
+        CASE_HRESULT(CTL_E_PATHNOTFOUND)
+        CASE_HRESULT(CTL_E_INVALIDPATTERNSTRING)
+        CASE_HRESULT(CTL_E_INVALIDUSEOFNULL)
+        CASE_HRESULT(CTL_E_INVALIDFILEFORMAT)
+        CASE_HRESULT(CTL_E_INVALIDPROPERTYVALUE)
+        CASE_HRESULT(CTL_E_INVALIDPROPERTYARRAYINDEX)
+        CASE_HRESULT(CTL_E_SETNOTSUPPORTEDATRUNTIME)
+        CASE_HRESULT(CTL_E_SETNOTSUPPORTED)
+        CASE_HRESULT(CTL_E_NEEDPROPERTYARRAYINDEX)
+        CASE_HRESULT(CTL_E_SETNOTPERMITTED)
+        CASE_HRESULT(CTL_E_GETNOTSUPPORTEDATRUNTIME)
+        CASE_HRESULT(CTL_E_GETNOTSUPPORTED)
+        CASE_HRESULT(CTL_E_PROPERTYNOTFOUND)
+        CASE_HRESULT(CTL_E_INVALIDCLIPBOARDFORMAT)
+        CASE_HRESULT(CTL_E_INVALIDPICTURE)
+        CASE_HRESULT(CTL_E_PRINTERERROR)
+        CASE_HRESULT(CTL_E_CANTSAVEFILETOTEMP)
+        CASE_HRESULT(CTL_E_SEARCHTEXTNOTFOUND)
+        CASE_HRESULT(CTL_E_REPLACEMENTSTOOLONG)
+#endif // FEATURE_COMINTEROP
+
+#ifdef _DEBUG  // @todo: do we want to burn strings for this in a free build?
+
+    CASE_HRESULT(CEE_E_CVTRES_NOT_FOUND)
+    CASE_HRESULT(COR_E_APPDOMAINUNLOADED)
+    CASE_HRESULT(COR_E_CANNOTUNLOADAPPDOMAIN)
+    CASE_HRESULT(MSEE_E_ASSEMBLYLOADINPROGRESS)
+    CASE_HRESULT(COR_E_FIXUPSINEXE)
+    CASE_HRESULT(COR_E_MODULE_HASH_CHECK_FAILED)
+    CASE_HRESULT(FUSION_E_LOADFROM_BLOCKED)
+    CASE_HRESULT(FUSION_E_CACHEFILE_FAILED)
+    CASE_HRESULT(FUSION_E_REF_DEF_MISMATCH)
+    CASE_HRESULT(FUSION_E_INVALID_PRIVATE_ASM_LOCATION)
+    CASE_HRESULT(FUSION_E_ASM_MODULE_MISSING)
+    CASE_HRESULT(FUSION_E_PRIVATE_ASM_DISALLOWED)
+    CASE_HRESULT(FUSION_E_SIGNATURE_CHECK_FAILED)
+    CASE_HRESULT(FUSION_E_INVALID_NAME)
+    CASE_HRESULT(FUSION_E_CODE_DOWNLOAD_DISABLED)
+    CASE_HRESULT(CLDB_E_FILE_BADREAD)
+    CASE_HRESULT(CLDB_E_FILE_BADWRITE)
+    CASE_HRESULT(CLDB_S_TRUNCATION)
+    CASE_HRESULT(CLDB_E_FILE_OLDVER)
+    CASE_HRESULT(CLDB_E_SMDUPLICATE)
+    CASE_HRESULT(CLDB_E_NO_DATA)
+    CASE_HRESULT(CLDB_E_INCOMPATIBLE)
+    CASE_HRESULT(CLDB_E_FILE_CORRUPT)
+    CASE_HRESULT(CLDB_E_BADUPDATEMODE)
+    CASE_HRESULT(CLDB_E_INDEX_NOTFOUND)
+    CASE_HRESULT(CLDB_E_RECORD_NOTFOUND)
+    CASE_HRESULT(CLDB_E_RECORD_OUTOFORDER)
+    CASE_HRESULT(CLDB_E_TOO_BIG)
+    CASE_HRESULT(META_E_BADMETADATA)
+    CASE_HRESULT(META_E_BAD_SIGNATURE)
+    CASE_HRESULT(META_E_BAD_INPUT_PARAMETER)
+    CASE_HRESULT(META_E_CANNOTRESOLVETYPEREF)
+    CASE_HRESULT(META_S_DUPLICATE)
+    CASE_HRESULT(META_E_STRINGSPACE_FULL)
+    CASE_HRESULT(META_E_HAS_UNMARKALL)
+    CASE_HRESULT(META_E_MUST_CALL_UNMARKALL)
+    CASE_HRESULT(META_E_CA_INVALID_TARGET)
+    CASE_HRESULT(META_E_CA_INVALID_VALUE)
+    CASE_HRESULT(META_E_CA_INVALID_BLOB)
+    CASE_HRESULT(META_E_CA_REPEATED_ARG)
+    CASE_HRESULT(META_E_CA_UNKNOWN_ARGUMENT)
+    CASE_HRESULT(META_E_CA_UNEXPECTED_TYPE)
+    CASE_HRESULT(META_E_CA_INVALID_ARGTYPE)
+    CASE_HRESULT(META_E_CA_INVALID_ARG_FOR_TYPE)
+    CASE_HRESULT(META_E_CA_INVALID_UUID)
+    CASE_HRESULT(META_E_CA_INVALID_MARSHALAS_FIELDS)
+    CASE_HRESULT(META_E_CA_NT_FIELDONLY)
+    CASE_HRESULT(META_E_CA_NEGATIVE_PARAMINDEX)
+    CASE_HRESULT(META_E_CA_NEGATIVE_CONSTSIZE)
+    CASE_HRESULT(META_E_CA_FIXEDSTR_SIZE_REQUIRED)
+    CASE_HRESULT(META_E_CA_CUSTMARSH_TYPE_REQUIRED)
+    CASE_HRESULT(META_E_CA_BAD_FRIENDS_ARGS)
+    CASE_HRESULT(VLDTR_E_RID_OUTOFRANGE)
+    CASE_HRESULT(VLDTR_E_STRING_INVALID)
+    CASE_HRESULT(VLDTR_E_GUID_INVALID)
+    CASE_HRESULT(VLDTR_E_BLOB_INVALID)
+    CASE_HRESULT(VLDTR_E_MR_BADCALLINGCONV)
+    CASE_HRESULT(VLDTR_E_SIGNULL)
+    CASE_HRESULT(VLDTR_E_MD_BADCALLINGCONV)
+    CASE_HRESULT(VLDTR_E_MD_THISSTATIC)
+    CASE_HRESULT(VLDTR_E_MD_NOTTHISNOTSTATIC)
+    CASE_HRESULT(VLDTR_E_MD_NOARGCNT)
+    CASE_HRESULT(VLDTR_E_SIG_MISSELTYPE)
+    CASE_HRESULT(VLDTR_E_SIG_MISSTKN)
+    CASE_HRESULT(VLDTR_E_SIG_TKNBAD)
+    CASE_HRESULT(VLDTR_E_SIG_MISSFPTR)
+    CASE_HRESULT(VLDTR_E_SIG_MISSFPTRARGCNT)
+    CASE_HRESULT(VLDTR_E_SIG_MISSRANK)
+    CASE_HRESULT(VLDTR_E_SIG_MISSNSIZE)
+    CASE_HRESULT(VLDTR_E_SIG_MISSSIZE)
+    CASE_HRESULT(VLDTR_E_SIG_MISSNLBND)
+    CASE_HRESULT(VLDTR_E_SIG_MISSLBND)
+    CASE_HRESULT(VLDTR_E_SIG_BADELTYPE)
+    CASE_HRESULT(VLDTR_E_TD_ENCLNOTNESTED)
+    CASE_HRESULT(VLDTR_E_FMD_PINVOKENOTSTATIC)
+    CASE_HRESULT(VLDTR_E_SIG_SENTINMETHODDEF)
+    CASE_HRESULT(VLDTR_E_SIG_SENTMUSTVARARG)
+    CASE_HRESULT(VLDTR_E_SIG_MULTSENTINELS)
+    CASE_HRESULT(VLDTR_E_SIG_MISSARG)
+    CASE_HRESULT(VLDTR_E_SIG_BYREFINFIELD)
+    CASE_HRESULT(VLDTR_E_SIG_BADVOID)
+    CASE_HRESULT(CORDBG_E_UNRECOVERABLE_ERROR)
+    CASE_HRESULT(CORDBG_E_PROCESS_TERMINATED)
+    CASE_HRESULT(CORDBG_E_PROCESS_NOT_SYNCHRONIZED)
+    CASE_HRESULT(CORDBG_E_CLASS_NOT_LOADED)
+    CASE_HRESULT(CORDBG_E_IL_VAR_NOT_AVAILABLE)
+    CASE_HRESULT(CORDBG_E_BAD_REFERENCE_VALUE)
+    CASE_HRESULT(CORDBG_E_FIELD_NOT_AVAILABLE)
+    CASE_HRESULT(CORDBG_E_NON_NATIVE_FRAME)
+    CASE_HRESULT(CORDBG_E_CODE_NOT_AVAILABLE)
+    CASE_HRESULT(CORDBG_E_FUNCTION_NOT_IL)
+    CASE_HRESULT(CORDBG_S_BAD_START_SEQUENCE_POINT)
+    CASE_HRESULT(CORDBG_S_BAD_END_SEQUENCE_POINT)
+    CASE_HRESULT(CORDBG_E_CANT_SET_IP_INTO_FINALLY)
+    CASE_HRESULT(CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY)
+    CASE_HRESULT(CORDBG_E_CANT_SET_IP_INTO_CATCH)
+    CASE_HRESULT(CORDBG_E_SET_IP_NOT_ALLOWED_ON_NONLEAF_FRAME)
+    CASE_HRESULT(CORDBG_E_SET_IP_IMPOSSIBLE)
+    CASE_HRESULT(CORDBG_E_FUNC_EVAL_BAD_START_POINT)
+    CASE_HRESULT(CORDBG_E_INVALID_OBJECT)
+    CASE_HRESULT(CORDBG_E_FUNC_EVAL_NOT_COMPLETE)
+    CASE_HRESULT(CORDBG_S_FUNC_EVAL_HAS_NO_RESULT)
+    CASE_HRESULT(CORDBG_S_VALUE_POINTS_TO_VOID)
+    CASE_HRESULT(CORDBG_S_FUNC_EVAL_ABORTED)
+    CASE_HRESULT(CORDBG_E_STATIC_VAR_NOT_AVAILABLE)
+    CASE_HRESULT(CORDBG_E_CANT_SETIP_INTO_OR_OUT_OF_FILTER)
+    CASE_HRESULT(CORDBG_E_CANT_CHANGE_JIT_SETTING_FOR_ZAP_MODULE)
+    CASE_HRESULT(CORDBG_E_CANT_SET_TO_JMC)
+    CASE_HRESULT(CORDBG_E_BAD_THREAD_STATE)
+    CASE_HRESULT(CORDBG_E_DEBUGGER_ALREADY_ATTACHED)
+    CASE_HRESULT(CORDBG_E_SUPERFLOUS_CONTINUE)
+    CASE_HRESULT(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME)
+    CASE_HRESULT(CORDBG_E_ENC_MODULE_NOT_ENC_ENABLED)
+    CASE_HRESULT(CORDBG_E_SET_IP_NOT_ALLOWED_ON_EXCEPTION)
+    CASE_HRESULT(CORDBG_E_VARIABLE_IS_ACTUALLY_LITERAL)
+    CASE_HRESULT(CORDBG_E_PROCESS_DETACHED)
+    CASE_HRESULT(CORDBG_E_ENC_CANT_ADD_FIELD_TO_VALUE_OR_LAYOUT_CLASS)
+    CASE_HRESULT(CORDBG_E_FIELD_NOT_STATIC)
+    CASE_HRESULT(CORDBG_E_FIELD_NOT_INSTANCE)
+    CASE_HRESULT(CORDBG_E_ENC_JIT_CANT_UPDATE)
+    CASE_HRESULT(CORDBG_E_ENC_INTERNAL_ERROR)
+    CASE_HRESULT(CORDBG_E_ENC_HANGING_FIELD)
+    CASE_HRESULT(CORDBG_E_MODULE_NOT_LOADED)
+    CASE_HRESULT(CORDBG_E_UNABLE_TO_SET_BREAKPOINT)
+    CASE_HRESULT(CORDBG_E_DEBUGGING_NOT_POSSIBLE)
+    CASE_HRESULT(CORDBG_E_KERNEL_DEBUGGER_ENABLED)
+    CASE_HRESULT(CORDBG_E_KERNEL_DEBUGGER_PRESENT)
+    CASE_HRESULT(CORDBG_E_INCOMPATIBLE_PROTOCOL)
+    CASE_HRESULT(CORDBG_E_TOO_MANY_PROCESSES)
+    CASE_HRESULT(CORDBG_E_INTEROP_NOT_SUPPORTED)
+    CASE_HRESULT(CORDBG_E_NO_REMAP_BREAKPIONT)
+    CASE_HRESULT(CORDBG_E_OBJECT_NEUTERED)
+    CASE_HRESULT(CORPROF_E_FUNCTION_NOT_COMPILED)
+    CASE_HRESULT(CORPROF_E_DATAINCOMPLETE)
+    CASE_HRESULT(CORPROF_E_FUNCTION_NOT_IL)
+    CASE_HRESULT(CORPROF_E_NOT_MANAGED_THREAD)
+    CASE_HRESULT(CORPROF_E_CALL_ONLY_FROM_INIT)
+    CASE_HRESULT(CORPROF_E_NOT_YET_AVAILABLE)
+    CASE_HRESULT(SECURITY_E_INCOMPATIBLE_SHARE)
+    CASE_HRESULT(SECURITY_E_UNVERIFIABLE)
+    CASE_HRESULT(SECURITY_E_INCOMPATIBLE_EVIDENCE)
+    CASE_HRESULT(CLDB_E_INTERNALERROR)
+    CASE_HRESULT(CORSEC_E_POLICY_EXCEPTION)
+    CASE_HRESULT(CORSEC_E_MIN_GRANT_FAIL)
+    CASE_HRESULT(CORSEC_E_NO_EXEC_PERM)
+    CASE_HRESULT(CORSEC_E_XMLSYNTAX)
+    CASE_HRESULT(CORSEC_E_INVALID_STRONGNAME)
+    CASE_HRESULT(CORSEC_E_MISSING_STRONGNAME)
+    CASE_HRESULT(CORSEC_E_INVALID_IMAGE_FORMAT)
+    CASE_HRESULT(CORSEC_E_CRYPTO)
+    CASE_HRESULT(CORSEC_E_CRYPTO_UNEX_OPER)
+    CASE_HRESULT(CORSECATTR_E_BAD_ACTION)
+    CASE_HRESULT(COR_E_APPLICATION)
+    CASE_HRESULT(COR_E_ARGUMENTOUTOFRANGE)
+    CASE_HRESULT(COR_E_ARITHMETIC)
+    CASE_HRESULT(COR_E_ARRAYTYPEMISMATCH)
+    CASE_HRESULT(COR_E_CONTEXTMARSHAL)
+    CASE_HRESULT(COR_E_TIMEOUT)
+    CASE_HRESULT(COR_E_DIVIDEBYZERO)
+    CASE_HRESULT(COR_E_EXCEPTION)
+    CASE_HRESULT(COR_E_EXECUTIONENGINE)
+    CASE_HRESULT(COR_E_FIELDACCESS)
+    CASE_HRESULT(COR_E_FORMAT)
+    CASE_HRESULT(COR_E_BADIMAGEFORMAT)
+    CASE_HRESULT(COR_E_ASSEMBLYEXPECTED)
+    CASE_HRESULT(COR_E_TYPEUNLOADED)
+    CASE_HRESULT(COR_E_INDEXOUTOFRANGE)
+    CASE_HRESULT(COR_E_INVALIDOPERATION)
+    CASE_HRESULT(COR_E_INVALIDPROGRAM)
+    CASE_HRESULT(COR_E_MEMBERACCESS)
+    CASE_HRESULT(COR_E_METHODACCESS)
+    CASE_HRESULT(COR_E_MISSINGFIELD)
+    CASE_HRESULT(COR_E_MISSINGMANIFESTRESOURCE)
+    CASE_HRESULT(COR_E_MISSINGMEMBER)
+    CASE_HRESULT(COR_E_MISSINGMETHOD)
+    CASE_HRESULT(COR_E_MULTICASTNOTSUPPORTED)
+    CASE_HRESULT(COR_E_NOTFINITENUMBER)
+    CASE_HRESULT(COR_E_DUPLICATEWAITOBJECT)
+    CASE_HRESULT(COR_E_PLATFORMNOTSUPPORTED)
+    CASE_HRESULT(COR_E_NOTSUPPORTED)
+    CASE_HRESULT(COR_E_OVERFLOW)
+    CASE_HRESULT(COR_E_RANK)
+    CASE_HRESULT(COR_E_SECURITY)
+    CASE_HRESULT(COR_E_SERIALIZATION)
+    CASE_HRESULT(COR_E_STACKOVERFLOW)
+    CASE_HRESULT(COR_E_SYNCHRONIZATIONLOCK)
+    CASE_HRESULT(COR_E_SYSTEM)
+    CASE_HRESULT(COR_E_THREADABORTED)
+    CASE_HRESULT(COR_E_THREADINTERRUPTED)
+    CASE_HRESULT(COR_E_THREADSTATE)
+    CASE_HRESULT(COR_E_THREADSTOP)
+    CASE_HRESULT(COR_E_TYPEINITIALIZATION)
+    CASE_HRESULT(COR_E_TYPELOAD)
+    CASE_HRESULT(COR_E_ENTRYPOINTNOTFOUND)
+    CASE_HRESULT(COR_E_DLLNOTFOUND)
+    CASE_HRESULT(COR_E_VERIFICATION)
+    CASE_HRESULT(COR_E_INVALIDCOMOBJECT)
+    CASE_HRESULT(COR_E_MARSHALDIRECTIVE)
+    CASE_HRESULT(COR_E_INVALIDOLEVARIANTTYPE)
+    CASE_HRESULT(COR_E_SAFEARRAYTYPEMISMATCH)
+    CASE_HRESULT(COR_E_SAFEARRAYRANKMISMATCH)
+    CASE_HRESULT(COR_E_INVALIDFILTERCRITERIA)
+    CASE_HRESULT(COR_E_REFLECTIONTYPELOAD)
+    CASE_HRESULT(COR_E_TARGET)
+    CASE_HRESULT(COR_E_TARGETINVOCATION)
+    CASE_HRESULT(COR_E_CUSTOMATTRIBUTEFORMAT)
+    CASE_HRESULT(COR_E_ENDOFSTREAM)
+    CASE_HRESULT(COR_E_FILELOAD)
+    CASE_HRESULT(COR_E_FILENOTFOUND)
+    CASE_HRESULT(COR_E_IO)
+    CASE_HRESULT(COR_E_DIRECTORYNOTFOUND)
+    CASE_HRESULT(COR_E_PATHTOOLONG)
+    CASE_HRESULT(COR_E_OBJECTDISPOSED)
+    CASE_HRESULT(COR_E_NEWER_RUNTIME)
+    CASE_HRESULT(CLR_E_SHIM_RUNTIMELOAD)
+    CASE_HRESULT(VER_E_FIELD_SIG)
+    CASE_HRESULT(CORDBG_E_THREAD_NOT_SCHEDULED)
+#endif
+
+        default:
+            return NULL;
+    }
+}
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+
+// ---------------------------------------------------------------------------
+// HRException class.  Implements exception API for exceptions from HRESULTS
+// ---------------------------------------------------------------------------
+
+HRESULT HRException::GetHR()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+    return m_hr;
+}
+
+// ---------------------------------------------------------------------------
+// COMException class. - moved to COMEx.cpp
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// SEHException class.  Implements exception API for SEH exception info
+// ---------------------------------------------------------------------------
+
+HRESULT SEHException::GetHR()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    if (IsComPlusException(&m_exception)) // EE exception
+        return (HRESULT) m_exception.ExceptionInformation[0];
+    else
+        return m_exception.ExceptionCode;
+}
+
+IErrorInfo *SEHException::GetErrorInfo()
+{
+    LIMITED_METHOD_CONTRACT;
+    return NULL;
+}
+
+void SEHException::GetMessage(SString &string)
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (IsComPlusException(&m_exception)) // EE exception
+    {
+        GenerateTopLevelHRExceptionMessage(GetHR(), string);
+    }
+    else
+    {
+        if (m_exception.ExceptionCode != 0)
+        {
+            string.Printf("Exception code 0x%.8x", m_exception.ExceptionCode);
+        }
+        else
+        {
+            // If we don't have a valid exception code, then give a generic message that's a little nicer than
+            // "code 0x00000000".
+            string.Printf("Unknown exception");
+        }
+    }
+}
+
+//==============================================================================
+// DelegatingException class.  Implements exception API for "foreign" exceptions.
+//==============================================================================
+
+DelegatingException::DelegatingException()
+ : m_delegatedException((Exception*)DELEGATE_NOT_YET_SET)
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+} // DelegatingException::DelegatingException()
+
+//------------------------------------------------------------------------------
+DelegatingException::~DelegatingException()
+{
+    WRAPPER_NO_CONTRACT;
+
+    // If there is a valid delegate pointer (inited and non-NULL), delete it.
+    if (IsDelegateValid())
+        Delete(m_delegatedException);
+
+    // Avoid confusion.
+    m_delegatedException = NULL;
+} // DelegatingException::~DelegatingException()
+
+//------------------------------------------------------------------------------
+// Retrieve the delegating exception, or get one from the Thread, or get NULL.
+Exception* DelegatingException::GetDelegate()
+{
+    WRAPPER_NO_CONTRACT;
+
+    // If we haven't gotten the exception pointer before..
+    if (!IsDelegateSet())
+    {
+        // .. get it now.  NULL in case there isn't one and we take default action.
+        m_delegatedException = NULL;
+        GetLastThrownObjectExceptionFromThread(&m_delegatedException);
+    }
+
+    return m_delegatedException;
+} // Exception* DelegatingException::GetDelegate()
+
+//------------------------------------------------------------------------------
+// Virtual overrides
+HRESULT DelegatingException::GetHR()
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    // Retrieve any delegating exception.
+    Exception *pDelegate = GetDelegate();
+
+    // If there is a delegate exception, defer to it.  Otherwise,
+    //  default to E_FAIL.
+    return pDelegate ? pDelegate->GetHR() : E_FAIL;
+
+} // HRESULT DelegatingException::GetHR()
+
+//------------------------------------------------------------------------------
+IErrorInfo *DelegatingException::GetErrorInfo()
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Retrieve any delegating exception.
+    Exception *pDelegate = GetDelegate();
+
+    // If there is a delegate exception, defer to it.  Otherwise,
+    //  default to NULL.
+    return pDelegate ? pDelegate->GetErrorInfo() : NULL;
+
+} // IErrorInfo *DelegatingException::GetErrorInfo()
+
+//------------------------------------------------------------------------------
+void DelegatingException::GetMessage(SString &result)
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Retrieve any delegating exception.
+    Exception *pDelegate = GetDelegate();
+
+    // If there is a delegate exception, defer to it.  Otherwise,
+    //  default to a generic message.
+    if (pDelegate)
+    {
+        pDelegate->GetMessage(result);
+    }
+    else
+    {
+        // If we don't have a valid exception code, then give a generic message
+        //  that's a little nicer than "code 0x00000000".
+        result.Printf("Unknown exception");
+    }
+} // void DelegatingException::GetMessage()
+
+//------------------------------------------------------------------------------
+Exception *DelegatingException::Clone()
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Clone the base exception, this will also take care of cloning the inner
+    // exception if there is one.
+    NewHolder<DelegatingException> retExcep((DelegatingException*)Exception::Clone());
+
+    // If there is a valid delegating exception...
+    if (IsDelegateValid())
+    {   // ... clone it.
+        retExcep->m_delegatedException = m_delegatedException->Clone();
+    }
+    else
+    {   // ... but if there is not, just copy -- either NULL or DELEGATE_NOT_YET_SET
+        retExcep->m_delegatedException = m_delegatedException;
+    }
+
+    retExcep.SuppressRelease();
+    return retExcep;
+} // virtual Exception *DelegatingException::Clone()
+
+//==============================================================================
+//==============================================================================
+
+void DECLSPEC_NORETURN ThrowHR(HRESULT hr)
+{
+    WRAPPER_NO_CONTRACT;
+
+    STRESS_LOG1(LF_EH, LL_INFO100, "ThrowHR: HR = %x\n", hr);
+
+    if (hr == E_OUTOFMEMORY)
+        ThrowOutOfMemory();
+
+    // Catchers assume only failing hresults
+    _ASSERTE(FAILED(hr));
+    if (hr == S_OK)
+        hr = E_FAIL;
+
+    EX_THROW(HRException, (hr));
+}
+
+void DECLSPEC_NORETURN ThrowHR(HRESULT hr, SString const &msg)
+{
+    WRAPPER_NO_CONTRACT;
+
+    STRESS_LOG1(LF_EH, LL_INFO100, "ThrowHR: HR = %x\n", hr);
+
+    if (hr == E_OUTOFMEMORY)
+        ThrowOutOfMemory();
+
+    // Catchers assume only failing hresults
+    _ASSERTE(FAILED(hr));
+    if (hr == S_OK)
+        hr = E_FAIL;
+
+    EX_THROW(HRMsgException, (hr, msg));
+}
+
+void DECLSPEC_NORETURN ThrowWin32(DWORD err)
+{
+    WRAPPER_NO_CONTRACT;
+    if (err == ERROR_NOT_ENOUGH_MEMORY)
+    {
+        ThrowOutOfMemory();
+    }
+    else
+    {
+        ThrowHR(HRESULT_FROM_WIN32(err));
+    }
+}
+
+void DECLSPEC_NORETURN ThrowLastError()
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC;
+
+    ThrowWin32(GetLastError());
+}
+
+void DECLSPEC_NORETURN ThrowOutOfMemory()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+#ifndef DACCESS_COMPILE
+
+    // Use volatile store to prevent compiler from optimizing the static variable away
+    VolatileStoreWithoutBarrier<HRESULT>(&g_hrFatalError, COR_E_OUTOFMEMORY);
+
+    // Regular CLR builds - throw our pre-created OOM exception object
+    PAL_CPP_THROW(Exception *, Exception::GetOOMException());
+
+#else
+
+    // DAC builds - raise a DacError
+    DacError(E_OUTOFMEMORY);
+
+    // DacError always throws but isn't marked DECLSPEC_NORETURN so we have to
+    // tell the compiler that this code is unreachable. We could mark DacError
+    // (and DacNotImpl) as DECLSPEC_NORETURN, but then we've have to update a
+    // lot of code where we do something afterwards. Also, due to inlining,
+    // we'd sometimes have to change functions which call functions that only
+    // call DacNotImpl. I have these changes in a bbpack and some of them look
+    // nice, but I'm not sure if it's worth the risk of merge conflicts.
+    UNREACHABLE();
+
+#endif
+}
+
+#include "corexcep.h"
+
+//--------------------------------------------------------------------------------
+// Helper for EX_THROW_WITH_INNER()
+//
+// Clones an exception into the current domain. Also handles special cases for
+// OOM and other stuff. Making this a function so we don't inline all this logic
+// every place we call EX_THROW_WITH_INNER.
+//
+// If the "inner" is a transient exception such as OOM or ThreadAbort, this function
+// will just throw it rather than allow it to be wrapped in another exception.
+//--------------------------------------------------------------------------------
+Exception *ExThrowWithInnerHelper(Exception *inner)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END
+
+    // Yes, NULL is a legal case. Makes it easier to author uniform helpers for
+    // both wrapped and normal exceptions.
+    if (inner == NULL)
+    {
+        return NULL;
+    }
+
+    if (inner == Exception::GetOOMException())
+    {
+        // We don't want to do allocations if we're already throwing an OOM!
+        PAL_CPP_THROW(Exception*, inner);
+    }
+
+    inner = inner->DomainBoundClone();
+
+    // It isn't useful to wrap OOMs and StackOverflows in other exceptions. Just throw them now.
+    //
+    if (inner->IsTransient())
+    {
+        PAL_CPP_THROW(Exception*, inner);
+    }
+    return inner;
+}
+
+#ifdef _DEBUG
+
+#ifdef _MSC_VER
+#pragma optimize("", off)
+#endif // _MSC_VER
+
+void ExThrowTrap(const char *fcn, const char *file, int line, const char *szType, HRESULT hr, const char *args)
+{
+    SUPPORTS_DAC;
+    return;
+}
+
+#ifdef _MSC_VER
+#pragma optimize("", on)
+#endif // _MSC_VER
+
+#endif
+
+
+
+
+//-------------------------------------------------------------------------------------------
+// This routine will generate the most descriptive possible error message for an hresult.
+// It will generate at minimum the hex value. It will also try to generate the symbolic name
+// (E_POINTER) and the friendly description (from the message tables.)
+//
+// bNoGeekStuff suppresses hex HR codes. Use this sparingly as most error strings generated by the
+// CLR are aimed at developers, not end-users.
+//-------------------------------------------------------------------------------------------
+void GetHRMsg(HRESULT hr, SString &result, BOOL bNoGeekStuff/* = FALSE*/)
+{
+    CONTRACTL
+    {
+        GC_NOTRIGGER;
+        THROWS;
+    }
+    CONTRACTL_END;
+
+    result = W("");     // Make sure this routine isn't an inadvertent data-leak exploit!
+
+
+
+    SString strDescr;
+    BOOL    fHaveDescr = FALSE;
+
+    if (FAILED(hr) && HRESULT_FACILITY(hr) == FACILITY_URT && HRESULT_CODE(hr) < MAX_URT_HRESULT_CODE)
+    {
+        fHaveDescr = strDescr.LoadResource(CCompRC::Error, MSG_FOR_URT_HR(hr));
+    }
+    else
+    {
+        DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;
+        dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
+
+        fHaveDescr = strDescr.FormatMessage(dwFlags, 0, hr, 0);
+    }
+
+    LPCSTR name = Exception::GetHRSymbolicName(hr);
+
+    // If we can't get a resource string, print the hresult regardless.
+    if (!fHaveDescr)
+    {
+        bNoGeekStuff = FALSE;
+    }
+
+    if (fHaveDescr)
+    {
+        result.Append(strDescr);
+    }
+
+    if (!bNoGeekStuff)
+    {
+        if (fHaveDescr)
+        {
+            result.Append(W(" ("));
+        }
+
+        result.AppendPrintf(W("0x%.8X"), hr);
+        if (name != NULL)
+        {
+            result.AppendPrintf(W(" (%S)"), name);
+        }
+
+        if (fHaveDescr)
+        {
+            result.Append(W(")"));
+        }
+    }
+}
+
+
+//-------------------------------------------------------------------------------------------
+// Similar to GetHRMsg but phrased for top-level exception message.
+//-------------------------------------------------------------------------------------------
+void GenerateTopLevelHRExceptionMessage(HRESULT hresult, SString &result)
+{
+    CONTRACTL
+    {
+        GC_NOTRIGGER;
+        THROWS;
+    }
+    CONTRACTL_END;
+
+    result = W("");     // Make sure this routine isn't an inadvertent data-leak exploit!
+
+    GetHRMsg(hresult, result);
+}
+
+//===========================================================================================
+// These abstractions hide the difference between legacy desktop CLR's (that don't support
+// side-by-side-inproc and rely on a fixed SEH code to identify managed exceptions) and
+// new CLR's that support side-by-side inproc.
+//
+// The new CLR's use a different set of SEH codes to avoid conflicting with the legacy CLR's.
+// In addition, to distinguish between EH's raised by different inproc instances of the CLR,
+// the module handle of the owning CLR is stored in ExceptionRecord.ExceptionInformation[4].
+//
+// (Note: all existing SEH's use either only slot [0] or no slots at all. We are leaving
+//  slots [1] thru [3] open for future expansion.)
+//===========================================================================================
+
+// Is this exception code one of the special CLR-specific SEH codes that participate in the
+// instance-tagging scheme?
+BOOL IsInstanceTaggedSEHCode(DWORD dwExceptionCode)
+{
+   LIMITED_METHOD_DAC_CONTRACT;
+
+    return dwExceptionCode == EXCEPTION_COMPLUS;
+}
+
+// This set of overloads generates the NumberParameters and ExceptionInformation[] array to
+// pass to RaiseException().
+//
+// Parameters:
+//    exceptionArgs:   a fixed-size array of size INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE.
+//                     This will get filled in by this function. (The module handle goes
+//                     in the last slot if this is a side-by-side-inproc enabled build.)
+//
+//    exceptionArg1... up to four arguments that go in slots [0]..[3]. These depends
+//                     the specific requirements of your exception code.
+//
+// Returns:
+//    The NumberParameters to pass to RaiseException().
+//
+//    Basically, this is  either INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE or the count of your
+//    fixed arguments depending on whether this tagged-SEH-enabled build.
+//
+// This function is not permitted to fail.
+
+// (the existing system can support more overloads up to 4 fixed arguments but we don't need them at this time.)
+
+static DWORD MarkAsThrownByUsWorker(UINT numArgs, /*out*/ ULONG_PTR exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE], ULONG_PTR arg0 = 0)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+
+    _ASSERTE(numArgs < INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE);
+    FillMemory(exceptionArgs, sizeof(ULONG_PTR) * INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE, 0);
+
+    exceptionArgs[0] = arg0;
+
+#if !defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
+    exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE - 1] = (ULONG_PTR)GetClrModuleBase();
+#endif // !defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
+
+    return INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE;
+}
+
+DWORD MarkAsThrownByUs(/*out*/ ULONG_PTR exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE])
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    return MarkAsThrownByUsWorker(0, exceptionArgs);
+}
+
+DWORD MarkAsThrownByUs(/*out*/ ULONG_PTR exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE], ULONG_PTR arg0)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    return MarkAsThrownByUsWorker(1, exceptionArgs, arg0);
+}
+
+// Given an exception record, checks if it's exception code matches a specific exception code
+// *and* whether it was tagged by the calling instance of the CLR.
+//
+// If this is a non-tagged-SEH-enabled build, it is blindly assumed to be tagged by the
+// calling instance of the CLR.
+BOOL WasThrownByUs(const EXCEPTION_RECORD *pcER, DWORD dwExceptionCode)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+
+    _ASSERTE(IsInstanceTaggedSEHCode(dwExceptionCode));
+    _ASSERTE(pcER != NULL);
+    if (dwExceptionCode != pcER->ExceptionCode)
+    {
+        return FALSE;
+    }
+
+    if (pcER->NumberParameters != INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE)
+    {
+        return FALSE;
+    }
+#if!defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
+    if ((ULONG_PTR)GetClrModuleBase() != pcER->ExceptionInformation[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE - 1] )
+    {
+        return FALSE;
+    }
+    return TRUE;
+#else // !(!defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
+    return FALSE;
+#endif // !defined(FEATURE_UTILCODE_NO_DEPENDENCIES)
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// The following group wraps the basic abstracts specifically for EXCEPTION_COMPLUS.
+//-----------------------------------------------------------------------------------
+BOOL IsComPlusException(const EXCEPTION_RECORD *pcER)
+{
+    STATIC_CONTRACT_WRAPPER;
+
+    return WasThrownByUs(pcER, EXCEPTION_COMPLUS);
+}
+
+//===========================================================================================
+//===========================================================================================
diff --git a/src/utilcode/fstring.cpp b/src/utilcode/fstring.cpp
new file mode 100644 (file)
index 0000000..9bcd12d
--- /dev/null
@@ -0,0 +1,321 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// FString.cpp
+//
+
+// ---------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "ex.h"
+#include "holder.h"
+
+#include "fstring.h"
+
+
+namespace FString
+{
+
+#ifdef _MSC_VER
+#pragma optimize("t", on)
+#endif // _MSC_VER
+
+#define MAX_LENGTH 0x1fffff00
+
+
+HRESULT Unicode_Utf8_Length(_In_z_ LPCWSTR pString, _Out_ bool * pAllAscii, _Out_ DWORD * pLength)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    * pAllAscii = true;
+
+    LPCWSTR p = pString;
+
+    while (true)
+    {
+        WCHAR ch = * p;
+
+        // Single check for termination and non ASCII
+        if (((unsigned) (ch - 1)) >= 0x7F)
+        {
+            if (ch != 0)
+            {
+                * pAllAscii = false;
+            }
+
+            break;
+        }
+
+        p ++;
+    }
+
+    if (* pAllAscii)
+    {
+        if ((p - pString) > MAX_LENGTH)
+        {
+            return COR_E_OVERFLOW;
+        }
+
+        * pLength = (DWORD) (p - pString);
+    }
+    else // use WideCharToMultiByte to calculate result length
+    {
+        * pLength = WszWideCharToMultiByte(CP_UTF8, 0, pString, -1, NULL, 0, NULL, NULL);
+
+        if (*pLength == 0)
+        {
+            return HRESULT_FROM_GetLastError();
+        }
+
+        // Remove the count of null terminator, to be consistent with the all-ASCII case.
+        --*pLength;
+
+        if (*pLength > MAX_LENGTH)
+        {
+            return COR_E_OVERFLOW;
+        }
+    }
+
+    return S_OK;
+}
+
+
+// UNICODE to UTF8
+HRESULT Unicode_Utf8(_In_z_ LPCWSTR pString, bool allAscii, _Out_writes_bytes_(length) LPSTR pBuffer, DWORD length)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    pBuffer[length] = 0;
+
+    if (allAscii)
+    {
+        LPCWSTR p = pString;
+
+        LPSTR q = pBuffer;
+
+        LPCWSTR endP = p + length - 8;
+
+        // Unfold to optimize for long string: 8 chars per iteration
+        while (p < endP)
+        {
+            q[0] = (char) p[0];
+            q[1] = (char) p[1];
+            q[2] = (char) p[2];
+            q[3] = (char) p[3];
+
+            q[4] = (char) p[4];
+            q[5] = (char) p[5];
+            q[6] = (char) p[6];
+            q[7] = (char) p[7];
+
+            q += 8;
+            p += 8;
+        }
+
+        endP += 8;
+
+        while (p < endP)
+        {
+            * q ++ = (char) * p ++;
+        }
+    }
+    else
+    {
+        length = WszWideCharToMultiByte(CP_UTF8, 0, pString, -1, pBuffer, (int) length + 1, NULL, NULL);
+
+        if (length == 0)
+        {
+            return HRESULT_FROM_GetLastError();
+        }
+    }
+
+    return S_OK;
+}
+
+
+HRESULT Utf8_Unicode_Length(_In_z_ LPCSTR pString, _Out_ bool * pAllAscii, _Out_ DWORD * pLength)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    * pAllAscii = true;
+
+    LPCSTR p = pString;
+
+    while (true)
+    {
+        char ch = * p;
+
+        // Single check for termination and non ASCII
+        if (((unsigned) (ch - 1)) >= 0x7F)
+        {
+            if (ch != 0)
+            {
+                * pAllAscii = false;
+            }
+
+            break;
+        }
+
+        p ++;
+    }
+
+    if (* pAllAscii)
+    {
+        if ((p - pString) > MAX_LENGTH)
+        {
+            return COR_E_OVERFLOW;
+        }
+
+        * pLength = (DWORD)(p - pString);
+    }
+    else
+    {
+        * pLength = WszMultiByteToWideChar(CP_UTF8, 0, pString, -1, NULL, 0);
+
+        if (* pLength == 0)
+        {
+            return HRESULT_FROM_GetLastError();
+        }
+
+        // Remove the count of null terminator, to be consistent with the all-ASCII case.
+        --*pLength;
+
+        if (* pLength > MAX_LENGTH)
+        {
+            return COR_E_OVERFLOW;
+        }
+    }
+
+    return S_OK;
+}
+
+
+// UTF8 to Unicode
+
+HRESULT Utf8_Unicode(_In_z_ LPCSTR pString, bool allAscii, _Out_writes_bytes_(length) LPWSTR pBuffer, DWORD length)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    pBuffer[length] = 0;
+
+    if (allAscii)
+    {
+        LPCSTR p = pString;
+
+        LPWSTR q = pBuffer;
+
+        LPCSTR endP = p + length - 8;
+
+        // Unfold to optimize for long string: 4 chars per iteration
+        while (p < endP)
+        {
+            q[0] = (WCHAR) p[0];
+            q[1] = (WCHAR) p[1];
+            q[2] = (WCHAR) p[2];
+            q[3] = (WCHAR) p[3];
+
+            q[4] = (WCHAR) p[4];
+            q[5] = (WCHAR) p[5];
+            q[6] = (WCHAR) p[6];
+            q[7] = (WCHAR) p[7];
+
+            q += 8;
+            p += 8;
+        }
+
+        endP += 8;
+
+        while (p < endP)
+        {
+            * q ++ = (WCHAR) * p ++;
+        }
+    }
+    else
+    {
+        length = WszMultiByteToWideChar(CP_UTF8, 0, pString, -1, pBuffer, (int) length + 1);
+
+        if (length == 0)
+        {
+            return HRESULT_FROM_GetLastError();
+        }
+    }
+
+    return S_OK;
+}
+
+
+HRESULT ConvertUnicode_Utf8(_In_z_ LPCWSTR pString, _Outptr_result_z_ LPSTR * pBuffer)
+{
+    bool  allAscii;
+    DWORD length;
+
+    HRESULT hr = Unicode_Utf8_Length(pString, & allAscii, & length);
+
+    if (SUCCEEDED(hr))
+    {
+        * pBuffer = new (nothrow) char[length + 1];
+
+        if (* pBuffer == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+        }
+        else
+        {
+            hr = Unicode_Utf8(pString, allAscii, * pBuffer, length);
+        }
+    }
+
+    return hr;
+}
+
+
+HRESULT ConvertUtf8_Unicode(_In_z_ LPCSTR pString, _Outptr_result_z_ LPWSTR * pBuffer)
+{
+    bool  allAscii;
+    DWORD length;
+
+    HRESULT hr = Utf8_Unicode_Length(pString, & allAscii, & length);
+
+    if (SUCCEEDED(hr))
+    {
+        * pBuffer = new (nothrow) WCHAR[length + 1];
+
+        if (* pBuffer == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+        }
+        else
+        {
+            hr = Utf8_Unicode(pString, allAscii, * pBuffer, length);
+        }
+    }
+
+    return hr;
+}
+
+
+#ifdef _MSC_VER
+#pragma optimize("", on)
+#endif // _MSC_VER
+
+} // namespace FString
diff --git a/src/utilcode/hostimpl.cpp b/src/utilcode/hostimpl.cpp
new file mode 100644 (file)
index 0000000..bd5c25a
--- /dev/null
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "stdafx.h"
+
+#include "mscoree.h"
+#include "clrinternal.h"
+#include "clrhost.h"
+#include "ex.h"
+
+thread_local size_t t_ThreadType;
+
+CRITSEC_COOKIE ClrCreateCriticalSection(CrstType crstType, CrstFlags flags)
+{
+    CRITICAL_SECTION *cs = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
+    InitializeCriticalSection(cs);
+    return (CRITSEC_COOKIE)cs;
+}
+
+void ClrDeleteCriticalSection(CRITSEC_COOKIE cookie)
+{
+    _ASSERTE(cookie);
+    DeleteCriticalSection((CRITICAL_SECTION*)cookie);
+    free(cookie);
+}
+
+void ClrEnterCriticalSection(CRITSEC_COOKIE cookie)
+{
+    _ASSERTE(cookie);
+    EnterCriticalSection((CRITICAL_SECTION*)cookie);
+}
+
+void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie)
+{
+    _ASSERTE(cookie);
+    LeaveCriticalSection((CRITICAL_SECTION*)cookie);
+}
+
+LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
+{
+#ifdef FAILPOINTS_ENABLED
+    if (RFS_HashStack ())
+        return NULL;
+#endif
+    return VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
+}
+
+BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
+{
+    return VirtualFree(lpAddress, dwSize, dwFreeType);
+}
+
+SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength)
+{
+    return VirtualQuery(lpAddress, lpBuffer, dwLength);
+}
+
+BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
+{
+    return VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
+}
+
+//------------------------------------------------------------------------------
+// Helper function to get an exception from outside the exception.  In
+//  the CLR, it may be from the Thread object.  Non-CLR users have no thread object,
+//  and it will do nothing.
+
+void GetLastThrownObjectExceptionFromThread(Exception** ppException)
+{
+    *ppException = NULL;
+}
+
+#ifdef HOST_WINDOWS
+void CreateCrashDumpIfEnabled(bool stackoverflow)
+{
+}
+#endif
diff --git a/src/utilcode/longfilepathwrappers.cpp b/src/utilcode/longfilepathwrappers.cpp
new file mode 100644 (file)
index 0000000..d1372fa
--- /dev/null
@@ -0,0 +1,942 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "stdafx.h"
+#include "windows.h"
+#include "longfilepathwrappers.h"
+#include "sstring.h"
+#include "ex.h"
+
+class LongFile
+{
+private:
+#ifdef HOST_WINDOWS
+        static const WCHAR* ExtendedPrefix;
+        static const WCHAR* DevicePathPrefix;
+        static const WCHAR* UNCPathPrefix;
+        static const WCHAR* UNCExtendedPathPrefix;
+        static const WCHAR VolumeSeparatorChar;
+               #define UNCPATHPREFIX W("\\\\")
+#endif //HOST_WINDOWS
+        static const WCHAR DirectorySeparatorChar;
+        static const WCHAR AltDirectorySeparatorChar;
+public:
+        static BOOL ContainsDirectorySeparator(SString & path);
+        static BOOL IsDirectorySeparator(WCHAR c);
+        static BOOL IsPathNotFullyQualified(const SString & path);
+
+        static HRESULT NormalizePath(SString& path);
+
+#ifdef HOST_WINDOWS
+        static BOOL IsExtended(const SString & path);
+        static BOOL IsUNCExtended(const SString & path);
+        static BOOL IsDevice(const SString & path);
+        static void NormalizeDirectorySeparators(SString& path);
+#endif
+};
+
+HMODULE
+LoadLibraryExWrapper(
+        LPCWSTR lpLibFileName,
+        HANDLE hFile,
+        DWORD dwFlags
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr   = S_OK;
+    HMODULE ret = NULL;
+    DWORD lastError;
+
+    EX_TRY
+    {
+
+        LongPathString path(LongPathString::Literal, lpLibFileName);
+
+        if (LongFile::IsPathNotFullyQualified(path) || SUCCEEDED(LongFile::NormalizePath(path)))
+        {
+#ifdef HOST_WINDOWS
+            //Adding the assert to ensure relative paths which are not just filenames are not used for LoadLibrary Calls
+            _ASSERTE(!LongFile::IsPathNotFullyQualified(path) || !LongFile::ContainsDirectorySeparator(path));
+            LongFile::NormalizeDirectorySeparators(path);
+#endif //HOST_WINDOWS
+
+            ret = LoadLibraryExW(path.GetUnicode(), hFile, dwFlags);
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK)
+    {
+        SetLastError(hr);
+    }
+    else if(ret == NULL)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+HANDLE
+CreateFileWrapper(
+        _In_ LPCWSTR lpFileName,
+        _In_ DWORD dwDesiredAccess,
+        _In_ DWORD dwShareMode,
+        _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+        _In_ DWORD dwCreationDisposition,
+        _In_ DWORD dwFlagsAndAttributes,
+        _In_opt_ HANDLE hTemplateFile
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    DWORD lastError;
+    HANDLE ret = INVALID_HANDLE_VALUE;
+
+    EX_TRY
+    {
+        LongPathString path(LongPathString::Literal, lpFileName);
+
+        if (SUCCEEDED(LongFile::NormalizePath(path)))
+        {
+            ret = CreateFileW(path.GetUnicode(),
+                    dwDesiredAccess,
+                    dwShareMode,
+                    lpSecurityAttributes,
+                    dwCreationDisposition,
+                    dwFlagsAndAttributes,
+                    hTemplateFile);
+
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK )
+    {
+        SetLastError(hr);
+    }
+    else if(ret == INVALID_HANDLE_VALUE)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+DWORD
+GetFileAttributesWrapper(
+        _In_ LPCWSTR lpFileName
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    DWORD  ret = INVALID_FILE_ATTRIBUTES;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        LongPathString path(LongPathString::Literal, lpFileName);
+
+        if (SUCCEEDED(LongFile::NormalizePath(path)))
+        {
+            ret = GetFileAttributesW(
+                    path.GetUnicode()
+                );
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK )
+    {
+        SetLastError(hr);
+    }
+    else if(ret == INVALID_FILE_ATTRIBUTES)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+BOOL
+GetFileAttributesExWrapper(
+        _In_ LPCWSTR lpFileName,
+        _In_ GET_FILEEX_INFO_LEVELS fInfoLevelId,
+        _Out_writes_bytes_(sizeof(WIN32_FILE_ATTRIBUTE_DATA)) LPVOID lpFileInformation
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    BOOL   ret = FALSE;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        LongPathString path(LongPathString::Literal, lpFileName);
+
+        if (SUCCEEDED(LongFile::NormalizePath(path)))
+        {
+            ret = GetFileAttributesExW(
+                    path.GetUnicode(),
+                    fInfoLevelId,
+                    lpFileInformation
+                    );
+
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK )
+    {
+        SetLastError(hr);
+    }
+    else if(ret == FALSE)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+BOOL
+DeleteFileWrapper(
+        _In_ LPCWSTR lpFileName
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    BOOL   ret = FALSE;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        LongPathString path(LongPathString::Literal, lpFileName);
+
+        if (SUCCEEDED(LongFile::NormalizePath(path)))
+        {
+            ret = DeleteFileW(
+                    path.GetUnicode()
+                    );
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK )
+    {
+        SetLastError(hr);
+    }
+    else if(ret == FALSE)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+BOOL
+MoveFileExWrapper(
+        _In_     LPCWSTR lpExistingFileName,
+        _In_opt_ LPCWSTR lpNewFileName,
+        _In_     DWORD    dwFlags
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr  = S_OK;
+    BOOL    ret = FALSE;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        LongPathString Existingpath(LongPathString::Literal, lpExistingFileName);
+        LongPathString Newpath(LongPathString::Literal, lpNewFileName);
+
+        if (SUCCEEDED(LongFile::NormalizePath(Existingpath)) && SUCCEEDED(LongFile::NormalizePath(Newpath)))
+        {
+            ret = MoveFileExW(
+                    Existingpath.GetUnicode(),
+                    Newpath.GetUnicode(),
+                    dwFlags
+                    );
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK )
+    {
+        SetLastError(hr);
+    }
+    else if(ret == FALSE)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+
+}
+
+DWORD
+SearchPathWrapper(
+        _In_opt_ LPCWSTR lpPath,
+        _In_ LPCWSTR lpFileName,
+        _In_opt_ LPCWSTR lpExtension,
+        _In_ BOOL getPath,
+        SString& lpBuffer,
+        _Out_opt_ LPWSTR * lpFilePart
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr  = S_OK;
+    DWORD    ret = 0;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        LongPathString Existingpath(LongPathString::Literal, lpPath);
+
+        if (lpPath != NULL)
+        {
+            if (FAILED(LongFile::NormalizePath(Existingpath)))
+            {
+                ret = FALSE;
+            }
+            else
+            {
+                lpPath = Existingpath.GetUnicode();
+            }
+        }
+
+        if (!getPath)
+        {
+            ret = SearchPathW(
+                    lpPath,
+                    lpFileName,
+                    lpExtension,
+                    0,
+                    NULL,
+                    NULL
+                    );
+        }
+        else
+        {
+            COUNT_T size = lpBuffer.GetUnicodeAllocation() + 1;
+
+            ret = SearchPathW(
+                    lpPath,
+                    lpFileName,
+                    lpExtension,
+                    size,
+                    lpBuffer.OpenUnicodeBuffer(size - 1),
+                    lpFilePart
+                    );
+
+            if (ret > size)
+            {
+                lpBuffer.CloseBuffer();
+                ret = SearchPathW(
+                        lpPath,
+                        lpFileName,
+                        lpExtension,
+                        ret,
+                        lpBuffer.OpenUnicodeBuffer(ret - 1),
+                        lpFilePart
+                        );
+            }
+
+            lpBuffer.CloseBuffer(ret);
+
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK)
+    {
+        SetLastError(hr);
+    }
+    else if (ret == 0)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+
+}
+
+DWORD
+GetModuleFileNameWrapper(
+    _In_opt_ HMODULE hModule,
+    SString& buffer
+    )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    DWORD ret = 0;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        COUNT_T size = buffer.GetUnicodeAllocation() + 1;
+
+        ret = GetModuleFileNameW(
+            hModule,
+            buffer.OpenUnicodeBuffer(size - 1),
+            (DWORD)size
+            );
+
+
+        while (ret == size )
+        {
+            buffer.CloseBuffer();
+            size = size * 2;
+            ret = GetModuleFileNameW(
+                hModule,
+                buffer.OpenUnicodeBuffer(size - 1),
+                (DWORD)size
+                );
+
+        }
+
+
+        lastError = GetLastError();
+        buffer.CloseBuffer(ret);
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK)
+    {
+        SetLastError(hr);
+    }
+    else if (ret == 0)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+UINT WINAPI GetTempFileNameWrapper(
+    _In_  LPCTSTR lpPathName,
+    _In_  LPCTSTR lpPrefixString,
+    _In_  UINT    uUnique,
+    SString&  lpTempFileName
+    )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    UINT ret = 0;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        //Change the behaviour in Redstone to retry
+        COUNT_T size = MAX_LONGPATH;
+        WCHAR* buffer = lpTempFileName.OpenUnicodeBuffer(size - 1);
+        ret  = GetTempFileNameW(
+            lpPathName,
+            lpPrefixString,
+            uUnique,
+            buffer
+            );
+
+        lastError = GetLastError();
+        size = (COUNT_T)wcslen(buffer);
+        lpTempFileName.CloseBuffer(size);
+
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK)
+    {
+        SetLastError(hr);
+    }
+    else if (ret == 0)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+DWORD WINAPI GetTempPathWrapper(
+    SString& lpBuffer
+    )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    DWORD ret = 0;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        //Change the behaviour in Redstone to retry
+        COUNT_T size = MAX_LONGPATH;
+
+        ret = GetTempPathW(
+            size,
+            lpBuffer.OpenUnicodeBuffer(size - 1)
+            );
+
+        lastError = GetLastError();
+        lpBuffer.CloseBuffer(ret);
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK)
+    {
+        SetLastError(hr);
+    }
+    else if (ret == 0)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+DWORD WINAPI GetCurrentDirectoryWrapper(
+    SString&  lpBuffer
+    )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    DWORD ret = 0;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        //Change the behaviour in Redstone to retry
+        COUNT_T size = MAX_LONGPATH;
+
+        ret = GetCurrentDirectoryW(
+            size,
+            lpBuffer.OpenUnicodeBuffer(size - 1)
+            );
+
+        lastError = GetLastError();
+        lpBuffer.CloseBuffer(ret);
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK)
+    {
+        SetLastError(hr);
+    }
+    else if (ret == 0)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+DWORD WINAPI GetEnvironmentVariableWrapper(
+    _In_opt_  LPCTSTR lpName,
+    _Out_opt_ SString&  lpBuffer
+    )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    DWORD ret = 0;
+    DWORD lastError;
+
+    EX_TRY
+    {
+
+        COUNT_T size = lpBuffer.GetUnicodeAllocation() + 1;
+
+        ret = GetEnvironmentVariableW(
+            lpName,
+            lpBuffer.OpenUnicodeBuffer(size - 1),
+            size
+            );
+
+        // We loop round getting the length of the env var and then trying to copy
+        // the value into a the allocated buffer. Usually we'll go through this loop
+        // precisely once, but the caution is ncessary in case the variable mutates
+        // beneath us, as the environment variable can be modified by another thread
+        //between two calls to GetEnvironmentVariableW
+
+        while (ret > size)
+        {
+            size = ret;
+            lpBuffer.CloseBuffer();
+            ret = GetEnvironmentVariableW(
+                lpName,
+                lpBuffer.OpenUnicodeBuffer(size - 1),
+                size);
+        }
+
+        lastError = GetLastError();
+        lpBuffer.CloseBuffer(ret);
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK)
+    {
+        SetLastError(hr);
+    }
+    else if (ret == 0)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+
+#ifdef HOST_WINDOWS
+
+BOOL
+CopyFileExWrapper(
+        _In_        LPCWSTR lpExistingFileName,
+        _In_        LPCWSTR lpNewFileName,
+        _In_opt_    LPPROGRESS_ROUTINE lpProgressRoutine,
+        _In_opt_    LPVOID lpData,
+        _When_(pbCancel != NULL, _Pre_satisfies_(*pbCancel == FALSE))
+        _Inout_opt_ LPBOOL pbCancel,
+        _In_        DWORD dwCopyFlags
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr  = S_OK;
+    BOOL    ret = FALSE;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        LongPathString Existingpath(LongPathString::Literal, lpExistingFileName);
+        LongPathString Newpath(LongPathString::Literal, lpNewFileName);
+
+        if (SUCCEEDED(LongFile::NormalizePath(Existingpath)) && SUCCEEDED(LongFile::NormalizePath(Newpath)))
+        {
+            ret = CopyFileExW(
+                    Existingpath.GetUnicode(),
+                    Newpath.GetUnicode(),
+                    lpProgressRoutine,
+                    lpData,
+                    pbCancel,
+                    dwCopyFlags
+                    );
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK )
+    {
+        SetLastError(hr);
+    }
+    else if(ret == FALSE)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+
+HANDLE
+FindFirstFileExWrapper(
+        _In_ LPCWSTR lpFileName,
+        _In_ FINDEX_INFO_LEVELS fInfoLevelId,
+        _Out_writes_bytes_(sizeof(WIN32_FIND_DATAW)) LPVOID lpFindFileData,
+        _In_ FINDEX_SEARCH_OPS fSearchOp,
+        _Reserved_ LPVOID lpSearchFilter,
+        _In_ DWORD dwAdditionalFlags
+        )
+{
+    CONTRACTL
+    {
+        NOTHROW;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = S_OK;
+    HANDLE ret = INVALID_HANDLE_VALUE;
+    DWORD lastError;
+
+    EX_TRY
+    {
+        LongPathString path(LongPathString::Literal, lpFileName);
+
+        if (SUCCEEDED(LongFile::NormalizePath(path)))
+        {
+            ret = FindFirstFileExW(
+                    path.GetUnicode(),
+                    fInfoLevelId,
+                    lpFindFileData,
+                    fSearchOp,
+                    lpSearchFilter,
+                    dwAdditionalFlags
+                    );
+        }
+
+        lastError = GetLastError();
+    }
+    EX_CATCH_HRESULT(hr);
+
+    if (hr != S_OK )
+    {
+        SetLastError(hr);
+    }
+    else if(ret == INVALID_HANDLE_VALUE)
+    {
+        SetLastError(lastError);
+    }
+
+    return ret;
+}
+#endif // HOST_WINDOWS
+
+//Implementation of LongFile Helpers
+const WCHAR LongFile::DirectorySeparatorChar = W('\\');
+const WCHAR LongFile::AltDirectorySeparatorChar = W('/');
+#ifdef HOST_WINDOWS
+const WCHAR LongFile::VolumeSeparatorChar = W(':');
+const WCHAR* LongFile::ExtendedPrefix = W("\\\\?\\");
+const WCHAR* LongFile::DevicePathPrefix = W("\\\\.\\");
+const WCHAR* LongFile::UNCExtendedPathPrefix = W("\\\\?\\UNC\\");
+const WCHAR* LongFile::UNCPathPrefix = UNCPATHPREFIX;
+
+void LongFile::NormalizeDirectorySeparators(SString& path)
+{
+    for(SString::Iterator i = path.Begin(); i < path.End(); ++i)
+    {
+        if (*i == AltDirectorySeparatorChar)
+        {
+            path.Replace(i, DirectorySeparatorChar);
+        }
+    }
+}
+
+BOOL LongFile::IsExtended(const SString & path)
+{
+    return path.BeginsWith(SL(ExtendedPrefix));
+}
+
+BOOL LongFile::IsUNCExtended(const SString & path)
+{
+    return path.BeginsWith(SL(UNCExtendedPathPrefix));
+}
+
+// Relative here means it could be relative to current directory on the relevant drive
+// NOTE: Relative segments ( \..\) are not considered relative
+// Returns true if the path specified is relative to the current drive or working directory.
+// Returns false if the path is fixed to a specific drive or UNC path.  This method does no
+// validation of the path (URIs will be returned as relative as a result).
+// Handles paths that use the alternate directory separator.  It is a frequent mistake to
+// assume that rooted paths (Path.IsPathRooted) are not relative.  This isn't the case.
+
+BOOL LongFile::IsPathNotFullyQualified(const SString & path)
+{
+    if (path.GetCount() < 2)
+    {
+        return TRUE;  // It isn't fixed, it must be relative.  There is no way to specify a fixed path with one character (or less).
+    }
+
+    if (IsDirectorySeparator(path[0]))
+    {
+        return !IsDirectorySeparator(path[1]); // There is no valid way to specify a relative path with two initial slashes
+    }
+
+    return !((path.GetCount() >= 3)           //The only way to specify a fixed path that doesn't begin with two slashes is the drive, colon, slash format- i.e. "C:\"
+            && (path[1] == VolumeSeparatorChar)
+            && IsDirectorySeparator(path[2]));
+}
+
+BOOL LongFile::IsDevice(const SString & path)
+{
+    return path.BeginsWith(SL(DevicePathPrefix));
+}
+
+// This function will normalize paths if the path length exceeds MAX_PATH
+// The normalization examples are :
+//  C:\foo\<long>\bar   => \\?\C:\foo\<long>\bar
+//  \\server\<long>\bar => \\?\UNC\server\<long>\bar
+HRESULT LongFile::NormalizePath(SString & path)
+{
+    HRESULT hr        = S_OK;
+    DWORD   ret       = 0;
+    COUNT_T prefixLen = 0;
+    if (path.IsEmpty()|| IsDevice(path) || IsExtended(path) || IsUNCExtended(path))
+        return S_OK;
+
+    if (!IsPathNotFullyQualified(path) && path.GetCount() < MAX_LONGPATH)
+        return S_OK;
+
+    //Now the path will be normalized
+
+    SString originalPath(path);
+    SString prefix(ExtendedPrefix);
+    prefixLen = prefix.GetCount();
+
+    if (path.BeginsWith(SL(UNCPathPrefix)))
+    {
+        prefix.Set(UNCExtendedPathPrefix);
+        //In this case if path is \\server the extended syntax should be like  \\?\UNC\server
+        //The below logic populates the path from prefixLen offset from the start. This ensures that first 2 characters are overwritten
+        //
+        prefixLen = prefix.GetCount() - (COUNT_T)wcslen(UNCPATHPREFIX);
+        _ASSERTE(prefixLen > 0 );
+    }
+
+
+    COUNT_T size  = path.GetUnicodeAllocation() + 1;
+    WCHAR* buffer = path.OpenUnicodeBuffer(size - 1);
+
+    ret = GetFullPathNameW(
+        originalPath.GetUnicode(),
+        size - prefixLen,        //memory avilable for path after reserving for prefix
+        (buffer + prefixLen),    //reserve memory for prefix
+        NULL
+        );
+
+    if (ret == 0)
+    {
+        return E_FAIL;
+    }
+
+    if (ret > size - prefixLen)
+    {
+        path.CloseBuffer();
+        size   = ret + prefixLen;
+        buffer = path.OpenUnicodeBuffer(size -1);
+
+        ret = GetFullPathNameW(
+            originalPath.GetUnicode(),
+            ret,                   // memory required for the path
+            (buffer + prefixLen),  //reserve memory for prefix
+            NULL
+            );
+
+        _ASSERTE(ret < size - prefixLen);
+
+        if (ret == 0)
+        {
+            return E_FAIL;
+        }
+    }
+
+       SString fullpath(SString::Literal,buffer + prefixLen);
+
+    //Check if the resolved path is a UNC. By default we assume relative path to resolve to disk
+    if (fullpath.BeginsWith(SL(UNCPathPrefix)) && prefixLen != prefix.GetCount() - (COUNT_T)wcslen(UNCPATHPREFIX))
+    {
+        //Remove the leading '\\' from the UNC path to be replaced with UNCExtendedPathPrefix
+        fullpath.Replace(fullpath.Begin(), (COUNT_T)wcslen(UNCPATHPREFIX), UNCExtendedPathPrefix);
+        path.CloseBuffer();
+        path.Set(fullpath);
+    }
+    else
+    {
+        //wcscpy_s always termintes with NULL, so we are saving the character that will be overwriiten
+        WCHAR temp = buffer[prefix.GetCount()];
+        wcscpy_s(buffer, prefix.GetCount() + 1, prefix.GetUnicode());
+        buffer[prefix.GetCount()] = temp;
+        path.CloseBuffer(ret + prefixLen);
+    }
+
+    return S_OK;
+}
+#else
+BOOL LongFile::IsPathNotFullyQualified(const SString & path)
+{
+    return TRUE;
+}
+
+//Don't need to do anything For XPlat
+HRESULT LongFile::NormalizePath(SString & path)
+{
+    return S_OK;
+}
+#endif //HOST_WINDOWS
+
+BOOL LongFile::ContainsDirectorySeparator(SString & path)
+{
+    return path.Find(path.Begin(), DirectorySeparatorChar) || path.Find(path.Begin(), AltDirectorySeparatorChar);
+}
+
+BOOL LongFile::IsDirectorySeparator(WCHAR c)
+{
+    return c == DirectorySeparatorChar || c == AltDirectorySeparatorChar;
+}
+
+
+
diff --git a/src/utilcode/namespaceutil.cpp b/src/utilcode/namespaceutil.cpp
new file mode 100644 (file)
index 0000000..5b6d3d9
--- /dev/null
@@ -0,0 +1,678 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// NamespaceUtil.cpp
+//
+
+//
+// Helpers for converting namespace separators.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "corhdr.h"
+#include "corhlpr.h"
+#include "sstring.h"
+#include "utilcode.h"
+
+#ifndef _ASSERTE
+#define _ASSERTE(foo)
+#endif
+
+#include "nsutilpriv.h"
+
+
+//*****************************************************************************
+// Determine how many chars large a fully qualified name would be given the
+// two parts of the name.  The return value includes room for every character
+// in both names, as well as room for the separator and a final terminator.
+//*****************************************************************************
+int ns::GetFullLength(                  // Number of chars in full name.
+    const WCHAR *szNameSpace,           // Namspace for value.
+    const WCHAR *szName)                // Name of value.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    int iLen = 1;                       // Null terminator.
+    if (szNameSpace)
+        iLen += (int)wcslen(szNameSpace);
+    if (szName)
+        iLen += (int)wcslen(szName);
+    if (szNameSpace && *szNameSpace && szName && *szName)
+        ++iLen;
+    return iLen;
+}   //int ns::GetFullLength()
+
+int ns::GetFullLength(                  // Number of chars in full name.
+    LPCUTF8     szNameSpace,            // Namspace for value.
+    LPCUTF8     szName)                 // Name of value.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+
+    int iLen = 1;
+    if (szNameSpace)
+        iLen += (int)strlen(szNameSpace);
+    if (szName)
+        iLen += (int)strlen(szName);
+    if (szNameSpace && *szNameSpace && szName && *szName)
+        ++iLen;
+    return iLen;
+}   //int ns::GetFullLength()
+
+
+//*****************************************************************************
+// Scan the string from the rear looking for the first valid separator.  If
+// found, return a pointer to it.  Else return null.  This code is smart enough
+// to skip over special sequences, such as:
+//      a.b..ctor
+//         ^
+//         |
+// The ".ctor" is considered one token.
+//*****************************************************************************
+WCHAR *ns::FindSep(                     // Pointer to separator or null.
+    const WCHAR *szPath)                // The path to look in.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    _ASSERTE(szPath);
+    WCHAR *ptr = (WCHAR*)wcsrchr(szPath, NAMESPACE_SEPARATOR_WCHAR);
+    if((ptr == NULL) || (ptr == szPath)) return NULL;
+    if(*(ptr - 1) == NAMESPACE_SEPARATOR_WCHAR) // here ptr is at least szPath+1
+        --ptr;
+    return ptr;
+}   //WCHAR *ns::FindSep()
+
+//<TODO>@todo: this isn't dbcs safe if this were ansi, but this is utf8.  Still an issue?</TODO>
+LPUTF8 ns::FindSep(                     // Pointer to separator or null.
+    LPCUTF8     szPath)                 // The path to look in.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+    STATIC_CONTRACT_SUPPORTS_DAC;
+
+    _ASSERTE(szPath);
+    LPUTF8 ptr = const_cast<LPUTF8>(strrchr(szPath, NAMESPACE_SEPARATOR_CHAR));
+    if((ptr == NULL) || (ptr == szPath)) return NULL;
+    if(*(ptr - 1) == NAMESPACE_SEPARATOR_CHAR) // here ptr is at least szPath+1
+        --ptr;
+    return ptr;
+}   //LPUTF8 ns::FindSep()
+
+
+
+//*****************************************************************************
+// Take a path and find the last separator (nsFindSep), and then replace the
+// separator with a '\0' and return a pointer to the name.  So for example:
+//      a.b.c
+// becomes two strings "a.b" and "c" and the return value points to "c".
+//*****************************************************************************
+WCHAR *ns::SplitInline(                 // Pointer to name portion.
+    __inout __inout_z WCHAR       *szPath)           // The path to split.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    WCHAR *ptr = ns::FindSep(szPath);
+    if (ptr)
+    {
+        *ptr = 0;
+        ++ptr;
+    }
+    return ptr;
+}   // WCHAR *ns::SplitInline()
+
+LPUTF8 ns::SplitInline(                 // Pointer to name portion.
+    __inout __inout_z LPUTF8  szPath)                 // The path to split.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    LPUTF8 ptr = ns::FindSep(szPath);
+    if (ptr)
+    {
+        *ptr = 0;
+        ++ptr;
+    }
+    return ptr;
+}   // LPUTF8 ns::SplitInline()
+
+void ns::SplitInline(
+    __inout __inout_z LPWSTR  szPath,                 // Path to split.
+    LPCWSTR     &szNameSpace,           // Return pointer to namespace.
+    LPCWSTR     &szName)                // Return pointer to name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    WCHAR *ptr = SplitInline(szPath);
+    if (ptr)
+    {
+        szNameSpace = szPath;
+        szName = ptr;
+    }
+    else
+    {
+        szNameSpace = 0;
+        szName = szPath;
+    }
+}   // void ns::SplitInline()
+
+void ns::SplitInline(
+    __inout __inout_z LPUTF8  szPath,                 // Path to split.
+    LPCUTF8     &szNameSpace,           // Return pointer to namespace.
+    LPCUTF8     &szName)                // Return pointer to name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    LPUTF8 ptr = SplitInline(szPath);
+    if (ptr)
+    {
+        szNameSpace = szPath;
+        szName = ptr;
+    }
+    else
+    {
+        szNameSpace = 0;
+        szName = szPath;
+    }
+}   // void ns::SplitInline()
+
+
+//*****************************************************************************
+// Split the last parsable element from the end of the string as the name,
+// the first part as the namespace.
+//*****************************************************************************
+int ns::SplitPath(                      // true ok, false trunction.
+    const WCHAR *szPath,                // Path to split.
+    _Out_writes_(cchNameSpace) WCHAR *szNameSpace,           // Output for namespace value.
+    int         cchNameSpace,           // Max chars for output.
+    _Out_writes_(cchName)      WCHAR *szName,                // Output for name.
+    int         cchName)                // Max chars for output.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    const WCHAR *ptr = ns::FindSep(szPath);
+    size_t iLen = (ptr) ? ptr - szPath : 0;
+    size_t iCopyMax;
+    int brtn = true;
+    if (szNameSpace && cchNameSpace)
+    {
+        _ASSERTE(cchNameSpace > 1);
+        iCopyMax = cchNameSpace - 1;
+        iCopyMax = min(iCopyMax, iLen);
+        wcsncpy_s(szNameSpace, cchNameSpace, szPath, iCopyMax);
+        szNameSpace[iCopyMax] = 0;
+
+        if (iLen >= (size_t)cchNameSpace)
+            brtn = false;
+    }
+
+    if (szName && cchName)
+    {
+        _ASSERTE(cchName > 1);
+        iCopyMax = cchName - 1;
+        if (ptr)
+            ++ptr;
+        else
+            ptr = szPath;
+        iLen = (int)wcslen(ptr);
+        iCopyMax = min(iCopyMax, iLen);
+        wcsncpy_s(szName, cchName, ptr, iCopyMax);
+        szName[iCopyMax] = 0;
+
+        if (iLen >= (size_t)cchName)
+            brtn = false;
+    }
+    return brtn;
+}   // int ns::SplitPath()
+
+
+int ns::SplitPath(                      // true ok, false trunction.
+    LPCUTF8     szPath,                 // Path to split.
+    _Out_writes_opt_ (cchNameSpace) LPUTF8      szNameSpace,            // Output for namespace value.
+    int         cchNameSpace,           // Max chars for output.
+    _Out_writes_opt_ (cchName) LPUTF8      szName,                 // Output for name.
+    int         cchName)                // Max chars for output.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    LPCUTF8 ptr = ns::FindSep(szPath);
+    size_t iLen = (ptr) ? ptr - szPath : 0;
+    size_t iCopyMax;
+    int brtn = true;
+    if (szNameSpace && cchNameSpace)
+    {
+        _ASSERTE(cchNameSpace > 1);
+        iCopyMax = cchNameSpace-1;
+        iCopyMax = min(iCopyMax, iLen);
+        strncpy_s(szNameSpace, cchNameSpace, szPath, iCopyMax);
+        szNameSpace[iCopyMax] = 0;
+
+        if (iLen >= (size_t)cchNameSpace)
+            brtn = false;
+    }
+
+    if (szName && cchName)
+    {
+        _ASSERTE(cchName > 1);
+        iCopyMax = cchName-1;
+        if (ptr)
+            ++ptr;
+        else
+            ptr = szPath;
+        iLen = (int)strlen(ptr);
+        iCopyMax = min(iCopyMax, iLen);
+        strncpy_s(szName, cchName, ptr, iCopyMax);
+        szName[iCopyMax] = 0;
+
+        if (iLen >= (size_t)cchName)
+            brtn = false;
+    }
+    return brtn;
+}   // int ns::SplitPath()
+
+
+//*****************************************************************************
+// Take two values and put them together in a fully qualified path using the
+// correct separator.
+//*****************************************************************************
+int ns::MakePath(                       // true ok, false truncation.
+    _Out_writes_(cchChars) WCHAR       *szOut,                 // output path for name.
+    int         cchChars,               // max chars for output path.
+    const WCHAR *szNameSpace,           // Namespace.
+    const WCHAR *szName)                // Name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    if (cchChars < 1)
+        return false;
+
+    if (szOut)
+        *szOut = 0;
+    else
+        return false;
+
+    if (szNameSpace && *szNameSpace != W('\0'))
+    {
+        if (wcsncpy_s(szOut, cchChars, szNameSpace, _TRUNCATE) == STRUNCATE)
+            return false;
+
+        // Add namespace separator if a non-empty name was supplied
+        if (szName && *szName != W('\0'))
+        {
+            if (wcsncat_s(szOut, cchChars, NAMESPACE_SEPARATOR_WSTR, _TRUNCATE) == STRUNCATE)
+            {
+                return false;
+            }
+        }
+    }
+
+    if (szName && *szName)
+    {
+        if (wcsncat_s(szOut, cchChars, szName, _TRUNCATE) == STRUNCATE)
+            return false;
+    }
+
+    return true;
+}   // int ns::MakePath()
+
+int ns::MakePath(                       // true ok, false truncation.
+    _Out_writes_(cchChars) LPUTF8      szOut,                  // output path for name.
+    int         cchChars,               // max chars for output path.
+    LPCUTF8     szNameSpace,            // Namespace.
+    LPCUTF8     szName)                 // Name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    if (cchChars < 1)
+        return false;
+
+    if (szOut)
+        *szOut = 0;
+    else
+        return false;
+
+    if (szNameSpace && *szNameSpace != W('\0'))
+    {
+        if (strncpy_s(szOut, cchChars, szNameSpace, _TRUNCATE) == STRUNCATE)
+            return false;
+
+        // Add namespace separator if a non-empty name was supplied
+        if (szName && *szName != W('\0'))
+        {
+            if (strncat_s(szOut, cchChars, NAMESPACE_SEPARATOR_STR, _TRUNCATE) == STRUNCATE)
+            {
+                return false;
+            }
+        }
+    }
+
+    if (szName && *szName)
+    {
+        if (strncat_s(szOut, cchChars, szName, _TRUNCATE) == STRUNCATE)
+            return false;
+    }
+
+    return true;
+
+}   // int ns::MakePath()
+
+int ns::MakePath(                       // true ok, false truncation.
+    _Out_writes_(cchChars) WCHAR       *szOut,                 // output path for name.
+    int         cchChars,               // max chars for output path.
+    LPCUTF8     szNamespace,            // Namespace.
+    LPCUTF8     szName)                 // Name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    if (cchChars < 1)
+        return false;
+
+    if (szOut)
+        *szOut = 0;
+    else
+        return false;
+
+    if (szNamespace != NULL && *szNamespace != '\0')
+    {
+        if (cchChars < 2)
+            return false;
+
+        int count;
+
+        // We use cBuffer - 2 to account for the '.' and at least a 1 character name below.
+        count = WszMultiByteToWideChar(CP_UTF8, 0, szNamespace, -1, szOut, cchChars-2);
+        if (count == 0)
+            return false; // Supply a bigger buffer!
+
+        // buffer access is bounded: WszMultiByteToWideChar returns 0 if access doesn't fit in range
+#ifdef _PREFAST_
+        #pragma warning( suppress: 26015 )
+#endif
+        szOut[count-1] = NAMESPACE_SEPARATOR_WCHAR;
+        szOut += count;
+        cchChars -= count;
+    }
+
+    if (((cchChars == 0) && (szName != NULL) && (*szName != '\0')) ||
+        (WszMultiByteToWideChar(CP_UTF8, 0, szName, -1, szOut, cchChars) == 0))
+        return false; // supply a bigger buffer!
+    return true;
+}   // int ns::MakePath()
+
+int ns::MakePath(                       // true ok, false out of memory
+    CQuickBytes &qb,                    // Where to put results.
+    LPCUTF8     szNameSpace,            // Namespace for name.
+    LPCUTF8     szName)                 // Final part of name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    int iLen = 2;
+    if (szNameSpace)
+        iLen += (int)strlen(szNameSpace);
+    if (szName)
+        iLen += (int)strlen(szName);
+    LPUTF8 szOut = (LPUTF8) qb.AllocNoThrow(iLen);
+    if (!szOut)
+        return false;
+    return ns::MakePath(szOut, iLen, szNameSpace, szName);
+}   // int ns::MakePath()
+
+int ns::MakePath(                       // true ok, false out of memory
+    CQuickArray<WCHAR> &qa,             // Where to put results.
+    LPCUTF8            szNameSpace,     // Namespace for name.
+    LPCUTF8            szName)          // Final part of name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    int iLen = 2;
+    if (szNameSpace)
+        iLen += (int)strlen(szNameSpace);
+    if (szName)
+        iLen += (int)strlen(szName);
+    WCHAR *szOut = (WCHAR *) qa.AllocNoThrow(iLen);
+    if (!szOut)
+        return false;
+    return ns::MakePath(szOut, iLen, szNameSpace, szName);
+}   // int ns::MakePath()
+
+int ns::MakePath(                       // true ok, false out of memory
+    CQuickBytes &qb,                    // Where to put results.
+    const WCHAR *szNameSpace,           // Namespace for name.
+    const WCHAR *szName)                // Final part of name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    int iLen = 2;
+    if (szNameSpace)
+        iLen += (int)wcslen(szNameSpace);
+    if (szName)
+        iLen += (int)wcslen(szName);
+    WCHAR *szOut = (WCHAR *) qb.AllocNoThrow(iLen * sizeof(WCHAR));
+    if (!szOut)
+        return false;
+    return ns::MakePath(szOut, iLen, szNameSpace, szName);
+}   // int ns::MakePath()
+
+void ns::MakePath(                      // throws on out of memory
+    SString       &ssBuf,               // Where to put results.
+    const SString &ssNameSpace,         // Namespace for name.
+    const SString &ssName)              // Final part of name.
+{
+    STATIC_CONTRACT_THROWS;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    ssBuf.Clear();
+
+    if (!ssNameSpace.IsEmpty())
+    {
+        if (ssName.IsEmpty())
+        {
+            ssBuf.Set(ssNameSpace);
+        }
+        else
+        {
+            SString s(SString::Literal, NAMESPACE_SEPARATOR_WSTR);
+            ssBuf.Set(ssNameSpace, s);
+        }
+    }
+
+    if (!ssName.IsEmpty())
+    {
+        ssBuf.Append(ssName);
+    }
+}
+
+bool ns::MakeAssemblyQualifiedName(                                        // true ok, false truncation
+                                   _Out_writes_(dwBuffer) WCHAR* pBuffer,  // Buffer to receive the results
+                                   int    dwBuffer,                        // Number of characters total in buffer
+                                   const WCHAR *szTypeName,                // Namespace for name.
+                                   int   dwTypeName,                       // Number of characters (not including null)
+                                   const WCHAR *szAssemblyName,            // Final part of name.
+                                   int   dwAssemblyName)                   // Number of characters (not including null)
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    if (dwBuffer < 2)
+        return false;
+
+    int iCopyMax = 0;
+    _ASSERTE(pBuffer);
+    *pBuffer = NULL;
+
+    if (szTypeName && *szTypeName != W('\0'))
+    {
+        _ASSERTE(dwTypeName > 0);
+        iCopyMax = min(dwBuffer-1, dwTypeName);
+        wcsncpy_s(pBuffer, dwBuffer, szTypeName, iCopyMax);
+        dwBuffer -= iCopyMax;
+    }
+
+    if (szAssemblyName && *szAssemblyName != W('\0'))
+    {
+
+        if(dwBuffer < ASSEMBLY_SEPARATOR_LEN)
+            return false;
+
+        for(DWORD i = 0; i < ASSEMBLY_SEPARATOR_LEN; i++)
+            pBuffer[iCopyMax+i] = ASSEMBLY_SEPARATOR_WSTR[i];
+
+        dwBuffer -= ASSEMBLY_SEPARATOR_LEN;
+        if(dwBuffer == 0)
+            return false;
+
+        int iCur = iCopyMax + ASSEMBLY_SEPARATOR_LEN;
+        _ASSERTE(dwAssemblyName > 0);
+        iCopyMax = min(dwBuffer-1, dwAssemblyName);
+        wcsncpy_s(pBuffer + iCur, dwBuffer, szAssemblyName, iCopyMax);
+        pBuffer[iCur + iCopyMax] = W('\0');
+
+        if (iCopyMax < dwAssemblyName)
+            return false;
+    }
+    else {
+        if(dwBuffer == 0) {
+            PREFIX_ASSUME(iCopyMax > 0);
+            pBuffer[iCopyMax-1] = W('\0');
+            return false;
+        }
+        else
+            pBuffer[iCopyMax] = W('\0');
+    }
+
+    return true;
+}   // int ns::MakePath()
+
+bool ns::MakeAssemblyQualifiedName(                                        // true ok, false out of memory
+                                   CQuickBytes &qb,                        // Where to put results.
+                                   const WCHAR *szTypeName,                // Namespace for name.
+                                   const WCHAR *szAssemblyName)            // Final part of name.
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    int iTypeName = 0;
+    int iAssemblyName = 0;
+    if (szTypeName)
+        iTypeName = (int)wcslen(szTypeName);
+    if (szAssemblyName)
+        iAssemblyName = (int)wcslen(szAssemblyName);
+
+    int iLen = ASSEMBLY_SEPARATOR_LEN + iTypeName + iAssemblyName + 1; // Space for null terminator
+    WCHAR *szOut = (WCHAR *) qb.AllocNoThrow(iLen * sizeof(WCHAR));
+    if (!szOut)
+        return false;
+
+    bool ret;
+    ret = ns::MakeAssemblyQualifiedName(szOut, iLen, szTypeName, iTypeName, szAssemblyName, iAssemblyName);
+    _ASSERTE(ret);
+    return true;
+}
+
+int ns::MakeNestedTypeName(             // true ok, false out of memory
+    CQuickBytes &qb,                    // Where to put results.
+    LPCUTF8     szEnclosingName,        // Full name for enclosing type
+    LPCUTF8     szNestedName)           // Full name for nested type
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FAULT;
+
+    _ASSERTE(szEnclosingName && szNestedName);
+    int iLen = 2;
+    iLen += (int)strlen(szEnclosingName);
+    iLen += (int)strlen(szNestedName);
+    LPUTF8 szOut = (LPUTF8) qb.AllocNoThrow(iLen);
+    if (!szOut)
+        return false;
+    return ns::MakeNestedTypeName(szOut, iLen, szEnclosingName, szNestedName);
+}   // int ns::MakeNestedTypeName()
+
+int ns::MakeNestedTypeName(             // true ok, false truncation.
+    _Out_writes_ (cchChars) LPUTF8      szOut,                  // output path for name.
+    int         cchChars,               // max chars for output path.
+    LPCUTF8     szEnclosingName,        // Full name for enclosing type
+    LPCUTF8     szNestedName)           // Full name for nested type
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_FORBID_FAULT;
+
+    if (cchChars < 1)
+        return false;
+
+    int iCopyMax = 0, iLen;
+    int brtn = true;
+    *szOut = 0;
+
+    iLen = (int)strlen(szEnclosingName);
+    iCopyMax = min(cchChars-1, iLen);
+    strncpy_s(szOut, cchChars, szEnclosingName, iCopyMax);
+
+    if (iLen >= cchChars)
+        brtn =  false;
+
+    szOut[iCopyMax] = NESTED_SEPARATOR_CHAR;
+    int iCur = iCopyMax+1; // iCopyMax characters + nested_separator_char
+    cchChars -= iCur;
+    if(cchChars == 0)
+        return false;
+
+    iLen = (int)strlen(szNestedName);
+    iCopyMax = min(cchChars-1, iLen);
+    strncpy_s(&szOut[iCur], cchChars, szNestedName, iCopyMax);
+    szOut[iCur + iCopyMax] = 0;
+
+    if (iLen >= cchChars)
+        brtn = false;
+
+    return brtn;
+}   // int ns::MakeNestedTypeName()
+
+void ns::MakeNestedTypeName(            // throws on out of memory
+    SString        &ssBuf,              // output path for name.
+    const SString  &ssEnclosingName,    // Full name for enclosing type
+    const SString  &ssNestedName)       // Full name for nested type
+{
+    STATIC_CONTRACT_THROWS;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    ssBuf.Clear();
+
+    ssBuf.Append(ssEnclosingName);
+    ssBuf.Append(NESTED_SEPARATOR_WCHAR);
+    ssBuf.Append(ssNestedName);
+}
+
diff --git a/src/utilcode/pedecoder.cpp b/src/utilcode/pedecoder.cpp
new file mode 100644 (file)
index 0000000..ad4f018
--- /dev/null
@@ -0,0 +1,2564 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// --------------------------------------------------------------------------------
+// PEDecoder.cpp
+//
+
+// --------------------------------------------------------------------------------
+
+#include "stdafx.h"
+
+#include "ex.h"
+#include "pedecoder.h"
+#include "mdcommon.h"
+#include "nibblemapmacros.h"
+
+CHECK PEDecoder::CheckFormat() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(HasContents());
+
+    if (HasNTHeaders())
+    {
+        CHECK(CheckNTHeaders());
+
+        if (HasCorHeader())
+        {
+            CHECK(CheckCorHeader());
+
+            if (IsILOnly())
+                CHECK(CheckILOnly());
+        }
+    }
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckNTFormat() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(HasContents());
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(CheckFormat());
+    CHECK(HasNTHeaders());
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckCORFormat() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(HasContents());
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(CheckFormat());
+    CHECK(HasNTHeaders());
+    CHECK(HasCorHeader());
+
+    CHECK_OK;
+}
+
+
+CHECK PEDecoder::CheckILFormat() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(HasContents());
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(CheckFormat());
+    CHECK(HasNTHeaders());
+    CHECK(HasCorHeader());
+
+    CHECK_OK;
+}
+
+
+CHECK PEDecoder::CheckILOnlyFormat() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(HasContents());
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(CheckFormat());
+    CHECK(HasNTHeaders());
+    CHECK(HasCorHeader());
+    CHECK(IsILOnly());
+
+    CHECK_OK;
+}
+
+BOOL PEDecoder::HasNTHeaders() const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+        PRECONDITION(HasContents());
+    }
+    CONTRACT_END;
+
+    // Check for a valid DOS header
+
+    if (m_size < sizeof(IMAGE_DOS_HEADER))
+        RETURN FALSE;
+
+    IMAGE_DOS_HEADER* pDOS = PTR_IMAGE_DOS_HEADER(m_base);
+
+    {
+        if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE)
+            || (DWORD) pDOS->e_lfanew == VAL32(0))
+        {
+            RETURN FALSE;
+        }
+
+        // Check for integer overflow
+        S_SIZE_T cbNTHeaderEnd(S_SIZE_T(static_cast<SIZE_T>(VAL32(pDOS->e_lfanew))) +
+                               S_SIZE_T(sizeof(IMAGE_NT_HEADERS)));
+        if (cbNTHeaderEnd.IsOverflow())
+        {
+            RETURN FALSE;
+        }
+
+        // Now check for a valid NT header
+        if (m_size < cbNTHeaderEnd.Value())
+        {
+            RETURN FALSE;
+        }
+    }
+
+    IMAGE_NT_HEADERS *pNT = PTR_IMAGE_NT_HEADERS(m_base + VAL32(pDOS->e_lfanew));
+
+    if (pNT->Signature != VAL32(IMAGE_NT_SIGNATURE))
+        RETURN FALSE;
+
+    if (pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC))
+    {
+        if (pNT->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER32)))
+            RETURN FALSE;
+    }
+    else if (pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC))
+    {
+        // on 64 bit we can promote this
+        if (pNT->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER64)))
+            RETURN FALSE;
+
+        // Check for integer overflow
+        S_SIZE_T cbNTHeaderEnd(S_SIZE_T(static_cast<SIZE_T>(VAL32(pDOS->e_lfanew))) +
+                               S_SIZE_T(sizeof(IMAGE_NT_HEADERS64)));
+
+        if (cbNTHeaderEnd.IsOverflow())
+        {
+            RETURN FALSE;
+    }
+
+        // Now check for a valid NT header
+        if (m_size < cbNTHeaderEnd.Value())
+        {
+            RETURN FALSE;
+        }
+
+    }
+    else
+        RETURN FALSE;
+
+    // Go ahead and cache NT header since we already found it.
+    const_cast<PEDecoder *>(this)->m_pNTHeaders = dac_cast<PTR_IMAGE_NT_HEADERS>(pNT);
+
+    RETURN TRUE;
+}
+
+CHECK PEDecoder::CheckNTHeaders() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+        PRECONDITION(HasContents());
+    }
+    CONTRACT_CHECK_END;
+
+    // Only check once per file
+    if (m_flags & FLAG_NT_CHECKED)
+        CHECK_OK;
+
+    CHECK(HasNTHeaders());
+
+    IMAGE_NT_HEADERS *pNT = FindNTHeaders();
+
+    CHECK((pNT->FileHeader.Characteristics & VAL16(IMAGE_FILE_SYSTEM)) == 0);
+
+    CHECK(CheckAlignment(VAL32(pNT->OptionalHeader.FileAlignment)));
+    CHECK(CheckAlignment(VAL32(pNT->OptionalHeader.SectionAlignment)));
+
+    CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.FileAlignment), 512));
+    CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SectionAlignment), VAL32(pNT->OptionalHeader.FileAlignment)));
+
+    CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SizeOfImage), VAL32(pNT->OptionalHeader.SectionAlignment)));
+    CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SizeOfHeaders), VAL32(pNT->OptionalHeader.FileAlignment)));
+
+    // Data directories will be validated later on.
+    PTR_IMAGE_DATA_DIRECTORY pDataDirectories = NULL;
+
+    if (Has32BitNTHeaders())
+    {
+        IMAGE_NT_HEADERS32* pNT32=GetNTHeaders32();
+        CHECK(CheckAligned(VAL32(pNT32->OptionalHeader.ImageBase), 0x10000));
+        CHECK((VAL32(pNT32->OptionalHeader.SizeOfStackCommit) <= VAL32(pNT32->OptionalHeader.SizeOfStackReserve)));
+        CHECK((VAL32(pNT32->OptionalHeader.SizeOfHeapCommit) <= VAL32(pNT32->OptionalHeader.SizeOfHeapReserve)));
+        pDataDirectories = dac_cast<PTR_IMAGE_DATA_DIRECTORY>(
+            dac_cast<TADDR>(pNT32) + offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory));
+    }
+    else
+    {
+        IMAGE_NT_HEADERS64* pNT64=GetNTHeaders64();
+        CHECK(CheckAligned(VAL64(pNT64->OptionalHeader.ImageBase), 0x10000));
+        CHECK((VAL64(pNT64->OptionalHeader.SizeOfStackCommit) <= VAL64(pNT64->OptionalHeader.SizeOfStackReserve)));
+        CHECK((VAL64(pNT64->OptionalHeader.SizeOfHeapCommit) <= VAL64(pNT64->OptionalHeader.SizeOfHeapReserve)));
+        pDataDirectories = dac_cast<PTR_IMAGE_DATA_DIRECTORY>(
+            dac_cast<TADDR>(pNT64) + offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory));
+    }
+
+    // @todo: this is a bit awkward here, it would be better to make this assertion on
+    // PEDecoder instantiation.  However, we don't necessarily have the NT headers there (in fact
+    // they might not exist.)
+
+    if (IsMapped())
+    {
+        // Ideally we would require the layout address to honor the section alignment constraints.
+        // However, we do have 8K aligned IL only images which we load on 32 bit platforms.
+        // Also in the case of files embedded within a single-file app, the default alignment for assemblies is 16 bytes.
+        CHECK(CheckAligned(m_base, 16));
+    }
+
+    // @todo: check NumberOfSections for overflow of SizeOfHeaders
+
+    UINT32 currentAddress  = 0;
+    UINT32 currentOffset = 0;
+
+    CHECK(CheckSection(currentAddress, 0, VAL32(pNT->OptionalHeader.SizeOfHeaders),
+                       currentOffset, 0, VAL32(pNT->OptionalHeader.SizeOfHeaders)));
+
+    currentAddress=currentOffset=VAL32(pNT->OptionalHeader.SizeOfHeaders);
+
+    PTR_IMAGE_SECTION_HEADER section = FindFirstSection(pNT);
+    PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(pNT->FileHeader.NumberOfSections);
+
+    CHECK(sectionEnd >= section);
+
+
+    while (section < sectionEnd)
+    {
+
+        //
+        // NOTE: the if condition is becuase of a design issue in the CLR and OS loader's remapping
+        // of PE32 headers to PE32+. Because IMAGE_NT_HEADERS64 is bigger than IMAGE_NT_HEADERS32,
+        // the remapping will expand this part of the header and push out the following
+        // IMAGE_SECTION_HEADER entries. When IMAGE_DOS_HEADER::e_lfanew is large enough
+        // (size is proportional to the number of tools used to produce the inputs to the C++ linker)
+        // this can push the last section header
+        // beyond the boundary set by IMAGE_NT_HEADERS::OptionalHeader.SizeOfHeaders (e.g., this
+        // was recently seen where the unaligned size of the headers was 0x1f8 and SizeOfHeaders was
+        // 0x200, and the header remapping resulted in new headers size of 0x208). To compensate
+        // for this issue (it would be quite difficult to fix in the remapping code; see Dev11 430008)
+        // we assume that when the image is mapped that the needed validation has already been done.
+        //
+
+        if (!IsMapped())
+        {
+            CHECK(CheckBounds(dac_cast<PTR_CVOID>(pNT),VAL32(pNT->OptionalHeader.SizeOfHeaders),
+                              section,sizeof(IMAGE_SECTION_HEADER)));
+        }
+
+        // Check flags
+        // Only allow a small list of characteristics
+        CHECK(!(section->Characteristics &
+            ~(VAL32((IMAGE_SCN_CNT_CODE           |
+                  IMAGE_SCN_CNT_INITIALIZED_DATA  |
+                  IMAGE_SCN_CNT_UNINITIALIZED_DATA|
+                  IMAGE_SCN_MEM_DISCARDABLE       |
+                  IMAGE_SCN_MEM_NOT_CACHED        |
+                  IMAGE_SCN_MEM_NOT_PAGED         |
+                  IMAGE_SCN_MEM_EXECUTE           |
+                  IMAGE_SCN_MEM_READ              |
+                  IMAGE_SCN_MEM_WRITE             |
+                  // allow shared sections for all images for now.
+                  // we'll constrain this in CheckILOnly
+                  IMAGE_SCN_MEM_SHARED)))));
+
+        // we should not allow writable code sections, check if both flags are set
+        CHECK((section->Characteristics & VAL32((IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_WRITE))) !=
+            VAL32((IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_WRITE)));
+
+        CHECK(CheckSection(currentAddress, VAL32(section->VirtualAddress), VAL32(section->Misc.VirtualSize),
+                           currentOffset, VAL32(section->PointerToRawData), VAL32(section->SizeOfRawData)));
+
+        currentAddress = VAL32(section->VirtualAddress)
+          + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(pNT->OptionalHeader.SectionAlignment));
+        currentOffset = VAL32(section->PointerToRawData) + VAL32(section->SizeOfRawData);
+
+        section++;
+    }
+
+    // Now check that the COR data directory is either NULL, or exists entirely in one section.
+    {
+        PTR_IMAGE_DATA_DIRECTORY pCORDataDir = pDataDirectories + IMAGE_DIRECTORY_ENTRY_COMHEADER;
+        CHECK(CheckRva(VAL32(pCORDataDir->VirtualAddress), VAL32(pCORDataDir->Size), 0, NULL_OK));
+    }
+
+    // @todo: verify directory entries
+
+    const_cast<PEDecoder *>(this)->m_flags |= FLAG_NT_CHECKED;
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckSection(COUNT_T previousAddressEnd, COUNT_T addressStart, COUNT_T addressSize,
+                              COUNT_T previousOffsetEnd, COUNT_T offsetStart, COUNT_T offsetSize) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(HasNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_CHECK_END;
+
+    // Fetch the NT header
+    IMAGE_NT_HEADERS *pNT = FindNTHeaders();
+
+    // OS will zero pad a mapped file up to file alignment size - some images rely on this
+    // COUNT_T alignedSize = AlignUp(m_size, VAL32(pNT->OptionalHeader.FileAlignment));
+    COUNT_T alignedSize = IsMapped() ? AlignUp(m_size, VAL32(pNT->OptionalHeader.FileAlignment)) : m_size;
+
+    // Check to make sure that our memory is big enough to cover the stated range.
+    // Note that this check is only required if we have a non-flat image.
+    if (IsMapped())
+        CHECK(alignedSize >= VAL32(pNT->OptionalHeader.SizeOfImage));
+
+    // Check expected alignments
+#if TARGET_WINDOWS
+    // On Windows we expect section starts to be a multiple of SectionAlignment.
+    // That is not an explicit requirement in the documentation, but it looks like OS loader expects it.
+    // In contrast to this, in Unix R2R files we keep lower 16bits of sections RVA and
+    // this condition does not hold.
+    CHECK(CheckAligned(addressStart, VAL32(pNT->OptionalHeader.SectionAlignment)));
+#endif
+    CHECK(CheckAligned(offsetStart, VAL32(pNT->OptionalHeader.FileAlignment)));
+    CHECK(CheckAligned(offsetSize, VAL32(pNT->OptionalHeader.FileAlignment)));
+
+    // addressSize is typically not aligned, so we align it for purposes of checks.
+    COUNT_T alignedAddressSize = AlignUp(addressSize, VAL32(pNT->OptionalHeader.SectionAlignment));
+    CHECK(addressSize <= alignedAddressSize);
+
+    // Check overflow
+    CHECK(CheckOverflow(addressStart, alignedAddressSize));
+    CHECK(CheckOverflow(offsetStart, offsetSize));
+
+    // Make sure we don't overlap the previous section
+    CHECK(addressStart >= previousAddressEnd
+          && (offsetSize == 0
+              || offsetStart >= previousOffsetEnd));
+
+    // Make sure we don't overrun the end of the mapped image
+    CHECK(addressStart + alignedAddressSize <= VAL32(pNT->OptionalHeader.SizeOfImage));
+
+    // Make sure we don't overrun the end of the file (only relevant if we're not mapped, otherwise
+    // we don't know the file size, as it's not declared in the headers.)
+    if (!IsMapped())
+        CHECK(offsetStart + offsetSize <= alignedSize);
+
+    // Make sure the data doesn't overrun the virtual address space
+    CHECK(offsetSize <= alignedAddressSize);
+
+    CHECK_OK;
+}
+
+BOOL PEDecoder::HasWriteableSections() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckFormat());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_CHECK_END;
+
+    PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection();
+    _ASSERTE(pSection != NULL);
+
+    PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
+
+    while (pSection < pSectionEnd)
+    {
+        if ((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) != 0)
+        {
+            return TRUE;
+        }
+
+        pSection++;
+    }
+
+    return FALSE;
+}
+
+CHECK PEDecoder::CheckDirectoryEntry(int entry, int forbiddenFlags, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(entry < IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
+        PRECONDITION(HasDirectoryEntry(entry));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(CheckDirectory(GetDirectoryEntry(entry), forbiddenFlags, ok));
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckPointer(pDir));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(CheckRva(VAL32(pDir->VirtualAddress), VAL32(pDir->Size), forbiddenFlags, ok));
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckRva(RVA rva, COUNT_T size, int forbiddenFlags, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_CHECK_END;
+
+    if (rva == 0)
+    {
+        CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
+        CHECK(size == 0);
+    }
+    else
+    {
+        IMAGE_SECTION_HEADER *section = RvaToSection(rva);
+
+        CHECK(section != NULL);
+
+        CHECK(CheckBounds(VAL32(section->VirtualAddress),
+                          // AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment)),
+                          (UINT)VAL32(section->Misc.VirtualSize),
+                          rva, size));
+        if(!IsMapped())
+        {
+            CHECK(CheckBounds(VAL32(section->VirtualAddress), VAL32(section->SizeOfRawData), rva, size));
+        }
+
+        if (forbiddenFlags!=0)
+            CHECK((section->Characteristics & VAL32(forbiddenFlags))==0);
+    }
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckRva(RVA rva, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_CHECK_END;
+
+    if (rva == 0)
+        CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
+    else
+        CHECK(RvaToSection(rva) != NULL);
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckOffset(COUNT_T fileOffset, COUNT_T size, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    if (fileOffset == 0)
+    {
+        CHECK_MSG(ok == NULL_OK, "zero fileOffset illegal");
+        CHECK(size == 0);
+    }
+    else
+    {
+        IMAGE_SECTION_HEADER *section = OffsetToSection(fileOffset);
+
+        CHECK(section != NULL);
+
+        CHECK(CheckBounds(section->PointerToRawData, section->SizeOfRawData,
+                          fileOffset, size));
+    }
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckOffset(COUNT_T fileOffset, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    if (fileOffset == NULL)
+        CHECK_MSG(ok == NULL_OK, "Null pointer illegal");
+    else
+    {
+        CHECK(OffsetToSection(fileOffset) != NULL);
+    }
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckData(const void *data, COUNT_T size, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    if (data == NULL)
+    {
+        CHECK_MSG(ok == NULL_OK, "NULL pointer illegal");
+        CHECK(size == 0);
+    }
+    else
+    {
+        CHECK(CheckUnderflow(data, m_base));
+        CHECK((UINT_PTR) (((BYTE *) data) - ((BYTE *) m_base)) <= COUNT_T_MAX);
+
+        if (IsMapped())
+            CHECK(CheckRva((COUNT_T) ((BYTE *) data - (BYTE *) m_base), size));
+        else
+            CHECK(CheckOffset((COUNT_T) ((BYTE *) data - (BYTE *) m_base), size));
+    }
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckData(const void *data, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    if (data == NULL)
+        CHECK_MSG(ok == NULL_OK, "Null pointer illegal");
+    else
+    {
+        CHECK(CheckUnderflow(data, m_base));
+        CHECK((UINT_PTR) (((BYTE *) data) - ((BYTE *) m_base)) <= COUNT_T_MAX);
+
+        if (IsMapped())
+            CHECK(CheckRva((COUNT_T) ((BYTE *) data - (BYTE *) m_base)));
+        else
+            CHECK(CheckOffset((COUNT_T) ((BYTE *) data - (BYTE *) m_base)));
+    }
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckInternalAddress(SIZE_T address, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    if (address == 0)
+        CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
+    else
+        CHECK(RvaToSection(InternalAddressToRva(address)) != NULL);
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckInternalAddress(SIZE_T address, COUNT_T size, IsNullOK ok) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    if (address == 0)
+    {
+        CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
+        CHECK(size == 0);
+    }
+    else
+    {
+        CHECK(CheckRva(InternalAddressToRva(address), size));
+    }
+
+    CHECK_OK;
+}
+
+RVA PEDecoder::InternalAddressToRva(SIZE_T address) const
+{
+    CONTRACT(RVA)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckRva(RETVAL));
+    }
+    CONTRACT_END;
+
+    if (m_flags & FLAG_RELOCATED)
+    {
+        // Address has been fixed up
+        RETURN (RVA) ((BYTE *) address - (BYTE *) m_base);
+    }
+    else
+    {
+        // Address has not been fixed up
+        RETURN (RVA) (address - (SIZE_T) GetPreferredBase());
+    }
+}
+
+// Returns a pointer to the named section or NULL if not found.
+// The name should include the starting "." as well.
+IMAGE_SECTION_HEADER *PEDecoder::FindSection(LPCSTR sectionName) const
+{
+    CONTRACT(IMAGE_SECTION_HEADER *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(sectionName != NULL);
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+    }
+    CONTRACT_END;
+
+    // Ensure that the section name length is valid
+    SIZE_T iSectionNameLength = strlen(sectionName);
+    if ((iSectionNameLength < 1) || (iSectionNameLength > IMAGE_SIZEOF_SHORT_NAME))
+    {
+        _ASSERTE(!"Invalid section name!");
+        RETURN NULL;
+    }
+
+    // Get the start and ends of the sections
+    PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection(FindNTHeaders());
+    _ASSERTE(pSection != NULL);
+    PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
+    _ASSERTE(pSectionEnd != NULL);
+
+    BOOL fFoundSection = FALSE;
+
+    // Loop thru the sections and see if we got the section we are interested in
+    while (pSection < pSectionEnd)
+    {
+        // Is this the section we are looking for?
+        if (strncmp(sectionName, (char*)pSection->Name, iSectionNameLength) == 0)
+        {
+            // We found our section - break out of the loop
+            fFoundSection = TRUE;
+            break;
+        }
+
+        // Move to the next section
+        pSection++;
+     }
+
+    if (TRUE == fFoundSection)
+        RETURN pSection;
+    else
+        RETURN NULL;
+}
+
+IMAGE_SECTION_HEADER *PEDecoder::RvaToSection(RVA rva) const
+{
+    CONTRACT(IMAGE_SECTION_HEADER *)
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    PTR_IMAGE_SECTION_HEADER section = dac_cast<PTR_IMAGE_SECTION_HEADER>(FindFirstSection(FindNTHeaders()));
+    PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
+
+    while (section < sectionEnd)
+    {
+        if (rva < (VAL32(section->VirtualAddress)
+                   + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment))))
+        {
+            if (rva < VAL32(section->VirtualAddress))
+                RETURN NULL;
+            else
+            {
+                RETURN section;
+            }
+        }
+
+        section++;
+    }
+
+    RETURN NULL;
+}
+
+IMAGE_SECTION_HEADER *PEDecoder::OffsetToSection(COUNT_T fileOffset) const
+{
+    CONTRACT(IMAGE_SECTION_HEADER *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    PTR_IMAGE_SECTION_HEADER section = dac_cast<PTR_IMAGE_SECTION_HEADER>(FindFirstSection(FindNTHeaders()));
+    PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
+
+    while (section < sectionEnd)
+    {
+        if (fileOffset < section->PointerToRawData + section->SizeOfRawData)
+        {
+            if (fileOffset < section->PointerToRawData)
+                RETURN NULL;
+            else
+                RETURN section;
+        }
+
+        section++;
+    }
+
+    RETURN NULL;
+}
+
+TADDR PEDecoder::GetRvaData(RVA rva, IsNullOK ok /*= NULL_NOT_OK*/) const
+{
+    CONTRACT(TADDR)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckRva(rva, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    if ((rva == 0)&&(ok == NULL_NOT_OK))
+        RETURN NULL;
+
+    RVA offset;
+    if (IsMapped())
+        offset = rva;
+    else
+    {
+        // !!! check for case where rva is in padded portion of segment
+        offset = RvaToOffset(rva);
+    }
+
+    RETURN( m_base + offset );
+}
+
+RVA PEDecoder::GetDataRva(const TADDR data) const
+{
+    CONTRACT(RVA)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckData((void *)data, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    if (data == NULL)
+        RETURN 0;
+
+    COUNT_T offset = (COUNT_T) (data - m_base);
+    if (IsMapped())
+        RETURN offset;
+    else
+        RETURN OffsetToRva(offset);
+}
+
+BOOL PEDecoder::PointerInPE(PTR_CVOID data) const
+{
+    CONTRACTL
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        FORBID_FAULT;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    TADDR taddrData = dac_cast<TADDR>(data);
+    TADDR taddrBase = dac_cast<TADDR>(m_base);
+
+    if (this->IsMapped())
+    {
+        return taddrBase <= taddrData  && taddrData  < taddrBase + GetVirtualSize();
+    }
+    else
+    {
+        return taddrBase <= taddrData  && taddrData < taddrBase + GetSize();
+    }
+}
+
+TADDR PEDecoder::GetOffsetData(COUNT_T fileOffset, IsNullOK ok /*= NULL_NOT_OK*/) const
+{
+    CONTRACT(TADDR)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        PRECONDITION(CheckOffset(fileOffset, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if ((fileOffset == 0)&&(ok == NULL_NOT_OK))
+        RETURN NULL;
+
+    RETURN GetRvaData(OffsetToRva(fileOffset));
+}
+
+//-------------------------------------------------------------------------------
+// Lifted from "..\md\inc\mdfileformat.h"
+// (cannot #include it here because it references lot of other stuff)
+#define STORAGE_MAGIC_SIG   0x424A5342  // BSJB
+struct STORAGESIGNATURE
+{
+    ULONG       lSignature;             // "Magic" signature.
+    USHORT      iMajorVer;              // Major file version.
+    USHORT      iMinorVer;              // Minor file version.
+    ULONG       iExtraData;             // Offset to next structure of information
+    ULONG       iVersionString;         // Length of version string
+};
+typedef STORAGESIGNATURE UNALIGNED * PSTORAGESIGNATURE;
+typedef DPTR(STORAGESIGNATURE UNALIGNED) PTR_STORAGESIGNATURE;
+
+
+struct STORAGEHEADER
+{
+    BYTE        fFlags;                 // STGHDR_xxx flags.
+    BYTE        pad;
+    USHORT      iStreams;               // How many streams are there.
+};
+typedef STORAGEHEADER UNALIGNED * PSTORAGEHEADER;
+typedef DPTR(STORAGEHEADER UNALIGNED) PTR_STORAGEHEADER;
+
+
+struct STORAGESTREAM
+{
+    ULONG       iOffset;                // Offset in file for this stream.
+    ULONG       iSize;                  // Size of the file.
+    char        rcName[32];  // Start of name, null terminated.
+};
+typedef STORAGESTREAM UNALIGNED * PSTORAGESTREAM;
+typedef DPTR(STORAGESTREAM UNALIGNED) PTR_STORAGESTREAM;
+
+
+// if the stream's name is shorter than 32 bytes (incl.zero terminator),
+// the size of storage stream header is less than sizeof(STORAGESTREAM)
+// and is padded to 4-byte alignment
+inline PTR_STORAGESTREAM NextStorageStream(PTR_STORAGESTREAM pSS)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+        CANNOT_TAKE_LOCK;
+    }
+    CONTRACTL_END;
+
+    SUPPORTS_DAC;
+    TADDR pc = dac_cast<TADDR>(pSS);
+    pc += (sizeof(STORAGESTREAM) - 32 /*sizeof(STORAGESTREAM::rcName)*/ + strlen(pSS->rcName)+1+3)&~3;
+    return PTR_STORAGESTREAM(pc);
+}
+//-------------------------------------------------------------------------------
+
+
+CHECK PEDecoder::CheckCorHeader() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_CHECK_END;
+
+    if (m_flags & FLAG_COR_CHECKED)
+        CHECK_OK;
+
+    CHECK(CheckNTHeaders());
+
+    CHECK(HasCorHeader());
+
+    IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER);
+
+    CHECK(CheckDirectory(pDir, IMAGE_SCN_MEM_WRITE, NULL_NOT_OK));
+
+    CHECK(VAL32(pDir->Size) >= sizeof(IMAGE_COR20_HEADER));
+
+    IMAGE_SECTION_HEADER *section = RvaToSection(VAL32(pDir->VirtualAddress));
+    CHECK(section != NULL);
+    CHECK((section->Characteristics & VAL32(IMAGE_SCN_MEM_READ))!=0);
+
+    CHECK(CheckRva(VAL32(pDir->VirtualAddress), sizeof(IMAGE_COR20_HEADER)));
+
+    IMAGE_COR20_HEADER *pCor = GetCorHeader();
+
+    // Currently composite r2r images miss some information, for example the version is 0.0.
+    // We may want to change that to something more conforming and explicit.
+    // For now, for compatibility purposes, we will accept that as a valid format.
+    bool possiblyCompositeR2R =
+        pCor->MinorRuntimeVersion == 0 &&
+        pCor->MajorRuntimeVersion == 0;
+
+    //CHECK(((ULONGLONG)pCor & 0x3)==0);
+
+    // If the file is COM+ 1.0, which by definition has nothing the runtime can
+    // use, or if the file requires a newer version of this engine than us,
+    // it cannot be run by this engine.
+    if (!possiblyCompositeR2R)
+        CHECK(VAL16(pCor->MajorRuntimeVersion) > 1 && VAL16(pCor->MajorRuntimeVersion) <= COR_VERSION_MAJOR);
+
+#ifdef HOST_WINDOWS
+    CHECK(CheckDirectory(&pCor->MetaData, IMAGE_SCN_MEM_WRITE, NULL_NOT_OK));
+#else
+    CHECK(CheckDirectory(
+        &pCor->MetaData,
+        possiblyCompositeR2R ? 0 : IMAGE_SCN_MEM_WRITE,
+        NULL_NOT_OK));
+#endif
+    CHECK(CheckDirectory(&pCor->Resources, IMAGE_SCN_MEM_WRITE, NULL_OK));
+    CHECK(CheckDirectory(&pCor->StrongNameSignature, IMAGE_SCN_MEM_WRITE, NULL_OK));
+    CHECK(CheckDirectory(&pCor->CodeManagerTable, IMAGE_SCN_MEM_WRITE, NULL_OK));
+    CHECK(CheckDirectory(&pCor->VTableFixups, 0, NULL_OK));
+    CHECK(CheckDirectory(&pCor->ExportAddressTableJumps, 0, NULL_OK));
+    CHECK(CheckDirectory(&pCor->ManagedNativeHeader, 0, NULL_OK));
+
+    CHECK(VAL32(pCor->cb) >= offsetof(IMAGE_COR20_HEADER, ManagedNativeHeader) + sizeof(IMAGE_DATA_DIRECTORY));
+
+    DWORD validBits = COMIMAGE_FLAGS_ILONLY
+      | COMIMAGE_FLAGS_32BITREQUIRED
+      | COMIMAGE_FLAGS_TRACKDEBUGDATA
+      | COMIMAGE_FLAGS_STRONGNAMESIGNED
+      | COMIMAGE_FLAGS_NATIVE_ENTRYPOINT
+      | COMIMAGE_FLAGS_IL_LIBRARY
+      | COMIMAGE_FLAGS_32BITPREFERRED;
+
+    CHECK((pCor->Flags&VAL32(~validBits)) == 0);
+
+    // Pure IL images should not have VTable fixups or EAT jumps
+    if (IsILOnly())
+    {
+        CHECK(pCor->VTableFixups.Size == VAL32(0));
+        CHECK(pCor->ExportAddressTableJumps.Size == VAL32(0));
+        CHECK(!(pCor->Flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)));
+        //@TODO: If not an exe, check that EntryPointToken is mdNil
+    }
+    else
+    {
+        if (pCor->Flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT))
+        {
+            CHECK(CheckRva(VAL32(IMAGE_COR20_HEADER_FIELD(*pCor,EntryPointToken))));
+        }
+    }
+
+    // Strong name signed images should have a signature
+    if (IsStrongNameSigned())
+        CHECK(HasStrongNameSignature());
+
+    // IL library files (really a misnomer - these are native images or ReadyToRun images)
+    // only they can have a native image header
+    if ((pCor->Flags&VAL32(COMIMAGE_FLAGS_IL_LIBRARY)) == 0 && !possiblyCompositeR2R)
+    {
+        CHECK(VAL32(pCor->ManagedNativeHeader.Size) == 0);
+    }
+
+    // Metadata header checks
+    IMAGE_DATA_DIRECTORY *pDirMD = &pCor->MetaData;
+    COUNT_T ctMD = (COUNT_T)VAL32(pDirMD->Size);
+    TADDR   pcMD = (TADDR)GetDirectoryData(pDirMD);
+
+    if(pcMD != NULL)
+    {
+        // Storage signature checks
+        CHECK(ctMD >= sizeof(STORAGESIGNATURE));
+        PTR_STORAGESIGNATURE pStorageSig = PTR_STORAGESIGNATURE((TADDR)pcMD);
+        COUNT_T ctMDStreamSize = ctMD;          // Store MetaData stream size for later usage
+
+
+        CHECK(VAL32(pStorageSig->lSignature) == STORAGE_MAGIC_SIG);
+        COUNT_T ctSSig;
+        CHECK(ClrSafeInt<COUNT_T>::addition(sizeof(STORAGESIGNATURE), (COUNT_T)VAL32(pStorageSig->iVersionString), ctSSig));
+        CHECK(ctMD > ctSSig);
+
+        // Storage header checks
+        pcMD += ctSSig;
+
+        PTR_STORAGEHEADER pSHdr = PTR_STORAGEHEADER((TADDR)pcMD);
+
+
+        ctMD -= ctSSig;
+        CHECK(ctMD >= sizeof(STORAGEHEADER));
+        pcMD = dac_cast<TADDR>(pSHdr) + sizeof(STORAGEHEADER);
+        ctMD -= sizeof(STORAGEHEADER);
+        WORD nStreams = VAL16(pSHdr->iStreams);
+
+        // Storage streams checks (pcMD is a target pointer, so watch out)
+        PTR_STORAGESTREAM pStr = PTR_STORAGESTREAM((TADDR)pcMD);
+        PTR_STORAGESTREAM pSSOutOfRange =
+            PTR_STORAGESTREAM((TADDR)(pcMD + ctMD));
+        size_t namelen;
+        WORD iStr;
+        PTR_STORAGESTREAM pSS;
+        for(iStr = 1, pSS = pStr; iStr <= nStreams; iStr++)
+        {
+            CHECK(pSS < pSSOutOfRange);
+            CHECK(pSS + 1 <= pSSOutOfRange);
+
+            for(namelen=0; (namelen<32)&&(pSS->rcName[namelen]!=0); namelen++);
+            CHECK((0 < namelen)&&(namelen < 32));
+
+            // Forbid HOT_MODEL_STREAM
+            CHECK(strcmp(pSS->rcName, HOT_MODEL_STREAM_A) != 0);
+
+            pcMD = dac_cast<TADDR>(NextStorageStream(pSS));
+            ctMD -= (COUNT_T)(pcMD - dac_cast<TADDR>(pSS));
+
+            pSS = PTR_STORAGESTREAM((TADDR)pcMD);
+        }
+
+        // At this moment, pcMD is pointing past the last stream header
+        // and ctMD contains total size left for streams per se
+        // Now, check the offsets and sizes of streams
+        COUNT_T ctStreamsBegin = (COUNT_T)(pcMD - dac_cast<TADDR>(pStorageSig));  // min.possible offset
+        COUNT_T  ctSS, ctSSbegin, ctSSend = 0;
+        for(iStr = 1, pSS = pStr; iStr <= nStreams; iStr++,pSS = NextStorageStream(pSS))
+        {
+            ctSSbegin = (COUNT_T)VAL32(pSS->iOffset);
+            CHECK(ctStreamsBegin <= ctSSbegin);
+            CHECK(ctSSbegin < ctMDStreamSize);
+
+            ctSS = (COUNT_T)VAL32(pSS->iSize);
+            CHECK(ctMD >= ctSS);
+            CHECK(ClrSafeInt<COUNT_T>::addition(ctSSbegin, ctSS, ctSSend));
+            CHECK(ctSSend <= ctMDStreamSize);
+            ctMD -= ctSS;
+
+            // Check stream overlap
+            PTR_STORAGESTREAM pSSprior;
+            for(pSSprior=pStr; pSSprior < pSS; pSSprior = NextStorageStream(pSSprior))
+            {
+                COUNT_T ctSSprior_end = 0;
+                CHECK(ClrSafeInt<COUNT_T>::addition((COUNT_T)VAL32(pSSprior->iOffset), (COUNT_T)VAL32(pSSprior->iSize), ctSSprior_end));
+                CHECK((ctSSbegin >= ctSSprior_end)||(ctSSend <= (COUNT_T)VAL32(pSSprior->iOffset)));
+            }
+        }
+    }  //end if(pcMD != NULL)
+
+    const_cast<PEDecoder *>(this)->m_flags |= FLAG_COR_CHECKED;
+
+    CHECK_OK;
+}
+
+
+
+// This function exists to provide compatibility between two different native image
+// (NGEN) formats. In particular, the manifest metadata blob and the full metadata
+// blob swapped locations from 3.5RTM to 3.5SP1. The logic here is to look at the
+// runtime version embedded in the native image, to determine which format it is.
+IMAGE_DATA_DIRECTORY *PEDecoder::GetMetaDataHelper(METADATA_SECTION_TYPE type) const
+{
+    CONTRACT(IMAGE_DATA_DIRECTORY *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckCorHeader());
+        PRECONDITION(type == METADATA_SECTION_FULL);
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    IMAGE_DATA_DIRECTORY *pDirRet = &GetCorHeader()->MetaData;
+
+    RETURN pDirRet;
+}
+
+PTR_CVOID PEDecoder::GetMetadata(COUNT_T *pSize) const
+{
+    CONTRACT(PTR_CVOID)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckCorHeader());
+        PRECONDITION(CheckPointer(pSize, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    IMAGE_DATA_DIRECTORY *pDir = GetMetaDataHelper(METADATA_SECTION_FULL);
+
+    if (pSize != NULL)
+        *pSize = VAL32(pDir->Size);
+
+    RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
+}
+
+const void *PEDecoder::GetResources(COUNT_T *pSize) const
+{
+    CONTRACT(const void *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckCorHeader());
+        PRECONDITION(CheckPointer(pSize, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
+
+    if (pSize != NULL)
+        *pSize = VAL32(pDir->Size);
+
+    RETURN (void *)GetDirectoryData(pDir);
+}
+
+CHECK PEDecoder::CheckResource(COUNT_T offset) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(CheckCorHeader());
+    }
+    CONTRACT_CHECK_END;
+
+    IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
+
+    CHECK(CheckOverflow(VAL32(pDir->VirtualAddress), offset));
+
+    RVA rva = VAL32(pDir->VirtualAddress) + offset;
+
+    // Make sure we have at least enough data for a length
+    CHECK(CheckRva(rva, sizeof(DWORD)));
+
+    // Make sure resource is within resource section
+    CHECK(CheckBounds(VAL32(pDir->VirtualAddress), VAL32(pDir->Size),
+                      rva + sizeof(DWORD), GET_UNALIGNED_VAL32((LPVOID)GetRvaData(rva))));
+
+    CHECK_OK;
+}
+
+const void *PEDecoder::GetResource(COUNT_T offset, COUNT_T *pSize) const
+{
+    CONTRACT(const void *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckCorHeader());
+        PRECONDITION(CheckPointer(pSize, NULL_OK));
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
+
+    // 403571: Prefix complained correctly about need to always perform rva check
+    if (CheckResource(offset) == FALSE)
+        return NULL;
+
+    void * resourceBlob = (void *)GetRvaData(VAL32(pDir->VirtualAddress) + offset);
+    // Holds if CheckResource(offset) == TRUE
+    PREFIX_ASSUME(resourceBlob != NULL);
+
+     if (pSize != NULL)
+        *pSize = GET_UNALIGNED_VAL32(resourceBlob);
+
+    RETURN (const void *) ((BYTE*)resourceBlob+sizeof(DWORD));
+}
+
+BOOL PEDecoder::HasManagedEntryPoint() const
+{
+    CONTRACTL {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckCorHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    ULONG flags = GetCorHeader()->Flags;
+    return (!(flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)) &&
+            (!IsNilToken(GetEntryPointToken())));
+}
+
+ULONG PEDecoder::GetEntryPointToken() const
+{
+    CONTRACT(ULONG)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckCorHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    RETURN VAL32(IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken));
+}
+
+IMAGE_COR_VTABLEFIXUP *PEDecoder::GetVTableFixups(COUNT_T *pCount) const
+{
+    CONTRACT(IMAGE_COR_VTABLEFIXUP *)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckCorHeader());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+    IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->VTableFixups;
+
+    if (pCount != NULL)
+        *pCount = VAL32(pDir->Size)/sizeof(IMAGE_COR_VTABLEFIXUP);
+
+    RETURN PTR_IMAGE_COR_VTABLEFIXUP(GetDirectoryData(pDir));
+}
+
+CHECK PEDecoder::CheckILOnly() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    if (m_flags & FLAG_IL_ONLY_CHECKED)
+        CHECK_OK;
+
+    CHECK(CheckCorHeader());
+
+    if (HasReadyToRunHeader())
+    {
+        // Pretend R2R images are IL-only
+        const_cast<PEDecoder *>(this)->m_flags |= FLAG_IL_ONLY_CHECKED;
+        CHECK_OK;
+    }
+
+    // Allow only verifiable directories.
+
+    static int s_allowedBitmap =
+        ((1 << (IMAGE_DIRECTORY_ENTRY_IMPORT   )) |
+         (1 << (IMAGE_DIRECTORY_ENTRY_RESOURCE )) |
+         (1 << (IMAGE_DIRECTORY_ENTRY_SECURITY )) |
+         (1 << (IMAGE_DIRECTORY_ENTRY_BASERELOC)) |
+         (1 << (IMAGE_DIRECTORY_ENTRY_DEBUG    )) |
+         (1 << (IMAGE_DIRECTORY_ENTRY_IAT      )) |
+         (1 << (IMAGE_DIRECTORY_ENTRY_COMHEADER)));
+
+
+
+
+    for (UINT32 entry=0; entry<GetNumberOfRvaAndSizes(); ++entry)
+    {
+        if (Has32BitNTHeaders())
+            CheckBounds(dac_cast<PTR_CVOID>(&GetNTHeaders32()->OptionalHeader),
+                        GetNTHeaders32()->FileHeader.SizeOfOptionalHeader,
+                        dac_cast<PTR_CVOID>(GetNTHeaders32()->OptionalHeader.DataDirectory + entry),
+                        sizeof(IMAGE_DATA_DIRECTORY));
+        else
+            CheckBounds(dac_cast<PTR_CVOID>(&GetNTHeaders64()->OptionalHeader),
+                        GetNTHeaders32()->FileHeader.SizeOfOptionalHeader,
+                        dac_cast<PTR_CVOID>(GetNTHeaders64()->OptionalHeader.DataDirectory + entry),
+                        sizeof(IMAGE_DATA_DIRECTORY));
+
+        if (HasDirectoryEntry(entry))
+        {
+            CHECK((s_allowedBitmap & (1 << entry)) != 0);
+            if (entry!=IMAGE_DIRECTORY_ENTRY_SECURITY)  //ignored by OS loader
+                CHECK(CheckDirectoryEntry(entry,IMAGE_SCN_MEM_SHARED,NULL_NOT_OK));
+        }
+    }
+    if (HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT) ||
+        HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC) ||
+        FindNTHeaders()->OptionalHeader.AddressOfEntryPoint != 0)
+    {
+        // When the image is LoadLibrary'd, we whack the import, IAT directories and the entrypoint. We have to relax
+        // the verification for mapped images. Ideally, we would only do it for a post-LoadLibrary image.
+        if (!IsMapped() || (HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT) || HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC)))
+        {
+            CHECK(CheckILOnlyImportDlls());
+            CHECK(CheckILOnlyBaseRelocations());
+        }
+
+#ifdef TARGET_X86
+        if (!IsMapped())
+        {
+            CHECK(CheckILOnlyEntryPoint());
+        }
+#endif
+    }
+
+    // Check some section characteristics
+    IMAGE_NT_HEADERS *pNT = FindNTHeaders();
+    IMAGE_SECTION_HEADER *section = FindFirstSection(pNT);
+    IMAGE_SECTION_HEADER *sectionEnd = section + VAL16(pNT->FileHeader.NumberOfSections);
+    while (section < sectionEnd)
+    {
+        // Don't allow shared sections for IL-only images
+        CHECK(!(section->Characteristics & IMAGE_SCN_MEM_SHARED));
+
+        // Be sure that we have some access to the section.  Note that this test assumes that
+        //  execute or write permissions will also let us read the section.  If that is found to be an
+        //  incorrect assumption, this will need to be modified.
+        CHECK((section->Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) != 0);
+        section++;
+    }
+
+    // For EXE, check that OptionalHeader.Win32VersionValue is zero.  When this value is non-zero, GetVersionEx
+    //  returns PE supplied values, rather than native OS values; the runtime relies on knowing the actual
+    //  OS version.
+    if (!IsDll())
+    {
+        CHECK(GetWin32VersionValue() == 0);
+    }
+
+
+    const_cast<PEDecoder *>(this)->m_flags |= FLAG_IL_ONLY_CHECKED;
+
+    CHECK_OK;
+}
+
+
+CHECK PEDecoder::CheckILOnlyImportDlls() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    // The only allowed DLL Imports are MscorEE.dll:_CorExeMain,_CorDllMain
+
+#ifdef HOST_64BIT
+    // On win64, when the image is LoadLibrary'd, we whack the import and IAT directories. We have to relax
+    // the verification for mapped images. Ideally, we would only do it for a post-LoadLibrary image.
+    if (IsMapped() && !HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT))
+        CHECK_OK;
+#endif
+
+    CHECK(HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT));
+    CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_SCN_MEM_WRITE));
+
+    // Get the import directory entry
+    PIMAGE_DATA_DIRECTORY pDirEntryImport = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT);
+    CHECK(pDirEntryImport != NULL);
+    PREFIX_ASSUME(pDirEntryImport != NULL);
+
+    // There should be space for 2 entries. (mscoree and NULL)
+    CHECK(VAL32(pDirEntryImport->Size) >= (2 * sizeof(IMAGE_IMPORT_DESCRIPTOR)));
+
+    // Get the import data
+    PIMAGE_IMPORT_DESCRIPTOR pID = (PIMAGE_IMPORT_DESCRIPTOR) GetDirectoryData(pDirEntryImport);
+    CHECK(pID != NULL);
+    PREFIX_ASSUME(pID != NULL);
+
+    // Entry 0: ILT, Name, IAT must be be non-null.  Forwarder, DateTime should be NULL.
+    CHECK( IMAGE_IMPORT_DESC_FIELD(pID[0], Characteristics) != 0
+        && pID[0].TimeDateStamp == 0
+        && (pID[0].ForwarderChain == 0 || pID[0].ForwarderChain == static_cast<ULONG>(-1))
+        && pID[0].Name != 0
+        && pID[0].FirstThunk != 0);
+
+    // Entry 1: must be all nulls.
+    CHECK( IMAGE_IMPORT_DESC_FIELD(pID[1], Characteristics) == 0
+        && pID[1].TimeDateStamp == 0
+        && pID[1].ForwarderChain == 0
+        && pID[1].Name == 0
+        && pID[1].FirstThunk == 0);
+
+    // Ensure the RVA of the name plus its length is valid for this image
+    UINT nameRVA = VAL32(pID[0].Name);
+    CHECK(CheckRva(nameRVA, (COUNT_T) sizeof("mscoree.dll")));
+
+    // Make sure the name is equal to mscoree
+    CHECK(SString::_stricmp( (char *)GetRvaData(nameRVA), "mscoree.dll") == 0);
+
+    // Check the Hint/Name table.
+    CHECK(CheckILOnlyImportByNameTable(VAL32(IMAGE_IMPORT_DESC_FIELD(pID[0], OriginalFirstThunk))));
+
+    // The IAT needs to be checked only for size.
+    CHECK(CheckRva(VAL32(pID[0].FirstThunk), 2*sizeof(UINT32)));
+
+    CHECK_OK;
+}
+
+CHECK PEDecoder::CheckILOnlyImportByNameTable(RVA rva) const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    // Check if we have enough space to hold 2 DWORDS
+    CHECK(CheckRva(rva, 2*sizeof(UINT32)));
+
+    UINT32 UNALIGNED *pImportArray = (UINT32 UNALIGNED *) GetRvaData(rva);
+
+    CHECK(GET_UNALIGNED_VAL32(&pImportArray[0]) != 0);
+    CHECK(GET_UNALIGNED_VAL32(&pImportArray[1]) == 0);
+
+    UINT32 importRVA = GET_UNALIGNED_VAL32(&pImportArray[0]);
+
+    // First bit Set implies Ordinal lookup
+    CHECK((importRVA & 0x80000000) == 0);
+
+#define DLL_NAME "_CorDllMain"
+#define EXE_NAME "_CorExeMain"
+
+    static_assert_no_msg(sizeof(DLL_NAME) == sizeof(EXE_NAME));
+
+    // Check if we have enough space to hold 2 bytes +
+    // _CorExeMain or _CorDllMain and a NULL char
+    CHECK(CheckRva(importRVA, offsetof(IMAGE_IMPORT_BY_NAME, Name) + sizeof(DLL_NAME)));
+
+    IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME*) GetRvaData(importRVA);
+
+    CHECK(SString::_stricmp((char *) import->Name, DLL_NAME) == 0 || _stricmp((char *) import->Name, EXE_NAME) == 0);
+
+    CHECK_OK;
+}
+
+#ifdef TARGET_X86
+// jmp dword ptr ds:[XXXX]
+#define JMP_DWORD_PTR_DS_OPCODE { 0xFF, 0x25 }
+#define JMP_DWORD_PTR_DS_OPCODE_SIZE   2        // Size of opcode
+#define JMP_SIZE   6                            // Size of opcode + operand
+#endif
+
+CHECK PEDecoder::CheckILOnlyBaseRelocations() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC))
+    {
+        // We require base relocs for dlls.
+        CHECK(!IsDll());
+
+        CHECK((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) != 0);
+    }
+    else
+    {
+        CHECK((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) == 0);
+
+        CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_SCN_MEM_WRITE));
+
+        IMAGE_DATA_DIRECTORY *pRelocDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+
+        IMAGE_SECTION_HEADER *section = RvaToSection(VAL32(pRelocDir->VirtualAddress));
+        CHECK(section != NULL);
+        CHECK((section->Characteristics & VAL32(IMAGE_SCN_MEM_READ))!=0);
+
+        IMAGE_BASE_RELOCATION *pReloc = (IMAGE_BASE_RELOCATION *)
+          GetRvaData(VAL32(pRelocDir->VirtualAddress));
+
+        // 403569: PREfix correctly complained about pReloc being possibly NULL
+        CHECK(pReloc != NULL);
+        CHECK(VAL32(pReloc->SizeOfBlock) == VAL32(pRelocDir->Size));
+
+        UINT16 *pRelocEntry = (UINT16 *) (pReloc + 1);
+        UINT16 *pRelocEntryEnd = (UINT16 *) ((BYTE *) pReloc + VAL32(pReloc->SizeOfBlock));
+        if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_IA64))
+        {
+            // Exactly 2 Reloc records, both IMAGE_REL_BASED_DIR64
+            CHECK(VAL32(pReloc->SizeOfBlock) >= (sizeof(IMAGE_BASE_RELOCATION)+2*sizeof(UINT16)));
+            CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
+            pRelocEntry++;
+            CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
+        }
+        else
+        {
+            // Only one Reloc record is expected
+            CHECK(VAL32(pReloc->SizeOfBlock) >= (sizeof(IMAGE_BASE_RELOCATION)+sizeof(UINT16)));
+            if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_AMD64))
+                CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
+            else
+                CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_HIGHLOW << 12));
+        }
+
+        while (++pRelocEntry < pRelocEntryEnd)
+        {
+            // NULL padding entries are allowed
+            CHECK((VAL16(pRelocEntry[0]) & 0xF000) == IMAGE_REL_BASED_ABSOLUTE);
+        }
+    }
+
+    CHECK_OK;
+}
+
+#ifdef TARGET_X86
+CHECK PEDecoder::CheckILOnlyEntryPoint() const
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    CHECK(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint != 0);
+
+    if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_I386))
+    {
+        // EntryPoint should be a jmp dword ptr ds:[XXXX] instruction.
+        // XXXX should be RVA of the first and only entry in the IAT.
+
+        CHECK(CheckRva(VAL32(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint), JMP_SIZE));
+
+        BYTE *stub = (BYTE *) GetRvaData(VAL32(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint));
+
+        static const BYTE s_DllOrExeMain[] = JMP_DWORD_PTR_DS_OPCODE;
+
+        // 403570: prefix complained about stub being possibly NULL.
+        // Unsure here. PREFIX_ASSUME might be also correct as indices are
+        // verified in the above CHECK statement.
+        CHECK(stub != NULL);
+        CHECK(memcmp(stub, s_DllOrExeMain, JMP_DWORD_PTR_DS_OPCODE_SIZE) == 0);
+
+        // Verify target of jump - it should be first entry in the IAT.
+
+        PIMAGE_IMPORT_DESCRIPTOR pID =
+            (PIMAGE_IMPORT_DESCRIPTOR) GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_IMPORT);
+
+        UINT32 va = * (UINT32 *) (stub + JMP_DWORD_PTR_DS_OPCODE_SIZE);
+
+        CHECK(VAL32(pID[0].FirstThunk) == (va - (SIZE_T) GetPreferredBase()));
+    }
+
+    CHECK_OK;
+}
+#endif // TARGET_X86
+
+
+bool ReadResourceDirectoryHeader(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rva, IMAGE_RESOURCE_DIRECTORY_ENTRY** ppDirectoryEntries, IMAGE_RESOURCE_DIRECTORY **ppResourceDirectory)
+{
+    if (!pDecoder->CheckRva(rva, sizeof(IMAGE_RESOURCE_DIRECTORY)))
+    {
+        return false;
+    }
+
+    *ppResourceDirectory = (IMAGE_RESOURCE_DIRECTORY *)pDecoder->GetRvaData(rva);
+
+    // Check to see if entire resource directory is accessible
+    if (!pDecoder->CheckRva(rva + sizeof(IMAGE_RESOURCE_DIRECTORY),
+                       (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * (*ppResourceDirectory)->NumberOfNamedEntries) +
+                       (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * (*ppResourceDirectory)->NumberOfIdEntries)))
+    {
+        return false;
+    }
+
+    *ppDirectoryEntries = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)pDecoder->GetRvaData(rva + sizeof(IMAGE_RESOURCE_DIRECTORY));
+    return true;
+}
+
+bool ReadNameFromResourceDirectoryEntry(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries, DWORD iEntry, DWORD *pNameUInt, WCHAR **pNameStr)
+{
+    *pNameStr = NULL;
+    *pNameUInt = 0;
+
+    if (!IS_INTRESOURCE(pDirectoryEntries[iEntry].Name))
+    {
+        DWORD entryName = pDirectoryEntries[iEntry].Name;
+        if (!(entryName & IMAGE_RESOURCE_NAME_IS_STRING))
+            return false;
+        DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection;
+
+        if (!pDecoder->CheckRva(entryNameRva, sizeof(WORD)))
+            return false;
+
+        size_t entryNameLen = *(WORD*)pDecoder->GetRvaData(entryNameRva);
+        if (!pDecoder->CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
+            return false;
+        *pNameStr = new(nothrow) WCHAR[entryNameLen + 1];
+        if ((*pNameStr) == NULL)
+            return false;
+        memcpy((*pNameStr), (WCHAR*)pDecoder->GetRvaData(entryNameRva + sizeof(WORD)), entryNameLen * sizeof(WCHAR));
+        (*pNameStr)[entryNameLen] = 0;
+    }
+    else
+    {
+        DWORD name = pDirectoryEntries[iEntry].Name;
+        if (!IS_INTRESOURCE(name))
+            return false;
+
+        *pNameUInt = name;
+    }
+
+    return true;
+}
+
+DWORD ReadResourceDirectory(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rva, LPCWSTR name, BOOL *pisDirectory)
+{
+    *pisDirectory = FALSE;
+
+    IMAGE_RESOURCE_DIRECTORY* pResourceDirectory;
+    IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries;
+    if (!ReadResourceDirectoryHeader(pDecoder, rvaOfResourceSection, rva, &pDirectoryEntries, &pResourceDirectory))
+    {
+        return 0;
+    }
+
+    // A fast implementation of resource lookup uses a binary search, but our needs are simple, and a linear search
+    // is easier to prove correct, so do that instead.
+    DWORD iEntryCount = (DWORD)pResourceDirectory->NumberOfNamedEntries + (DWORD)pResourceDirectory->NumberOfIdEntries;
+
+    for (DWORD iEntry = 0; iEntry < iEntryCount; iEntry++)
+    {
+        BOOL foundEntry = FALSE;
+
+        if (IS_INTRESOURCE(name))
+        {
+            // name is id
+            if (pDirectoryEntries[iEntry].Name == (DWORD)(SIZE_T)name)
+                foundEntry = TRUE;
+        }
+        else
+        {
+            // name is string
+            DWORD entryName = pDirectoryEntries[iEntry].Name;
+            if (!(entryName & IMAGE_RESOURCE_NAME_IS_STRING))
+                continue;
+
+            DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection;
+
+            if (!pDecoder->CheckRva(entryNameRva, sizeof(WORD)))
+                return 0;
+
+            size_t entryNameLen = *(WORD*)pDecoder->GetRvaData(entryNameRva);
+            if (wcslen(name) != entryNameLen)
+                continue;
+
+            if (!pDecoder->CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
+                return 0;
+
+            if (memcmp((WCHAR*)pDecoder->GetRvaData(entryNameRva + sizeof(WORD)), name, entryNameLen * sizeof(WCHAR)) == 0)
+                foundEntry = TRUE;
+        }
+
+        if (!foundEntry)
+            continue;
+
+        *pisDirectory = !!(pDirectoryEntries[iEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY);
+        DWORD offsetToData = pDirectoryEntries[iEntry].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY;
+        DWORD dataRva = rvaOfResourceSection + offsetToData;
+        return dataRva;
+    }
+
+    return 0;
+}
+
+DWORD ReadResourceDataEntry(const PEDecoder *pDecoder, DWORD rva, COUNT_T *pSize)
+{
+    *pSize = 0;
+
+    if (!pDecoder->CheckRva(rva, sizeof(IMAGE_RESOURCE_DATA_ENTRY)))
+    {
+        return 0;
+    }
+
+    IMAGE_RESOURCE_DATA_ENTRY *pDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)pDecoder->GetRvaData(rva);
+    *pSize = pDataEntry->Size;
+    return pDataEntry->OffsetToData;
+}
+
+void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSize /*=NULL*/) const
+{
+    CONTRACTL {
+        INSTANCE_CHECK;
+        PRECONDITION(IsMapped());
+        NOTHROW;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    COUNT_T sizeUnused = 0; // Use this variable if pSize is null
+    if (pSize == NULL)
+        pSize = &sizeUnused;
+
+    *pSize = 0;
+
+    if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
+        return NULL;
+
+    COUNT_T resourceDataSize = 0;
+    IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
+
+    if (pDir->VirtualAddress == 0)
+        return NULL;
+
+    BOOL isDirectory = FALSE;
+    DWORD nameTableRva = ReadResourceDirectory(this, pDir->VirtualAddress, pDir->VirtualAddress, lpType, &isDirectory);
+
+    if (!isDirectory)
+        return NULL;
+
+    if (nameTableRva == 0)
+        return NULL;
+
+    DWORD languageTableRva = ReadResourceDirectory(this, pDir->VirtualAddress, nameTableRva, lpName, &isDirectory);
+    if (!isDirectory)
+        return NULL;
+
+    if (languageTableRva == 0)
+        return NULL;
+
+    // This api is designed to find resources with LANGID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
+    // This translates to LANGID 0 as the initial lookup point, which is sufficient for the needs of this api at this time
+    // (FindResource in the Windows api implements a large number of fallback paths which this api does not implement)
+
+    DWORD resourceDataEntryRva = ReadResourceDirectory(this, pDir->VirtualAddress, languageTableRva, 0, &isDirectory);
+    if (isDirectory) // This must not be a resource directory itself
+        return NULL;
+
+    if (resourceDataEntryRva == 0)
+        return NULL;
+
+    DWORD resourceDataRva = ReadResourceDataEntry(this, resourceDataEntryRva, pSize);
+    if (!CheckRva(resourceDataRva, *pSize))
+    {
+        *pSize = 0;
+        return NULL;
+    }
+
+    return (void*)GetRvaData(resourceDataRva);
+}
+
+typedef bool (*PEDecoder_EnumerateResourceTableFunction)(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context);
+
+struct ResourceEnumerateNamesState
+{
+    PEDecoder_ResourceNamesCallbackFunction namesCallback;
+    PEDecoder_ResourceCallbackFunction langIDcallback;
+    void *context;
+    LPCWSTR nameType;
+    LPCWSTR nameName;
+    PEDecoder_EnumerateResourceTableFunction callbackPerName;
+    PEDecoder_EnumerateResourceTableFunction callbackPerLangID;
+};
+
+struct ResourceEnumerateTypesState
+{
+    PEDecoder_ResourceTypesCallbackFunction callback;
+    void *context;
+    LPCWSTR nameType;
+};
+
+bool EnumerateWin32ResourceTable(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rvaOfResourceTable, PEDecoder_EnumerateResourceTableFunction resourceTableEnumerator, void *context)
+{
+    IMAGE_RESOURCE_DIRECTORY* pResourceDirectory;
+    IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries;
+    if (!ReadResourceDirectoryHeader(pDecoder, rvaOfResourceSection, rvaOfResourceTable, &pDirectoryEntries, &pResourceDirectory))
+    {
+        return false;
+    }
+
+    DWORD iEntryCount = (DWORD)pResourceDirectory->NumberOfNamedEntries + (DWORD)pResourceDirectory->NumberOfIdEntries;
+
+    for (DWORD iEntry = 0; iEntry < iEntryCount; iEntry++)
+    {
+        DWORD nameUInt;
+        NewArrayHolder<WCHAR> nameString;
+        if (!ReadNameFromResourceDirectoryEntry(pDecoder, rvaOfResourceSection, pDirectoryEntries, iEntry, &nameUInt, &nameString))
+            return false;
+
+        LPCWSTR name = MAKEINTRESOURCEW(nameUInt);
+        if (nameString != NULL)
+            name = &nameString[0];
+
+        bool isDirectory = !!(pDirectoryEntries[iEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY);
+        DWORD offsetToData = pDirectoryEntries[iEntry].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY;
+        DWORD dataRva = rvaOfResourceSection + offsetToData;
+
+        if (!resourceTableEnumerator(pDecoder, rvaOfResourceSection, isDirectory, name, dataRva, context))
+            return false;
+    }
+
+    return true;
+}
+
+bool DoesResourceNameMatch(LPCWSTR nameA, LPCWSTR nameB)
+{
+    bool foundEntry = false;
+
+    if (IS_INTRESOURCE(nameA))
+    {
+        // name is id
+        if (nameA == nameB)
+            foundEntry = true;
+    }
+    else
+    {
+        // name is a string.
+
+        // Check for name enumerated is an id. If so, it doesn't match, skip to next.
+        if (IS_INTRESOURCE(nameB))
+            return false;
+        else
+            foundEntry = !wcscmp(nameB, nameA);
+    }
+
+    return foundEntry;
+}
+
+bool EnumerateLangIDs(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+    ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
+    if (isDirectory)
+        return false;
+
+    // Only LangIDs are permitted here
+    if (!IS_INTRESOURCE(name))
+        return false;
+
+    if (dataRVA == 0)
+        return false;
+
+    COUNT_T cbData;
+    DWORD resourceDataRva = ReadResourceDataEntry(pDecoder, dataRVA, &cbData);
+    if (!pDecoder->CheckRva(resourceDataRva, cbData))
+    {
+        return false;
+    }
+
+    BYTE *pData = (BYTE*)pDecoder->GetRvaData(resourceDataRva);
+
+    return state->langIDcallback(state->nameName, state->nameType, (DWORD)(uintptr_t)name, pData, cbData, state->context);
+}
+
+
+bool EnumerateNames(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+    ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
+    if (!isDirectory)
+        return false;
+
+    state->nameName = name;
+    return state->namesCallback(state->nameName, state->nameType, state->context);
+}
+
+bool EnumerateNamesForLangID(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+    ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
+    if (!isDirectory)
+        return false;
+
+    bool foundEntry = DoesResourceNameMatch(state->nameName, name);
+
+    if (foundEntry)
+        return EnumerateWin32ResourceTable(pDecoder, rvaOfResourceSection, dataRVA, state->callbackPerLangID, context);
+    else
+        return true; // Keep scanning
+}
+
+
+bool EnumerateTypes(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+    ResourceEnumerateTypesState *state = (ResourceEnumerateTypesState*)context;
+    if (!isDirectory)
+        return false;
+
+    state->nameType = name;
+    return state->callback(name, state->context);
+}
+
+bool EnumerateTypesForNames(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+    ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
+    if (!isDirectory)
+        return false;
+
+    bool foundEntry = DoesResourceNameMatch(state->nameType, name);
+
+    if (foundEntry)
+        return EnumerateWin32ResourceTable(pDecoder, rvaOfResourceSection, dataRVA, state->callbackPerName, context);
+    else
+        return true; // Keep scanning
+}
+
+
+bool PEDecoder::EnumerateWin32ResourceTypes(PEDecoder_ResourceTypesCallbackFunction callback, void* context) const
+{
+    if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
+        return true;
+
+    COUNT_T resourceDataSize = 0;
+    IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
+
+    if (pDir->VirtualAddress == 0)
+        return true;
+
+    DWORD rvaOfResourceSection = pDir->VirtualAddress;
+
+    ResourceEnumerateTypesState state;
+    state.context = context;
+    state.callback = callback;
+
+    return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypes, &state);
+}
+
+bool PEDecoder::EnumerateWin32ResourceNames(LPCWSTR lpType, PEDecoder_ResourceNamesCallbackFunction callback, void* context) const
+{
+    if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
+        return true;
+
+    COUNT_T resourceDataSize = 0;
+    IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
+
+    if (pDir->VirtualAddress == 0)
+        return true;
+
+    DWORD rvaOfResourceSection = pDir->VirtualAddress;
+
+    ResourceEnumerateNamesState state;
+    state.context = context;
+    state.namesCallback = callback;
+    state.langIDcallback = NULL;
+    state.nameType = lpType;
+    state.nameName = NULL;
+    state.callbackPerName = EnumerateNames;
+    state.callbackPerLangID = NULL;
+
+    return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypesForNames, &state);
+}
+
+bool PEDecoder::EnumerateWin32Resources(LPCWSTR lpName, LPCWSTR lpType, PEDecoder_ResourceCallbackFunction callback, void* context) const
+{
+    if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
+        return true;
+
+    COUNT_T resourceDataSize = 0;
+    IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
+
+    if (pDir->VirtualAddress == 0)
+        return true;
+
+    DWORD rvaOfResourceSection = pDir->VirtualAddress;
+
+    ResourceEnumerateNamesState state;
+    state.context = context;
+    state.namesCallback = NULL;
+    state.langIDcallback = callback;
+    state.nameType = lpType;
+    state.nameName = lpName;
+    state.callbackPerName = EnumerateNamesForLangID;
+    state.callbackPerLangID = EnumerateLangIDs;
+
+    return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypesForNames, &state);
+}
+
+READYTORUN_HEADER * PEDecoder::FindReadyToRunHeader() const
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
+
+    if (VAL32(pDir->Size) >= sizeof(READYTORUN_HEADER) && CheckDirectory(pDir))
+    {
+        PTR_READYTORUN_HEADER pHeader = PTR_READYTORUN_HEADER((TADDR)GetDirectoryData(pDir));
+        if (pHeader->Signature == READYTORUN_SIGNATURE)
+        {
+            const_cast<PEDecoder*>(this)->m_pReadyToRunHeader = pHeader;
+            return pHeader;
+        }
+    }
+
+    const_cast<PEDecoder *>(this)->m_flags |= FLAG_HAS_NO_READYTORUN_HEADER;
+    return NULL;
+}
+
+PTR_VOID PEDecoder::GetExport(LPCSTR exportName) const
+{
+    // Get the export directory entry
+    PIMAGE_DATA_DIRECTORY pExportDirectoryEntry = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_EXPORT);
+    if (pExportDirectoryEntry->VirtualAddress == 0 || pExportDirectoryEntry->Size == 0)
+    {
+        return NULL;
+    }
+
+    PTR_IMAGE_EXPORT_DIRECTORY pExportDir = dac_cast<PTR_IMAGE_EXPORT_DIRECTORY>(GetDirectoryData(pExportDirectoryEntry));
+
+    uint32_t namePointerCount = VAL32(pExportDir->NumberOfNames);
+    uint32_t addressTableRVA = VAL32(pExportDir->AddressOfFunctions);
+    uint32_t ordinalTableRVA = VAL32(pExportDir->AddressOfNameOrdinals);
+    uint32_t nameTableRVA = VAL32(pExportDir->AddressOfNames);
+
+    for (uint32_t nameIndex = 0; nameIndex < namePointerCount; nameIndex++)
+    {
+        uint32_t namePointerRVA = *dac_cast<PTR_UINT32>(GetRvaData(nameTableRVA + sizeof(uint32_t) * nameIndex));
+        if (namePointerRVA != 0)
+        {
+            const char *namePointer = dac_cast<PTR_CSTR>(GetRvaData(namePointerRVA));
+            if (!strcmp(namePointer, exportName))
+            {
+                uint16_t ordinalForNamedExport = *dac_cast<PTR_UINT16>(GetRvaData(ordinalTableRVA + sizeof(uint16_t) * nameIndex));
+                uint32_t exportRVA = *dac_cast<PTR_UINT32>(GetRvaData(addressTableRVA + sizeof(uint32_t) * ordinalForNamedExport));
+                return dac_cast<PTR_VOID>(GetRvaData(exportRVA));
+            }
+        }
+    }
+
+    return NULL;
+}
+
+//
+// code:PEDecoder::CheckILMethod and code:PEDecoder::ComputeILMethodSize really belong to
+// file:..\inc\corhlpr.cpp. Unfortunately, corhlpr.cpp is public header file that cannot be
+// properly DACized and have other dependencies on the rest of the CLR.
+//
+
+typedef DPTR(COR_ILMETHOD_TINY) PTR_COR_ILMETHOD_TINY;
+typedef DPTR(COR_ILMETHOD_FAT) PTR_COR_ILMETHOD_FAT;
+typedef DPTR(COR_ILMETHOD_SECT_SMALL) PTR_COR_ILMETHOD_SECT_SMALL;
+typedef DPTR(COR_ILMETHOD_SECT_FAT) PTR_COR_ILMETHOD_SECT_FAT;
+
+CHECK PEDecoder::CheckILMethod(RVA rva)
+{
+    CONTRACT_CHECK
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_CHECK_END;
+
+    //
+    // Incrementaly validate that the entire IL method body is within the bounds of the image
+    //
+
+    // We need to have at least the tiny header
+    CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_TINY)));
+
+    TADDR pIL = GetRvaData(rva);
+
+    PTR_COR_ILMETHOD_TINY pMethodTiny = PTR_COR_ILMETHOD_TINY(pIL);
+
+    if (pMethodTiny->IsTiny())
+    {
+        // Tiny header has no optional sections - we are done.
+        CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_TINY) + pMethodTiny->GetCodeSize()));
+        CHECK_OK;
+    }
+
+    //
+    // Fat header
+    //
+
+    CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_FAT)));
+
+    PTR_COR_ILMETHOD_FAT pMethodFat = PTR_COR_ILMETHOD_FAT(pIL);
+
+    CHECK(pMethodFat->IsFat());
+
+    S_UINT32 codeEnd = S_UINT32(4) * S_UINT32(pMethodFat->GetSize()) + S_UINT32(pMethodFat->GetCodeSize());
+    CHECK(!codeEnd.IsOverflow());
+
+    // Check minimal size of the header
+    CHECK(pMethodFat->GetSize() >= (sizeof(COR_ILMETHOD_FAT) / 4));
+
+    CHECK(CheckRva(rva, codeEnd.Value()));
+
+    if (!pMethodFat->More())
+    {
+        CHECK_OK;
+    }
+
+    // DACized copy of code:COR_ILMETHOD_FAT::GetSect
+    TADDR pSect = AlignUp(pIL + codeEnd.Value(), 4);
+
+    //
+    // Optional sections following the code
+    //
+
+    for (;;)
+    {
+        CHECK(CheckRva(rva, UINT32(pSect - pIL) + sizeof(IMAGE_COR_ILMETHOD_SECT_SMALL)));
+
+        PTR_COR_ILMETHOD_SECT_SMALL pSectSmall = PTR_COR_ILMETHOD_SECT_SMALL(pSect);
+
+        UINT32 sectSize;
+
+        if (pSectSmall->IsSmall())
+        {
+            sectSize = pSectSmall->DataSize;
+
+            // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
+            if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
+                sectSize = COR_ILMETHOD_SECT_EH_SMALL::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL));
+        }
+        else
+        {
+            CHECK(CheckRva(rva, UINT32(pSect - pIL) + sizeof(IMAGE_COR_ILMETHOD_SECT_FAT)));
+
+            PTR_COR_ILMETHOD_SECT_FAT pSectFat = PTR_COR_ILMETHOD_SECT_FAT(pSect);
+
+            sectSize = pSectFat->GetDataSize();
+
+            // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
+            if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
+                sectSize = COR_ILMETHOD_SECT_EH_FAT::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
+        }
+
+        // Section has to be non-empty to avoid infinite loop below
+        CHECK(sectSize > 0);
+
+        S_UINT32 sectEnd = S_UINT32(UINT32(pSect - pIL)) + S_UINT32(sectSize);
+        CHECK(!sectEnd.IsOverflow());
+
+        CHECK(CheckRva(rva, sectEnd.Value()));
+
+        if (!pSectSmall->More())
+        {
+            CHECK_OK;
+        }
+
+        // DACized copy of code:COR_ILMETHOD_FAT::Next
+        pSect = AlignUp(pIL + sectEnd.Value(), 4);
+    }
+}
+
+//
+// Compute size of IL blob. Assumes that the IL is within the bounds of the image - make sure
+// to call code:PEDecoder::CheckILMethod before calling this method.
+//
+// code:PEDecoder::ComputeILMethodSize is DACized duplicate of code:COR_ILMETHOD_DECODER::GetOnDiskSize.
+// code:MethodDesc::GetILHeader contains debug-only check that ensures that both implementations
+// are in sync.
+//
+
+SIZE_T PEDecoder::ComputeILMethodSize(TADDR pIL)
+{
+    CONTRACTL {
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    } CONTRACTL_END;
+
+    //
+    // Mirror flow of code:PEDecoder::CheckILMethod, except for the range checks
+    //
+
+    PTR_COR_ILMETHOD_TINY pMethodTiny = PTR_COR_ILMETHOD_TINY(pIL);
+
+    if (pMethodTiny->IsTiny())
+    {
+        return sizeof(IMAGE_COR_ILMETHOD_TINY) + pMethodTiny->GetCodeSize();
+    }
+
+    PTR_COR_ILMETHOD_FAT pMethodFat = PTR_COR_ILMETHOD_FAT(pIL);
+
+    UINT32 codeEnd = 4 * pMethodFat->GetSize() + pMethodFat->GetCodeSize();
+
+    if (!pMethodFat->More())
+    {
+        return codeEnd;
+    }
+
+    // DACized copy of code:COR_ILMETHOD_FAT::GetSect
+    TADDR pSect = AlignUp(pIL + codeEnd, 4);
+
+    for (;;)
+    {
+        PTR_COR_ILMETHOD_SECT_SMALL pSectSmall = PTR_COR_ILMETHOD_SECT_SMALL(pSect);
+
+        UINT32 sectSize;
+
+        if (pSectSmall->IsSmall())
+        {
+            sectSize = pSectSmall->DataSize;
+
+            // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
+            if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
+                sectSize = COR_ILMETHOD_SECT_EH_SMALL::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL));
+        }
+        else
+        {
+            PTR_COR_ILMETHOD_SECT_FAT pSectFat = PTR_COR_ILMETHOD_SECT_FAT(pSect);
+
+            sectSize = pSectFat->GetDataSize();
+
+            // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
+            if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
+                sectSize = COR_ILMETHOD_SECT_EH_FAT::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
+        }
+
+        UINT32 sectEnd = UINT32(pSect - pIL) + sectSize;
+
+        if (!pSectSmall->More() || (sectSize == 0))
+        {
+            return sectEnd;
+        }
+
+        // DACized copy of code:COR_ILMETHOD_FAT::Next
+        pSect = AlignUp(pIL + sectEnd, 4);
+    }
+}
+
+//
+// GetDebugDirectoryEntry - return the debug directory entry at the specified index
+//
+// Arguments:
+//   index    The 0-based index of the entry to return.  Usually this is just 0,
+//            but there can be multiple debug directory entries in a PE file.
+//
+// Return value:
+//   A pointer to the IMAGE_DEBUG_DIRECTORY in the PE file for the specified index,
+//   or NULL if it doesn't exist.
+//
+// Note that callers on untrusted input are required to validate the debug directory
+// first by calling CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG) (possibly
+// indirectly via one of the CheckILOnly* functions).
+//
+PTR_IMAGE_DEBUG_DIRECTORY PEDecoder::GetDebugDirectoryEntry(UINT index) const
+{
+    CONTRACT(PTR_IMAGE_DEBUG_DIRECTORY)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckNTHeaders());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG))
+    {
+        RETURN NULL;
+    }
+
+    // Get a pointer to the contents and size of the debug directory
+    // Also validates (in CHK builds) that this is all within one section, which the
+    // caller should have already validated if they don't trust the context of this PE file.
+    COUNT_T cbDebugDir;
+    TADDR taDebugDir = GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_DEBUG, &cbDebugDir);
+
+    // Check if the specified directory entry exists (based on the size of the directory)
+    // Note that the directory size should be an even multiple of the entry size, but we
+    // just round-down because we need to be resiliant (without asserting) to corrupted /
+    // fuzzed PE files.
+    UINT cNumEntries = cbDebugDir / sizeof(IMAGE_DEBUG_DIRECTORY);
+    if (index >= cNumEntries)
+    {
+        RETURN NULL;    // index out of range
+    }
+
+    // Get the debug directory entry at the specified index.
+    PTR_IMAGE_DEBUG_DIRECTORY pDebugEntry = dac_cast<PTR_IMAGE_DEBUG_DIRECTORY>(taDebugDir);
+    pDebugEntry += index;   // offset from the first entry to the requested entry
+    RETURN pDebugEntry;
+}
+
+
+PTR_CVOID PEDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const
+{
+    CONTRACT(PTR_CVOID)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(HasReadyToRunHeader());
+        POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // TBD - may not store metadata for IJW
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    IMAGE_DATA_DIRECTORY *pDir = NULL;
+    {
+        READYTORUN_HEADER * pHeader = GetReadyToRunHeader();
+
+        PTR_READYTORUN_SECTION pSections = dac_cast<PTR_READYTORUN_SECTION>(dac_cast<TADDR>(pHeader) + sizeof(READYTORUN_HEADER));
+        for (DWORD i = 0; i < pHeader->CoreHeader.NumberOfSections; i++)
+        {
+            // Verify that section types are sorted
+            _ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type));
+
+            READYTORUN_SECTION * pSection = pSections + i;
+            if (pSection->Type == ReadyToRunSectionType::ManifestMetadata)
+            {
+                // Set pDir to the address of the manifest metadata section
+                pDir = &pSection->Section;
+                break;
+            }
+        }
+
+        // ReadyToRun file without large version bubble support doesn't have the ManifestMetadata
+        if (pDir == NULL)
+        {
+            if (pSize != NULL)
+            {
+                *pSize = 0;
+            }
+
+            RETURN NULL;
+        }
+    }
+
+    if (pSize != NULL)
+        *pSize = VAL32(pDir->Size);
+
+    RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
+}
+
+// Get the SizeOfStackReserve and SizeOfStackCommit from the PE file that was used to create
+// the calling process (.exe file).
+void PEDecoder::GetEXEStackSizes(SIZE_T *PE_SizeOfStackReserve, SIZE_T *PE_SizeOfStackCommit) const
+{
+    CONTRACTL {
+        PRECONDITION(!IsDll()); // This routine should only be called for EXE files.
+        NOTHROW;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    * PE_SizeOfStackReserve = GetSizeOfStackReserve();
+    * PE_SizeOfStackCommit  = GetSizeOfStackCommit();
+}
+
+BOOL PEDecoder::HasNativeEntryPoint() const
+{
+    CONTRACTL {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(CheckCorHeader());
+    } CONTRACTL_END;
+
+    ULONG flags = GetCorHeader()->Flags;
+    return ((flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)) &&
+            (IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken) != VAL32(0)));
+}
+
+void *PEDecoder::GetNativeEntryPoint() const
+{
+    CONTRACT (void *) {
+        INSTANCE_CHECK;
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(CheckCorHeader());
+        PRECONDITION(HasNativeEntryPoint());
+        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+    } CONTRACT_END;
+
+    RETURN ((void *) GetRvaData((RVA)VAL32(IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken))));
+}
+
+#ifdef DACCESS_COMPILE
+
+void
+PEDecoder::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
+                             bool enumThis)
+{
+    SUPPORTS_DAC;
+    if (enumThis)
+    {
+        DAC_ENUM_DTHIS();
+    }
+
+    DacEnumMemoryRegion((TADDR)m_base, sizeof(IMAGE_DOS_HEADER));
+    m_pNTHeaders.EnumMem();
+    m_pCorHeader.EnumMem();
+    m_pReadyToRunHeader.EnumMem();
+
+    if (HasNTHeaders())
+    {
+        // resource file does not have NT Header.
+        //
+        // we also need to write out section header.
+        DacEnumMemoryRegion(dac_cast<TADDR>(FindFirstSection()), sizeof(IMAGE_SECTION_HEADER) * GetNumberOfSections());
+    }
+}
+
+#endif // #ifdef DACCESS_COMPILE
+
+//
+//  MethodSectionIterator class is used to iterate hot (or) cold method section in an ngen image.
+//  Also used to iterate over jitted methods in the code heap
+//
+MethodSectionIterator::MethodSectionIterator(const void *code, SIZE_T codeSize,
+                                             const void *codeTable, SIZE_T codeTableSize)
+{
+    //For DAC builds,we'll read the table one DWORD at a time.  Note that m_code IS
+    //NOT a host pointer.
+    m_codeTableStart = PTR_DWORD(TADDR(codeTable));
+    m_codeTable = m_codeTableStart;
+    _ASSERTE((codeTableSize % sizeof(DWORD)) == 0);
+    m_codeTableEnd = m_codeTableStart + (codeTableSize / sizeof(DWORD));
+    m_code = (BYTE *) code;
+    m_current = NULL;
+
+
+    if (m_codeTable < m_codeTableEnd)
+    {
+        m_dword = *m_codeTable++;
+        m_index = 0;
+    }
+    else
+    {
+        m_index = NIBBLES_PER_DWORD;
+    }
+}
+
+BOOL MethodSectionIterator::Next()
+{
+    while (m_codeTable < m_codeTableEnd || m_index < (int)NIBBLES_PER_DWORD)
+    {
+        while (m_index++ < (int)NIBBLES_PER_DWORD)
+        {
+            int nibble = (m_dword & HIGHEST_NIBBLE_MASK)>>HIGHEST_NIBBLE_BIT;
+            m_dword <<= NIBBLE_SIZE;
+
+            if (nibble != 0)
+            {
+                // We have found a method start
+                m_current = m_code + ((nibble-1)*CODE_ALIGN);
+                m_code += BYTES_PER_BUCKET;
+                return TRUE;
+            }
+
+            m_code += BYTES_PER_BUCKET;
+        }
+
+        if (m_codeTable < m_codeTableEnd)
+        {
+            m_dword = *m_codeTable++;
+            m_index = 0;
+        }
+    }
+    return FALSE;
+}
diff --git a/src/utilcode/safewrap.cpp b/src/utilcode/safewrap.cpp
new file mode 100644 (file)
index 0000000..2090386
--- /dev/null
@@ -0,0 +1,336 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// SafeWrap.cpp
+//
+
+//
+// This file contains wrapper functions for Win32 API's that take SStrings
+// and use CLR-safe holders.
+//
+// See guidelines in SafeWrap.h for writing these APIs.
+//*****************************************************************************
+
+#include "stdafx.h"                     // Precompiled header key.
+#include "safewrap.h"
+#include "winwrap.h"                    // Header for macros and functions.
+#include "utilcode.h"
+#include "holder.h"
+#include "sstring.h"
+#include "ex.h"
+
+//-----------------------------------------------------------------------------
+// Get the current directory.
+// On success, returns true and sets 'Value' to unicode version of cur dir.
+// Throws on all failures. This should mainly be oom.
+//-----------------------------------------------------------------------------
+void ClrGetCurrentDirectory(SString & value)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    // Get size needed
+    DWORD len = WszGetCurrentDirectory(value);
+
+
+    // An actual API failure in GetCurrentDirectory failure should be very rare, so we'll throw on those.
+    if (len == 0)
+    {
+        ThrowLastError();
+    }
+}
+
+//-----------------------------------------------------------------------------
+// Reads an environment variable into the given SString.
+// Returns true on success, false on failure (includes if the var does not exist).
+// May throw on oom.
+//-----------------------------------------------------------------------------
+bool ClrGetEnvironmentVariable(LPCSTR szEnvVarName, SString & value)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+
+        PRECONDITION(szEnvVarName != NULL);
+    }
+    CONTRACTL_END;
+
+    // First read it to get the needed length.
+    DWORD lenWithNull = GetEnvironmentVariableA(szEnvVarName, NULL, 0);
+    if (lenWithNull == 0)
+    {
+        return false;
+    }
+
+    // Now read it for content.
+    char * pCharBuf = value.OpenANSIBuffer(lenWithNull);
+    DWORD lenWithoutNull = GetEnvironmentVariableA(szEnvVarName, pCharBuf, lenWithNull);
+    value.CloseBuffer(lenWithoutNull);
+
+    if (lenWithoutNull != (lenWithNull - 1))
+    {
+        // Env var must have changed underneath us.
+        return false;
+    }
+    return true;
+}
+
+void ClrGetModuleFileName(HMODULE hModule, SString & value)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    WCHAR * pCharBuf = value.OpenUnicodeBuffer(_MAX_PATH);
+    DWORD numChars = GetModuleFileNameW(hModule, pCharBuf, _MAX_PATH);
+    value.CloseBuffer(numChars);
+}
+
+ClrDirectoryEnumerator::ClrDirectoryEnumerator(LPCWSTR pBaseDirectory, LPCWSTR pMask /*= W("*")*/)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    StackSString strMask(pBaseDirectory);
+    SString s(SString::Literal, DIRECTORY_SEPARATOR_STR_W);
+    if (!strMask.EndsWith(s))
+    {
+        strMask.Append(s);
+    }
+    strMask.Append(pMask);
+    dirHandle = WszFindFirstFile(strMask, &data);
+
+    if (dirHandle == INVALID_HANDLE_VALUE)
+    {
+        DWORD dwLastError = GetLastError();
+
+        // We either ran out of files, or didnt encounter even a single file matching the
+        // search mask. If it is neither of these conditions, then convert the error to an exception
+        // and raise it.
+        if ((dwLastError != ERROR_FILE_NOT_FOUND) && (dwLastError != ERROR_NO_MORE_FILES))
+            ThrowLastError();
+    }
+
+    fFindNext = FALSE;
+}
+
+bool ClrDirectoryEnumerator::Next()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    if (dirHandle == INVALID_HANDLE_VALUE)
+        return FALSE;
+
+    for (;;)
+    {
+        if (fFindNext)
+        {
+            if (!WszFindNextFile(dirHandle, &data))
+            {
+                if (GetLastError() != ERROR_NO_MORE_FILES)
+                    ThrowLastError();
+
+                return FALSE;
+            }
+        }
+        else
+        {
+            fFindNext  = TRUE;
+        }
+
+        // Skip junk
+        if (wcscmp(data.cFileName, W(".")) != 0 && wcscmp(data.cFileName, W("..")) != 0)
+            return TRUE;
+    }
+}
+
+DWORD ClrReportEvent(
+    LPCWSTR     pEventSource,
+    WORD        wType,
+    WORD        wCategory,
+    DWORD       dwEventID,
+    PSID        lpUserSid,
+    WORD        wNumStrings,
+    LPCWSTR     *lpStrings,
+    DWORD       dwDataSize /*=0*/,
+    LPVOID      lpRawData /*=NULL*/)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+#ifndef TARGET_UNIX
+    HANDLE h = ::RegisterEventSourceW(
+        NULL, // uses local computer
+        pEventSource);
+    if (h == NULL)
+    {
+        // Return the error code to the caller so that
+        // appropriate asserts/logging can be done
+        // incase of errors like event log being full
+        return GetLastError();
+    }
+
+    // Every event id should have matching description in dlls\shim\eventmsg.mc.  This allows
+    // event view to know how to display message.
+    _ASSERTE (dwEventID != 0);
+
+    // Attempt to report the event to the event log. Note that if the operation fails
+    // (for example because of low memory conditions) it isn't fatal so we can safely ignore
+    // the return code from ReportEventW.
+    BOOL ret = ::ReportEventW(
+        h,                 // event log handle
+        wType,
+        wCategory,
+        dwEventID,
+        lpUserSid,
+        wNumStrings,
+        dwDataSize,
+        lpStrings,
+        lpRawData);
+
+    DWORD dwRetStatus = GetLastError();
+
+    ::DeregisterEventSource(h);
+
+    return (ret == TRUE)?ERROR_SUCCESS:dwRetStatus;
+#else // TARGET_UNIX
+    // UNIXTODO: Report the event somewhere?
+    return ERROR_SUCCESS;
+#endif // TARGET_UNIX
+}
+
+// Returns ERROR_SUCCESS if succeessful in reporting to event log, or
+// Windows error code to indicate the specific error.
+DWORD ClrReportEvent(
+    LPCWSTR     pEventSource,
+    WORD        wType,
+    WORD        wCategory,
+    DWORD       dwEventID,
+    PSID        lpUserSid,
+    LPCWSTR     pMessage)
+{
+    return ClrReportEvent(pEventSource, wType, wCategory, dwEventID, lpUserSid, 1, &pMessage);
+}
+
+#ifndef TARGET_UNIX
+// Read a REG_SZ (null-terminated string) value from the registry.  Throws.
+//
+// Arguments:
+//     hKey - key to registry hive.
+//     szValueName - null-terminated string for value name to lookup.
+//        If this is empty, this gets the (default) value in the registry hive.
+//     value - out parameter to hold registry value string contents.
+//
+// Returns:
+//    value is set on success. Throws on any failure, including if the value doesn't exist
+//    or if the value exists but is not a REG_SZ.
+//
+// Notes:
+//    REG_SZ is a single null-terminated string in the registry.
+//    This is only support on Windows because the registry is windows specific.
+void ClrRegReadString(HKEY hKey, const SString & szValueName, SString & value)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    DWORD type;
+    DWORD numBytesData;
+
+    // Preemptively clear the string such that it's empty in any failure case.
+    value.Clear();
+
+    //
+    // Step 1:  First call to find size of buffer and ensure data type is correct
+    //
+    LONG ret = WszRegQueryValueEx(
+      hKey,
+      szValueName.GetUnicode(), // NULL or "\0" represents the (default) key.
+      NULL, // reserved
+      &type, // should be REG_SZ
+      NULL, // not requesting data yet
+      &numBytesData
+    );
+
+    if (ret != ERROR_SUCCESS)
+    {
+        ThrowWin32(ret);
+    }
+
+    if (type != REG_SZ)
+    {
+        // The registry value is not a string.
+        ThrowHR(E_INVALIDARG);
+    }
+
+    // REG_SZ includes the null terminator.
+    DWORD numCharsIncludingNull = numBytesData / sizeof(WCHAR);
+
+    //
+    //  Step 2: Allocate buffer to hold final result
+    //
+    WCHAR * pData = value.OpenUnicodeBuffer(numCharsIncludingNull);
+    DWORD numBytesData2 = numBytesData;
+
+
+    //
+    // Step 3: Requery to get actual contents
+    //
+    ret = WszRegQueryValueEx(
+      hKey,
+      szValueName.GetUnicode(),
+      NULL, // reserved
+      &type, // should still be REG_SZ
+      (LPBYTE) pData,
+      &numBytesData2
+    );
+
+    // This check should only fail if the registry was changed inbetween the first query
+    // and the second. In practice, that should never actually happen.
+    if ((numBytesData2 != numBytesData) || (type != REG_SZ))
+    {
+        // On error, leave string empty.
+        value.CloseBuffer(0);
+
+        ThrowHR(E_FAIL);
+    }
+
+    if (ret != ERROR_SUCCESS)
+    {
+        // On error, leave string empty.
+        value.CloseBuffer(0);
+        ThrowWin32(ret);
+    }
+
+
+    //
+    // Step 4:  Close the string buffer
+    //
+    COUNT_T numCharsNoNull = numCharsIncludingNull - 1;
+    value.CloseBuffer(numCharsNoNull);
+}
+#endif // TARGET_UNIX
diff --git a/src/utilcode/sbuffer.cpp b/src/utilcode/sbuffer.cpp
new file mode 100644 (file)
index 0000000..215efef
--- /dev/null
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+
+//
+// Buffer.cpp
+// ---------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "sbuffer.h"
+#include "ex.h"
+#include "holder.h"
+#include "stdmacros.h"
+
+// Try to minimize the performance impact of contracts on CHK build.
+#if defined(_MSC_VER)
+#pragma inline_depth (20)
+#endif
+
+const DWORD g_garbageFillBuffer[GARBAGE_FILL_BUFFER_ITEMS] =
+{
+        GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD,
+        GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD,
+        GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD,
+        GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD, GARBAGE_FILL_DWORD,
+};
+
+//----------------------------------------------------------------------------
+// ReallocateBuffer
+// Low level buffer reallocate routine
+//----------------------------------------------------------------------------
+void SBuffer::ReallocateBuffer(COUNT_T allocation, Preserve preserve)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckBufferClosed());
+        PRECONDITION(CheckAllocation(allocation));
+        PRECONDITION(allocation >= m_size);
+        POSTCONDITION(m_allocation == allocation);
+        if (allocation > 0) THROWS; else NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    BYTE *newBuffer = NULL;
+    if (allocation > 0)
+    {
+        newBuffer = NewBuffer(allocation);
+
+        if (preserve == PRESERVE)
+        {
+            // Copy the relevant contents of the old buffer over
+            DebugMoveBuffer(newBuffer, m_buffer, m_size);
+        }
+    }
+
+    if (IsAllocated())
+        DeleteBuffer(m_buffer, m_allocation);
+
+    m_buffer = newBuffer;
+    m_allocation = allocation;
+
+    if (allocation > 0)
+        SetAllocated();
+    else
+        ClearAllocated();
+
+    ClearImmutable();
+
+    RETURN;
+}
+
+void SBuffer::Replace(const Iterator &i, COUNT_T deleteSize, COUNT_T insertSize)
+{
+    CONTRACT_VOID
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        PRECONDITION(CheckIteratorRange(i, deleteSize));
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    COUNT_T startRange = (COUNT_T) (i.m_ptr - m_buffer);
+    // The PRECONDITION(CheckIterationRange(i, deleteSize)) should check this in
+    // contract-checking builds, but this ensures we don't integer overflow if someone
+    // passes in an egregious deleteSize by capping it to the remaining length in the
+    // buffer.
+    if ((COUNT_T)(m_buffer + m_size - i.m_ptr) < deleteSize)
+    {
+        _ASSERTE(!"Trying to replace more bytes than are remaining in the buffer.");
+        deleteSize = (COUNT_T)(m_buffer + m_size - i.m_ptr);
+    }
+    COUNT_T endRange = startRange + deleteSize;
+    COUNT_T end = m_size;
+
+    SCOUNT_T delta = insertSize - deleteSize;
+
+    if (delta < 0)
+    {
+        // Buffer is shrinking
+
+        DebugDestructBuffer(i.m_ptr, deleteSize);
+
+        DebugMoveBuffer(m_buffer + endRange + delta,
+                        m_buffer + endRange,
+                        end - endRange);
+
+        Resize(m_size+delta, PRESERVE);
+
+        i.Resync(this, m_buffer + startRange);
+
+    }
+    else if (delta > 0)
+    {
+        // Buffer is growing
+
+        ResizePadded(m_size+delta);
+
+        i.Resync(this, m_buffer + startRange);
+
+        DebugDestructBuffer(i.m_ptr, deleteSize);
+
+        DebugMoveBuffer(m_buffer + endRange + delta,
+                        m_buffer + endRange,
+                        end - endRange);
+
+    }
+    else
+    {
+        // Buffer stays the same size.  We need to DebugDestruct it first to keep
+        // the invariant that the new space is clean.
+
+        DebugDestructBuffer(i.m_ptr, insertSize);
+    }
+
+    DebugConstructBuffer(i.m_ptr, insertSize);
+
+    RETURN;
+}
+
+
diff --git a/src/utilcode/securityutil.cpp b/src/utilcode/securityutil.cpp
new file mode 100644 (file)
index 0000000..d3cab8a
--- /dev/null
@@ -0,0 +1,494 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#include "stdafx.h"
+
+#include "securityutil.h"
+#include "ex.h"
+
+#include "securitywrapper.h"
+
+// These are the right that we will give to the global section and global events used
+// in communicating between debugger and debugee
+//
+// SECTION_ALL_ACCESS is needed for the IPC block. Unfortunately, we DACL our events and
+// IPC block identically. Or this particular right does not need to bleed into here.
+//
+#ifndef CLR_IPC_GENERIC_RIGHT
+#define CLR_IPC_GENERIC_RIGHT (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | STANDARD_RIGHTS_ALL | SECTION_ALL_ACCESS)
+#endif
+
+
+//*****************************************************************
+// static helper function
+//
+// helper to form ACL that contains AllowedACE of users of current
+// process and target process
+//
+// [IN] pid - target process id
+// [OUT] ppACL - ACL for the process
+//
+// Clean up -
+// Caller remember to call FreeACL() on *ppACL
+//*****************************************************************
+HRESULT SecurityUtil::GetACLOfPid(DWORD pid, PACL *ppACL)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    HRESULT         hr = S_OK;
+    _ASSERTE(ppACL);
+    *ppACL = NULL;
+
+    PSID    pCurrentProcessSid = NULL;
+    PSID    pTargetProcessSid = NULL;
+    PSID    pTargetProcessAppContainerSid = NULL;
+    DWORD   cSid = 0;
+    DWORD   dwAclSize = 0;
+
+    LOG((LF_CORDB, LL_INFO10000,
+         "SecurityUtil::GetACLOfPid on pid : 0x%08x\n",
+         pid));
+
+
+    SidBuffer sidCurrentProcess;
+    SidBuffer sidTargetProcess;
+    SidBuffer sidTargetProcessAppContainer;
+
+    // Get sid for current process.
+    if (SUCCEEDED(sidCurrentProcess.InitFromProcessNoThrow(GetCurrentProcessId())))
+    {
+        pCurrentProcessSid = sidCurrentProcess.GetSid().RawSid();
+        cSid++;
+    }
+
+    // Get sid for target process.
+    if (SUCCEEDED(sidTargetProcess.InitFromProcessNoThrow(pid)))
+    {
+        pTargetProcessSid = sidTargetProcess.GetSid().RawSid();
+        cSid++;
+    }
+
+    //FISHY: what is the scenario where only one of the above calls succeeds?
+    if (cSid == 0)
+    {
+        // failed to get any useful sid. Just return.
+        // need a better error.
+        //
+        hr = E_FAIL;
+        goto exit;
+    }
+
+    hr = sidTargetProcessAppContainer.InitFromProcessAppContainerSidNoThrow(pid);
+    if (FAILED(hr))
+    {
+        goto exit;
+    }
+    else if (hr == S_OK)
+    {
+        pTargetProcessAppContainerSid = sidTargetProcessAppContainer.GetSid().RawSid();
+        cSid++;
+    }
+    else if(hr == S_FALSE) //not an app container, no sid to add
+    {
+        hr = S_OK; // don't leak S_FALSE
+    }
+
+    LOG((LF_CORDB, LL_INFO10000,
+         "SecurityUtil::GetACLOfPid number of sid : 0x%08x\n",
+         cSid));
+
+    // Now allocate space for ACL. First calculate the space is need to hold ACL
+    dwAclSize = sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) * cSid;
+    if (pCurrentProcessSid)
+    {
+        dwAclSize += GetLengthSid(pCurrentProcessSid);
+    }
+    if (pTargetProcessSid)
+    {
+        dwAclSize += GetLengthSid(pTargetProcessSid);
+    }
+    if (pTargetProcessAppContainerSid)
+    {
+        dwAclSize += GetLengthSid(pTargetProcessAppContainerSid);
+    }
+
+    *ppACL = (PACL) new (nothrow) char[dwAclSize];
+    if (*ppACL == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto exit;
+    }
+
+    // Initialize ACL
+    // add each sid to the allowed ace list
+    if (!InitializeAcl(*ppACL, dwAclSize, ACL_REVISION))
+    {
+        hr = HRESULT_FROM_GetLastError();
+        goto exit;
+    }
+
+    if (pCurrentProcessSid)
+    {
+        // add the current process's sid into ACL if we have it
+        if (!AddAccessAllowedAce(*ppACL, ACL_REVISION, CLR_IPC_GENERIC_RIGHT, pCurrentProcessSid))
+        {
+            hr = HRESULT_FROM_GetLastError();
+            goto exit;
+        }
+    }
+
+    if (pTargetProcessSid)
+    {
+        // add the target process's sid into ACL if we have it
+        if (!AddAccessAllowedAce(*ppACL, ACL_REVISION, CLR_IPC_GENERIC_RIGHT, pTargetProcessSid))
+        {
+            hr = HRESULT_FROM_GetLastError();
+            goto exit;
+        }
+    }
+
+    if (pTargetProcessAppContainerSid)
+    {
+        // add the target process's AppContainer's sid into ACL if we have it
+        if (!AddAccessAllowedAce(*ppACL, ACL_REVISION, CLR_IPC_GENERIC_RIGHT, pTargetProcessAppContainerSid))
+        {
+            hr = HRESULT_FROM_GetLastError();
+            goto exit;
+        }
+    }
+
+    // we better to form a valid ACL to return
+    _ASSERTE(IsValidAcl(*ppACL));
+exit:
+    if (FAILED(hr) && *ppACL)
+    {
+        delete [] (reinterpret_cast<char*>(ppACL));
+    }
+    return hr;
+}   // SecurityUtil::GetACLOfPid
+
+
+//*****************************************************************
+// static helper function
+//
+// free the ACL allocated by SecurityUtil::GetACLOfPid
+//
+// [IN] pACL - ACL to be freed
+//
+//*****************************************************************
+void SecurityUtil::FreeACL(PACL pACL)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+    if (pACL)
+    {
+        delete [] (reinterpret_cast<char*>(pACL));
+    }
+}   // SecurityUtil::FreeACL
+
+
+//*****************************************************************
+// constructor
+//
+// [IN] pACL - ACL that this instance of SecurityUtil will held on to
+//
+//*****************************************************************
+SecurityUtil::SecurityUtil(PACL pACL)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+    m_pACL = pACL;
+    m_pSacl = NULL;
+    m_fInitialized = false;
+}
+
+//*****************************************************************
+// destructor
+//
+// free the ACL that this instance of SecurityUtil helds on to
+//
+//*****************************************************************
+SecurityUtil::~SecurityUtil()
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+    FreeACL(m_pACL);
+    FreeACL(m_pSacl);
+}
+
+//*****************************************************************
+// Initialization function
+//
+// form the SecurityDescriptor that will represent the m_pACL
+//
+//*****************************************************************
+HRESULT SecurityUtil::Init()
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    HRESULT    hr = S_OK;
+
+    if (m_pACL)
+    {
+        if (!InitializeSecurityDescriptor(&m_SD, SECURITY_DESCRIPTOR_REVISION))
+        {
+            hr = HRESULT_FROM_GetLastError();
+            return hr;
+        }
+        if (!SetSecurityDescriptorDacl(&m_SD, TRUE, m_pACL, FALSE))
+        {
+            hr = HRESULT_FROM_GetLastError();
+            return hr;
+        }
+
+        m_SA.nLength = sizeof(SECURITY_ATTRIBUTES);
+        m_SA.lpSecurityDescriptor = &m_SD;
+        m_SA.bInheritHandle = FALSE;
+        m_fInitialized = true;
+    }
+    return S_OK;
+}
+
+// ***************************************************************************
+// Initialization functions which will call the normal Init and add a
+// mandatory label entry to the sacl
+//
+// Expects hProcess to be a valid handle to the process which has the desired
+// mandatory label
+// ***************************************************************************
+HRESULT SecurityUtil::Init(HANDLE hProcess)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = Init();
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    NewArrayHolder<BYTE> pLabel;
+
+    hr = GetMandatoryLabelFromProcess(hProcess, &pLabel);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    TOKEN_MANDATORY_LABEL * ptml = (TOKEN_MANDATORY_LABEL *) pLabel.GetValue();
+
+    hr = SetSecurityDescriptorMandatoryLabel(ptml->Label.Sid);
+
+    return hr;
+}
+
+
+// ***************************************************************************
+// Given a process, this will put the mandatory label into a buffer and point
+// ppbLabel at the buffer.
+//
+// Caller must free ppbLabel via the array "delete []" operator
+// ***************************************************************************
+HRESULT SecurityUtil::GetMandatoryLabelFromProcess(HANDLE hProcess, LPBYTE * ppbLabel)
+{
+    *ppbLabel = NULL;
+
+    DWORD dwSize = 0;
+    HandleHolder hToken;
+    DWORD err = 0;
+
+    if(!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
+    {
+        return HRESULT_FROM_GetLastError();
+    }
+
+    if(!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenIntegrityLevel, NULL, 0, &dwSize))
+    {
+        err = GetLastError();
+    }
+
+    // We need to make sure that GetTokenInformation failed in a predictable manner so we know that
+    // dwSize has the correct buffer size in it.
+    if (err != ERROR_INSUFFICIENT_BUFFER || dwSize == 0)
+    {
+        return HRESULT_FROM_WIN32(err);
+    }
+
+    NewArrayHolder<BYTE> pLabel = new (nothrow) BYTE[dwSize];
+    if (pLabel == NULL)
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    if(!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenIntegrityLevel, pLabel, dwSize, &dwSize))
+    {
+        return HRESULT_FROM_GetLastError();
+    }
+
+    // Our caller will be freeing the memory so use Extract
+    *ppbLabel = pLabel.Extract();
+
+    return S_OK;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Returns pointer inside the specified mandatory SID to the DWORD representing the
+// integrity level of the process.  This DWORD will be one of the
+// SECURITY_MANDATORY_*_RID constants.
+//
+// Arguments:
+//      psidIntegrityLevelLabel - [in] PSID in which to find the integrity level.
+//
+// Return Value:
+//      Pointer to the RID stored in the specified SID.  This RID represents the
+//      integrity level of the process
+//
+
+// static
+DWORD * SecurityUtil::GetIntegrityLevelFromMandatorySID(PSID psidIntegrityLevelLabel)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    return GetSidSubAuthority(psidIntegrityLevelLabel, (*GetSidSubAuthorityCount(psidIntegrityLevelLabel) - 1));
+}
+
+// Creates a mandatory label ace and sets it to be the entry in the
+// security descriptor's sacl. This assumes there are no other entries
+// in the sacl
+HRESULT SecurityUtil::SetSecurityDescriptorMandatoryLabel(PSID psidIntegrityLevelLabel)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    DWORD cbSid = GetLengthSid(psidIntegrityLevelLabel);
+    DWORD cbAceStart = offsetof(SYSTEM_MANDATORY_LABEL_ACE, SidStart);
+    // We are about allocate memory for a ACL and an ACE so we need space for:
+    // 1) the ACL: sizeof(ACL)
+    // 2) the entry: the sid is of variable size, so the SYSTEM_MANDATORY_LABEL_ACE
+    //    structure has only the first DWORD of the sid in its definition, to get the
+    //    appropriate size we get size without SidStart and add on the actual size of the sid
+    DWORD cbSacl = sizeof(ACL) + cbAceStart + cbSid;
+
+    NewArrayHolder<BYTE> sacl = new (nothrow) BYTE[cbSacl];
+
+    m_pSacl = NULL;
+
+    if (sacl == NULL)
+    {
+        return E_OUTOFMEMORY;
+    }
+    ZeroMemory(sacl.GetValue(), cbSacl);
+    PACL pSacl = reinterpret_cast<ACL *>(sacl.GetValue());
+    SYSTEM_MANDATORY_LABEL_ACE * pLabelAce = reinterpret_cast<SYSTEM_MANDATORY_LABEL_ACE *>(sacl.GetValue() + sizeof(ACL));
+    PSID psid = reinterpret_cast<SID *>(&pLabelAce->SidStart);
+
+    // Our buffer looks like this now: (not drawn to scale)
+    // sacl  pSacl pLabelAce psid
+    //  -      -
+    //  |      |
+    //  |      -       -
+    //  |              |
+    //  |              |       -
+    //  |              -       |
+    //  -                      -
+
+    DWORD dwIntegrityLevel = *(GetIntegrityLevelFromMandatorySID(psidIntegrityLevelLabel));
+
+    if (dwIntegrityLevel >= SECURITY_MANDATORY_MEDIUM_RID)
+    {
+        // No need to set the integrity level unless it's lower than medium
+        return S_OK;
+    }
+
+    if(!InitializeAcl(pSacl, cbSacl, ACL_REVISION))
+    {
+        return HRESULT_FROM_GetLastError();
+    }
+
+    pSacl->AceCount = 1;
+
+    pLabelAce->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE;
+    pLabelAce->Header.AceSize = WORD(cbAceStart + cbSid);
+    pLabelAce->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP;
+
+    memcpy(psid, psidIntegrityLevelLabel, cbSid);
+
+    if(!SetSecurityDescriptorSacl(m_SA.lpSecurityDescriptor, TRUE, pSacl, FALSE))
+    {
+        return HRESULT_FROM_GetLastError();
+    }
+
+    // No need to delete the sacl buffer, it will be deleted in the
+    // destructor of this class
+    m_pSacl = (PACL)sacl.Extract();
+    return S_OK;
+}
+
+//*****************************************************************
+// Return SECURITY_ATTRIBUTES that we form in the Init function
+//
+// No clean up is needed after calling this function. The destructor of the
+// instance will do the right thing. Note that this is designed such that
+// we minimize memory allocation, ie the SECURITY_DESCRIPTOR and
+// SECURITY_ATTRIBUTES are embedded in the SecurityUtil instance.
+//
+// Caller should not modify the returned SECURITY_ATTRIBUTES!!!
+//*****************************************************************
+HRESULT SecurityUtil::GetSA(SECURITY_ATTRIBUTES **ppSA)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    _ASSERTE(ppSA);
+
+    if (m_fInitialized == false)
+    {
+        _ASSERTE(!"Bad code path!");
+        *ppSA = NULL;
+        return E_FAIL;
+    }
+
+    *ppSA = &m_SA;
+    return S_OK;
+}
diff --git a/src/utilcode/securitywrapper.cpp b/src/utilcode/securitywrapper.cpp
new file mode 100644 (file)
index 0000000..8f7ac38
--- /dev/null
@@ -0,0 +1,749 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// File: SecurityWrapper.cpp
+//
+
+//
+// Wrapper around Win32 Security functions
+//
+//*****************************************************************************
+
+#include "stdafx.h"
+
+#include "securitywrapper.h"
+#include "ex.h"
+#include "holder.h"
+
+
+// For GetSidFromProcess*
+#include <tlhelp32.h>
+#include "wtsapi32.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor for Sid wrapper class.
+// pSid - OS sid to wrap
+//-----------------------------------------------------------------------------
+Sid::Sid(PSID pSid)
+{
+    _ASSERTE(pSid != NULL);
+    m_pSid = pSid;
+}
+
+//-----------------------------------------------------------------------------
+// Aesthetic wrapper for Sid equality
+//-----------------------------------------------------------------------------
+bool Sid::Equals(PSID a, PSID b)
+{
+    return EqualSid(a, b) != 0;
+}
+
+//-----------------------------------------------------------------------------
+// Ctor for SidBuffer class
+//-----------------------------------------------------------------------------
+SidBuffer::SidBuffer()
+{
+    m_pBuffer = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Dtor for SidBuffer class.
+//-----------------------------------------------------------------------------
+SidBuffer::~SidBuffer()
+{
+    delete [] m_pBuffer;
+}
+
+//-----------------------------------------------------------------------------
+// Get the underlying sid
+// Caller assumes SidBuffer has been initialized.
+//-----------------------------------------------------------------------------
+Sid SidBuffer::GetSid()
+{
+    _ASSERTE(m_pBuffer != NULL);
+    Sid s((PSID) m_pBuffer);
+    return s;
+}
+
+// ----------------------------------------------------------------------------
+// Used by GetSidFromProcessWorker to determine which SID from the
+// process token to use when initializing the SID
+enum SidType
+{
+    // Use TokenOwner: the default owner SID used for newly created objects
+    kOwnerSid,
+
+    // Use TokenUser: the user account from the token
+    kUserSid,
+};
+
+// ----------------------------------------------------------------------------
+// GetSidFromProcessWorker
+//
+// Description:
+//    Internal helper.  Gets the SID for the given process and given sid type
+//
+// Arguments:
+//    * dwProcessId - [in] Process to get SID from
+//    * sidType - [in] Type of sid to get (owner or user)
+//    * ppSid - [out] SID found.  Caller responsible for deleting this memory.
+//
+// Return Value:
+//    HRESULT indicating success / failure.
+//
+// Notes:
+//    * Caller owns deleting (*ppSid) when done with the SID
+//
+
+HRESULT GetSidFromProcessWorker(DWORD dwProcessId, SidType sidType, PSID *ppSid)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    HRESULT                     hr = S_OK;
+    TOKEN_USER                  *pTokUser = NULL;
+    HANDLE                      hProc = INVALID_HANDLE_VALUE;
+    HANDLE                      hToken = INVALID_HANDLE_VALUE;
+    DWORD                       dwRetLength = 0;
+    LPVOID                      pvTokenInfo = NULL;
+    TOKEN_INFORMATION_CLASS     tokenInfoClass;
+    PSID                        pSidFromTokenInfo = NULL;
+    DWORD                       cbSid;
+    PSID                        pSid = NULL;
+
+    LOG((LF_CORDB, LL_INFO10000,
+         "SecurityUtil::GetSidFromProcess: 0x%08x\n",
+         dwProcessId));
+
+    _ASSERTE(ppSid);
+    *ppSid = NULL;
+
+    _ASSERTE((sidType == kOwnerSid) || (sidType == kUserSid));
+    tokenInfoClass = (sidType == kOwnerSid) ? TokenOwner : TokenUser;
+
+    hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
+
+    if (hProc == NULL)
+    {
+        hr = HRESULT_FROM_GetLastError();
+        goto exit;
+    }
+    if (!OpenProcessToken(hProc, TOKEN_QUERY, &hToken))
+    {
+        hr = HRESULT_FROM_GetLastError();
+        goto exit;
+    }
+
+    // figure out the length
+    GetTokenInformation(hToken, tokenInfoClass, NULL, 0, &dwRetLength);
+    _ASSERTE(dwRetLength);
+
+    pvTokenInfo = new (nothrow) BYTE[dwRetLength];
+    if (pvTokenInfo == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto exit;
+    }
+
+    if (!GetTokenInformation(hToken, tokenInfoClass, pvTokenInfo, dwRetLength, &dwRetLength))
+    {
+        hr = HRESULT_FROM_GetLastError();
+        goto exit;
+    }
+
+    // Copy over the SID
+    pSidFromTokenInfo =
+        (sidType == kOwnerSid) ?
+            ((TOKEN_OWNER *) pvTokenInfo)->Owner :
+            ((TOKEN_USER *) pvTokenInfo)->User.Sid;
+    cbSid = GetLengthSid(pSidFromTokenInfo);
+    pSid = new (nothrow) BYTE[cbSid];
+    if (pSid == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+    }
+    else
+    {
+        if (!CopySid(cbSid, pSid, pSidFromTokenInfo))
+        {
+            hr = HRESULT_FROM_GetLastError();
+            goto exit;
+        }
+    }
+
+    *ppSid = pSid;
+    pSid = NULL;
+
+exit:
+    if (hToken != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(hToken);
+    }
+    if (hProc != INVALID_HANDLE_VALUE)
+    {
+        // clean up
+        CloseHandle(hProc);
+    }
+    if (pvTokenInfo)
+    {
+        delete [] (reinterpret_cast<BYTE*>(pvTokenInfo));
+    }
+
+    if (pSid)
+    {
+        delete [] (reinterpret_cast<BYTE*>(pSid));
+    }
+
+    LOG((LF_CORDB, LL_INFO10000,
+         "SecurityUtil::GetSidFromProcess return hr : 0x%08x\n",
+         hr));
+
+    return hr;
+}
+
+#ifndef FEATURE_CORESYSTEM
+//-----------------------------------------------------------------------------
+// get the sid of a given process id using WTSEnumerateProcesses
+// @todo: Make this function fail when WTSEnumerateProcesses is not available
+// Or is it always available on all of our platform?
+//
+// Caller remember to call delete on *ppSid
+//-----------------------------------------------------------------------------
+HRESULT GetSidFromProcessEXWorker(DWORD dwProcessId, PSID *ppSid)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(ppSid));
+    }
+    CONTRACTL_END;
+
+    HRESULT            hr = S_OK;
+    PWTS_PROCESS_INFOW rgProcessInfo = NULL;
+    DWORD              dwNumProcesses;
+    DWORD              iProc;
+    DWORD              cbSid;
+    PSID               pSid = NULL;
+
+    LOG((LF_CORDB, LL_INFO10000,
+         "SecurityUtil::GetSidFromProcessEx: 0x%08x\n",
+         dwProcessId));
+
+
+    *ppSid = NULL;
+    if (!WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE,   // use local server
+                                0,              // Reserved must be zero
+                                1,              // version must be 1
+                                &rgProcessInfo, // Receives pointer to process list
+                                &dwNumProcesses))
+    {
+        hr = HRESULT_FROM_GetLastError();
+        goto exit;
+    }
+
+    for (iProc = 0; iProc < dwNumProcesses; iProc++)
+    {
+
+        if (rgProcessInfo[iProc].ProcessId == dwProcessId)
+        {
+            if (rgProcessInfo[iProc].pUserSid == NULL)
+            {
+                LOG((LF_CORDB, LL_INFO10000,
+                     "SecurityUtil::GetSidFromProcessEx is not able to retrieve SID\n"));
+
+                // if there is no Sid for the user, don't call GetLengthSid.
+                // It will crash! It is ok to return E_FAIL as caller will ignore it.
+                hr = E_FAIL;
+                goto exit;
+            }
+            cbSid = GetLengthSid(rgProcessInfo[iProc].pUserSid);
+            pSid = new (nothrow) BYTE[cbSid];
+            if (pSid == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+            }
+            else
+            {
+                if (!CopySid(cbSid, pSid, rgProcessInfo[iProc].pUserSid))
+                {
+                    hr = HRESULT_FROM_GetLastError();
+                }
+                else
+                {
+                    // We are done. Go to exit
+                    hr = S_OK;
+                }
+            }
+
+            // we already find a match. Even if we fail from memory allocation of CopySid, still
+            // goto exit.
+            goto exit;
+        }
+    }
+
+    // Walk the whole list and cannot find the matching PID
+    // Find a better error code.
+    hr = E_FAIL;
+
+exit:
+
+    if (rgProcessInfo)
+    {
+        WTSFreeMemory(rgProcessInfo);
+    }
+
+    if (FAILED(hr) && pSid)
+    {
+        delete [] (reinterpret_cast<BYTE*>(pSid));
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        _ASSERTE(pSid);
+        *ppSid = pSid;
+    }
+    LOG((LF_CORDB, LL_INFO10000,
+         "SecurityUtil::GetSidFromProcessEx return hr : 0x%08x\n",
+         hr));
+
+
+    return hr;
+}
+#endif // !FEATURE_CORESYSTEM
+
+//-----------------------------------------------------------------------------
+// The functions below initialize this SidBuffer instance with a Sid from
+// the token of the specified process.  The first pair use the OWNER sid from
+// the process token if possible; else use the term serv API to find the
+// USER sid from the process token.  This seems a little inconsistent, but
+// remains this way for backward compatibility.  The second pair consistently
+// use the USER sid (never the OWNER).
+//
+// While the USER and OWNER sid are often the same, they are not always the
+// same.  For example, running a process on win2k3 server as a member of the
+// local admin group causes the USER sid to be the logged-on user, and the
+// OWNER sid to be the local admins group.  At least, that's how it was on
+// Monday.  Expect this to change randomly at unexpected times, as most
+// security-related behavior does.
+//-----------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------
+// SidBuffer::InitFromProcessNoThrow
+//
+// Description:
+//    Initialize this SidBuffer instance with a Sid from the token of the specified
+//    process. Use the OWNER sid from the process token if possible; else use the term
+//    serv API to find the USER sid from the process token. This seems a little
+//    inconsistent, but remains this way for backward compatibility.
+//
+// Arguments:
+//    * pid - Process ID from which to grab the SID
+//
+// Return Value:
+//    HRESULT indicating success / failure
+//
+
+HRESULT SidBuffer::InitFromProcessNoThrow(DWORD pid)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    _ASSERTE(m_pBuffer == NULL);
+    HRESULT hr = GetSidFromProcessWorker(pid, kOwnerSid, (PSID *) &m_pBuffer);
+#ifndef FEATURE_CORESYSTEM
+    if (FAILED(hr))
+    {
+        hr = GetSidFromProcessEXWorker(pid, (PSID *) &m_pBuffer);
+    }
+#endif // !FEATURE_CORESYSTEM
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    _ASSERTE(m_pBuffer != NULL);
+    return S_OK;
+}
+
+// See code:SidBuffer::InitFromProcessNoThrow.  Throws if there's an error.
+void SidBuffer::InitFromProcess(DWORD pid)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = InitFromProcessNoThrow(pid);
+    if (FAILED(hr))
+    {
+        ThrowHR(hr);
+    }
+}
+
+// ----------------------------------------------------------------------------
+// SidBuffer::InitFromProcessAppContainerSidNoThrow
+//
+// Description:
+//    Initialize this SidBuffer instance with the TokenAppContainerSid from
+//    the process token
+//
+// Arguments:
+//    * pid - Process ID from which to grab the SID
+//
+// Return Value:
+//    HRESULT indicating success / failure
+//    S_FALSE indicates the process isn't in an AppContainer
+//
+HRESULT SidBuffer::InitFromProcessAppContainerSidNoThrow(DWORD pid)
+{
+    HRESULT hr = S_OK;
+    HANDLE hToken = NULL;
+    BOOL fIsLowBox = FALSE;
+
+    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+    if (hProcess == NULL)
+    {
+        hr = HRESULT_FROM_GetLastError();
+        goto exit;
+    }
+    if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
+    {
+        hr = HRESULT_FROM_GetLastError();
+        goto exit;
+    }
+
+    // Define new TOKEN_INFORMATION_CLASS/ TOKEN_APPCONTAINER_INFORMATION members for Win8 since they are not in the DevDiv copy of WinSDK yet
+    typedef enum _TOKEN_INFORMATION_CLASS_WIN8 {
+        TokenIsAppContainer = TokenLogonSid + 1,
+        TokenCapabilities,
+        TokenAppContainerSid
+    } TOKEN_INFORMATION_CLASS_WIN8;
+
+    typedef struct _TOKEN_APPCONTAINER_INFORMATION
+    {
+        PSID TokenPackage;
+    } TOKEN_APPCONTAINER_INFORMATION, *PTOKEN_APPCONTAINER_INFORMATION;
+
+    DWORD size;
+    if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenIsAppContainer, &fIsLowBox, sizeof(fIsLowBox), &size))
+    {
+        DWORD gle = GetLastError();
+        if (gle == ERROR_INVALID_PARAMETER || gle == ERROR_INVALID_FUNCTION)
+        {
+            hr = S_FALSE; // We are on an OS which doesn't understand LowBox
+        }
+        else
+        {
+            hr = HRESULT_FROM_WIN32(gle);
+        }
+        goto exit;
+    }
+
+    if (!fIsLowBox)
+    {
+        hr = S_FALSE;
+        goto exit;
+    }
+
+    UCHAR PackSid[SECURITY_MAX_SID_SIZE + sizeof(TOKEN_APPCONTAINER_INFORMATION)];
+    if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenAppContainerSid, &PackSid, sizeof(PackSid), &size))
+    {
+        hr = HRESULT_FROM_GetLastError();
+        goto exit;
+    }
+
+    {
+        PTOKEN_APPCONTAINER_INFORMATION pTokPack = (PTOKEN_APPCONTAINER_INFORMATION)&PackSid;
+        PSID pLowBoxPackage = pTokPack->TokenPackage;
+        DWORD dwSidLen = GetLengthSid(pLowBoxPackage);
+        m_pBuffer = new (nothrow) BYTE[dwSidLen];
+        if (m_pBuffer == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto exit;
+        }
+        else
+        {
+            if (!CopySid(dwSidLen, m_pBuffer, pLowBoxPackage))
+            {
+                hr = HRESULT_FROM_GetLastError();
+                delete m_pBuffer;
+                m_pBuffer = NULL;
+                goto exit;
+            }
+        }
+    }
+
+exit:
+    if (hProcess != NULL)
+    {
+        CloseHandle(hProcess);
+    }
+    if (hToken != NULL)
+    {
+        CloseHandle(hToken);
+    }
+
+    return hr;
+}
+
+// ----------------------------------------------------------------------------
+// SidBuffer::InitFromProcessUserNoThrow
+//
+// Description:
+//    Initialize this SidBuffer instance with a Sid from the token of the specified
+//    process. Use the USER sid from the process token if possible; else use the term
+//    serv API to find the USER sid from the process token.
+//
+// Arguments:
+//    * pid - Process ID from which to grab the SID
+//
+// Return Value:
+//    HRESULT indicating success / failure
+//
+
+HRESULT SidBuffer::InitFromProcessUserNoThrow(DWORD pid)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    _ASSERTE(m_pBuffer == NULL);
+    HRESULT hr = GetSidFromProcessWorker(pid, kUserSid, (PSID *) &m_pBuffer);
+#ifndef FEATURE_CORESYSTEM
+    if (FAILED(hr))
+    {
+        hr = GetSidFromProcessEXWorker(pid, (PSID *) &m_pBuffer);
+    }
+#endif // !FEATURE_CORESYSTEM
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    _ASSERTE(m_pBuffer != NULL);
+    return S_OK;
+}
+
+// See code:SidBuffer::InitFromProcessUserNoThrow.  Throws if there's an error.
+void SidBuffer::InitFromProcessUser(DWORD pid)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    HRESULT hr = InitFromProcessUserNoThrow(pid);
+    if (FAILED(hr))
+    {
+        ThrowHR(hr);
+    }
+}
+
+//-----------------------------------------------------------------------------
+// Ctor for Dacl class. Wraps a win32 dacl.
+//-----------------------------------------------------------------------------
+Dacl::Dacl(PACL pAcl)
+{
+    m_acl = pAcl;
+}
+
+//-----------------------------------------------------------------------------
+// Get number of ACE (Access Control Entries) in this DACL.
+//-----------------------------------------------------------------------------
+SIZE_T Dacl::GetAceCount()
+{
+    return (SIZE_T) m_acl->AceCount;
+}
+
+//-----------------------------------------------------------------------------
+// Get Raw a ACE at the given index.
+// Caller assumes index is valid (0 <= dwAceIndex < GetAceCount())
+// Throws on error (which should only be if the index is out of bounds).
+//-----------------------------------------------------------------------------
+ACE_HEADER * Dacl::GetAce(SIZE_T dwAceIndex)
+{
+    CONTRACTL {
+        THROWS;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    ACE_HEADER * pAce = NULL;
+    BOOL fOk = ::GetAce(m_acl, (DWORD) dwAceIndex, (LPVOID*) &pAce);
+    _ASSERTE(fOk == (pAce != NULL));
+    if (!fOk)
+    {
+        ThrowLastError();
+    }
+    return pAce;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Ctor for SecurityDescriptor
+//-----------------------------------------------------------------------------
+Win32SecurityDescriptor::Win32SecurityDescriptor()
+{
+    m_pDesc = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Dtor for security Descriptor.
+//-----------------------------------------------------------------------------
+Win32SecurityDescriptor::~Win32SecurityDescriptor()
+{
+    delete [] ((BYTE*) m_pDesc);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Get the dacl for this security descriptor.
+//-----------------------------------------------------------------------------
+Dacl Win32SecurityDescriptor::GetDacl()
+{
+    CONTRACTL {
+        THROWS;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    _ASSERTE(m_pDesc != NULL);
+
+    BOOL bPresent;
+    BOOL bDaclDefaulted;
+    PACL acl;
+
+    if (GetSecurityDescriptorDacl(m_pDesc, &bPresent, &acl, &bDaclDefaulted) == 0)
+    {
+        ThrowLastError();
+    }
+    if (!bPresent)
+    {
+        // No dacl. We consider this an error because all of the objects we expect
+        // to see should be dacled. If it's not dacled, then it's a malicious user spoofing it.
+        ThrowHR(E_INVALIDARG);
+    }
+
+    Dacl d(acl);
+    return d;
+}
+
+//-----------------------------------------------------------------------------
+// Get the owner from the security descriptor.
+//-----------------------------------------------------------------------------
+HRESULT Win32SecurityDescriptor::GetOwnerNoThrow( PSID* ppSid)
+{
+    CONTRACTL {
+        NOTHROW;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    _ASSERTE(m_pDesc != NULL);
+    BOOL bOwnerDefaulted;
+
+    if( ppSid == NULL )
+    {
+        return E_INVALIDARG;
+    }
+
+    if (GetSecurityDescriptorOwner(m_pDesc, ppSid, &bOwnerDefaulted) == 0)
+    {
+        DWORD err = GetLastError();
+        return HRESULT_FROM_WIN32(err);
+    }
+
+    return S_OK;
+}
+Sid Win32SecurityDescriptor::GetOwner()
+{
+    CONTRACTL {
+        THROWS;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    PSID pSid;
+    HRESULT hr = GetOwnerNoThrow( &pSid );
+    if( FAILED(hr) )
+    {
+        ThrowHR( hr );
+    }
+
+    Sid s(pSid);
+    return s;
+}
+
+//-----------------------------------------------------------------------------
+// Initialize this instance of a SecurityDescriptor with the SD for the handle.
+// The handle must have READ_CONTROL permissions to do this.
+// Throws on error.
+//-----------------------------------------------------------------------------
+HRESULT Win32SecurityDescriptor::InitFromHandleNoThrow(HANDLE h)
+{
+    CONTRACTL {
+        NOTHROW;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    _ASSERTE(m_pDesc == NULL); //  only init once.
+
+    DWORD       cbNeeded = 0;
+
+    DWORD flags = OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
+
+    // Now get the creator's SID. First get the size of the array needed.
+    BOOL fOk = GetKernelObjectSecurity(h, flags, NULL, 0, &cbNeeded);
+    DWORD err = GetLastError();
+
+    // Caller should give us a handle for which this succeeds. First call will
+    // fail w/ InsufficientBuffer.
+    CONSISTENCY_CHECK_MSGF(fOk || (err == ERROR_INSUFFICIENT_BUFFER), ("Failed to get KernelSecurity for object handle=%p.Err=%d\n", h, err));
+
+    PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) new(nothrow) BYTE[cbNeeded];
+    if( pSD == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    if (GetKernelObjectSecurity(h, flags, pSD, cbNeeded, &cbNeeded) == 0)
+    {
+        // get last error and fail out.
+        err = GetLastError();
+        delete [] ((BYTE*) pSD);
+        return HRESULT_FROM_WIN32(err);
+    }
+
+    m_pDesc = pSD;
+    return S_OK;
+}
+void Win32SecurityDescriptor::InitFromHandle(HANDLE h)
+{
+    CONTRACTL {
+        THROWS;
+        GC_NOTRIGGER;
+    } CONTRACTL_END;
+
+    HRESULT hr = InitFromHandleNoThrow(h);
+    if (FAILED(hr))
+    {
+        ThrowHR(hr);
+    }
+}
diff --git a/src/utilcode/sstring.cpp b/src/utilcode/sstring.cpp
new file mode 100644 (file)
index 0000000..6b5f7af
--- /dev/null
@@ -0,0 +1,2790 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// SString.cpp
+//
+
+// ---------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "sstring.h"
+#include "ex.h"
+#include "holder.h"
+
+
+#if defined(_MSC_VER)
+#pragma inline_depth (25)
+#endif
+
+//-----------------------------------------------------------------------------
+// Static variables
+//-----------------------------------------------------------------------------
+
+// Have one internal, well-known, literal for the empty string.
+const BYTE SString::s_EmptyBuffer[2] = { 0 };
+
+// @todo: these need to be initialized by calling GetACP()
+
+UINT SString::s_ACP = 0;
+
+#ifndef DACCESS_COMPILE
+static BYTE s_EmptySpace[sizeof(SString)] = { 0 };
+#endif // DACCESS_COMPILE
+
+SPTR_IMPL(SString,SString,s_Empty);
+
+void SString::Startup()
+{
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+
+    if (s_ACP == 0)
+    {
+        UINT ACP = GetACP();
+
+#ifndef DACCESS_COMPILE
+        s_Empty = PTR_SString(new (s_EmptySpace) SString());
+        s_Empty->SetNormalized();
+#endif // DACCESS_COMPILE
+
+        MemoryBarrier();
+        s_ACP = ACP;
+    }
+}
+
+CHECK SString::CheckStartup()
+{
+    WRAPPER_NO_CONTRACT;
+
+    CHECK(s_Empty != NULL);
+    CHECK_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Case insensitive helpers.
+//-----------------------------------------------------------------------------
+
+static WCHAR MapChar(WCHAR wc, DWORD dwFlags)
+{
+    WRAPPER_NO_CONTRACT;
+
+    WCHAR                     wTmp;
+
+#ifndef TARGET_UNIX
+
+    int iRet = ::LCMapStringEx(LOCALE_NAME_INVARIANT, dwFlags, &wc, 1, &wTmp, 1, NULL, NULL, 0);
+    if (!iRet) {
+        // This can fail in non-exceptional cases becauseof unknown unicode characters.
+        wTmp = wc;
+    }
+
+#else // !TARGET_UNIX
+    // For PAL, no locale specific processing is done
+
+    if (dwFlags == LCMAP_UPPERCASE)
+    {
+        wTmp =
+#ifdef SELF_NO_HOST
+            toupper(wc);
+#else
+            PAL_ToUpperInvariant(wc);
+#endif
+    }
+    else
+    {
+        _ASSERTE(dwFlags == LCMAP_LOWERCASE);
+        wTmp =
+#ifdef SELF_NO_HOST
+            tolower(wc);
+#else
+            PAL_ToLowerInvariant(wc);
+#endif
+    }
+#endif // !TARGET_UNIX
+
+    return wTmp;
+}
+
+#define IS_UPPER_A_TO_Z(x) (((x) >= W('A')) && ((x) <= W('Z')))
+#define IS_LOWER_A_TO_Z(x) (((x) >= W('a')) && ((x) <= W('z')))
+#define CAN_SIMPLE_UPCASE(x) (((x)&~0x7f) == 0)
+#define CAN_SIMPLE_DOWNCASE(x) (((x)&~0x7f) == 0)
+#define SIMPLE_UPCASE(x) (IS_LOWER_A_TO_Z(x) ? ((x) - W('a') + W('A')) : (x))
+#define SIMPLE_DOWNCASE(x) (IS_UPPER_A_TO_Z(x) ? ((x) - W('A') + W('a')) : (x))
+
+/* static */
+int SString::CaseCompareHelper(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count, BOOL stopOnNull, BOOL stopOnCount)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    _ASSERTE(stopOnNull || stopOnCount);
+
+    const WCHAR *buffer1End = buffer1 + count;
+    int diff = 0;
+
+    while (!stopOnCount || (buffer1 < buffer1End))
+    {
+        WCHAR ch1 = *buffer1++;
+        WCHAR ch2 = *buffer2++;
+        diff = ch1 - ch2;
+        if ((ch1 == 0) || (ch2 == 0))
+        {
+            if  (diff != 0 || stopOnNull)
+            {
+                break;
+            }
+        }
+        else
+        {
+            if (diff != 0)
+            {
+                diff = ((CAN_SIMPLE_UPCASE(ch1) ? SIMPLE_UPCASE(ch1) : MapChar(ch1, LCMAP_UPPERCASE))
+                        - (CAN_SIMPLE_UPCASE(ch2) ? SIMPLE_UPCASE(ch2) : MapChar(ch2, LCMAP_UPPERCASE)));
+            }
+            if (diff != 0)
+            {
+                break;
+            }
+        }
+    }
+
+    return diff;
+}
+
+#define IS_LOWER_A_TO_Z_ANSI(x) (((x) >= 'a') && ((x) <= 'z'))
+#define CAN_SIMPLE_UPCASE_ANSI(x) (((x) >= 0x20) && ((x) <= 0x7f))
+#define SIMPLE_UPCASE_ANSI(x) (IS_LOWER_A_TO_Z(x) ? ((x) - 'a' + 'A') : (x))
+
+/* static */
+int SString::CaseCompareHelperA(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count, BOOL stopOnNull, BOOL stopOnCount)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    _ASSERTE(stopOnNull || stopOnCount);
+
+    const CHAR *buffer1End = buffer1 + count;
+    int diff = 0;
+
+    while (!stopOnCount || (buffer1 < buffer1End))
+    {
+        CHAR ch1 = *buffer1;
+        CHAR ch2 = *buffer2;
+        diff = ch1 - ch2;
+        if  (diff != 0 || stopOnNull)
+        {
+            if (ch1 == 0 || ch2 == 0)
+            {
+                break;
+            }
+            diff = (SIMPLE_UPCASE_ANSI(ch1) - SIMPLE_UPCASE_ANSI(ch2));
+            if (diff != 0)
+            {
+                break;
+            }
+        }
+        buffer1++;
+        buffer2++;
+    }
+    return diff;
+}
+
+
+int CaseHashHelper(const WCHAR *buffer, COUNT_T count)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    const WCHAR *bufferEnd = buffer + count;
+    ULONG hash = 5381;
+
+    while (buffer < bufferEnd)
+    {
+        WCHAR ch = *buffer++;
+        ch = CAN_SIMPLE_UPCASE(ch) ? SIMPLE_UPCASE(ch) : MapChar(ch, LCMAP_UPPERCASE);
+
+        hash = (((hash << 5) + hash) ^ ch);
+    }
+
+    return hash;
+}
+
+static int CaseHashHelperA(const CHAR *buffer, COUNT_T count)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    const CHAR *bufferEnd = buffer + count;
+    ULONG hash = 5381;
+
+    while (buffer < bufferEnd)
+    {
+        CHAR ch = *buffer++;
+        ch = SIMPLE_UPCASE_ANSI(ch);
+
+        hash = (((hash << 5) + hash) ^ ch);
+    }
+
+    return hash;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a copy of the unicode string
+//-----------------------------------------------------------------------------
+void SString::Set(const WCHAR *string)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (string == NULL || *string == 0)
+        Clear();
+    else
+    {
+        Resize((COUNT_T) wcslen(string), REPRESENTATION_UNICODE);
+        wcscpy_s(GetRawUnicode(), GetBufferSizeInCharIncludeNullChar(), string);
+    }
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a copy of the first count characters of the given
+// unicode string.
+//-----------------------------------------------------------------------------
+void SString::Set(const WCHAR *string, COUNT_T count)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckCount(count));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    if (count == 0)
+        Clear();
+    else
+    {
+        Resize(count, REPRESENTATION_UNICODE);
+        wcsncpy_s(GetRawUnicode(), GetBufferSizeInCharIncludeNullChar(), string, count);
+        GetRawUnicode()[count] = 0;
+    }
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a point to the first count characters of the given
+// preallocated unicode string (shallow copy).
+//-----------------------------------------------------------------------------
+void SString::SetPreallocated(const WCHAR *string, COUNT_T count)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckCount(count));
+        SS_POSTCONDITION(IsEmpty());
+        GC_NOTRIGGER;
+        NOTHROW;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    SetImmutable();
+    SetImmutable((BYTE*) string, count*2);
+    ClearAllocated();
+    SetRepresentation(REPRESENTATION_UNICODE);
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a copy of the given ansi string
+//-----------------------------------------------------------------------------
+void SString::SetASCII(const ASCII *string)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckASCIIString(string));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    if (string == NULL || *string == 0)
+        Clear();
+    else
+    {
+        Resize((COUNT_T) strlen(string), REPRESENTATION_ASCII);
+        strcpy_s(GetRawUTF8(), GetBufferSizeInCharIncludeNullChar(), string);
+    }
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a copy of the first count characters of the given
+// ascii string
+//-----------------------------------------------------------------------------
+void SString::SetASCII(const ASCII *string, COUNT_T count)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckASCIIString(string, count));
+        PRECONDITION(CheckCount(count));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    if (count == 0)
+        Clear();
+    else
+    {
+        Resize(count, REPRESENTATION_ASCII);
+        strncpy_s(GetRawASCII(), GetBufferSizeInCharIncludeNullChar(), string, count);
+        GetRawASCII()[count] = 0;
+    }
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a copy of the given UTF8 string
+//-----------------------------------------------------------------------------
+void SString::SetUTF8(const UTF8 *string)
+{
+    SS_CONTRACT_VOID
+    {
+        // !!! Check for illegal UTF8 encoding?
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    if (string == NULL || *string == 0)
+        Clear();
+    else
+    {
+        Resize((COUNT_T) strlen(string), REPRESENTATION_UTF8);
+        strcpy_s(GetRawUTF8(), GetBufferSizeInCharIncludeNullChar(), string);
+    }
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a copy of the first count characters of the given
+// UTF8 string.
+//-----------------------------------------------------------------------------
+void SString::SetUTF8(const UTF8 *string, COUNT_T count)
+{
+    SS_CONTRACT_VOID
+    {
+        // !!! Check for illegal UTF8 encoding?
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckCount(count));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    if (count == 0)
+        Clear();
+    else
+    {
+        Resize(count, REPRESENTATION_UTF8);
+        strncpy_s(GetRawUTF8(), GetBufferSizeInCharIncludeNullChar(), string, count);
+        GetRawUTF8()[count] = 0;
+    }
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a copy of the given ANSI string
+//-----------------------------------------------------------------------------
+void SString::SetANSI(const ANSI *string)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    if (string == NULL || *string == 0)
+        Clear();
+    else
+    {
+        Resize((COUNT_T) strlen(string), REPRESENTATION_ANSI);
+        strcpy_s(GetRawANSI(), GetBufferSizeInCharIncludeNullChar(), string);
+    }
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to a copy of the first count characters of the given
+// ANSI string.
+//-----------------------------------------------------------------------------
+void SString::SetANSI(const ANSI *string, COUNT_T count)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(string, NULL_OK));
+        PRECONDITION(CheckCount(count));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    if (count == 0)
+        Clear();
+    else
+    {
+        Resize(count, REPRESENTATION_ANSI);
+        strncpy_s(GetRawANSI(), GetBufferSizeInCharIncludeNullChar(), string, count);
+        GetRawANSI()[count] = 0;
+    }
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to the given unicode character
+//-----------------------------------------------------------------------------
+void SString::Set(WCHAR character)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    if (character == 0)
+        Clear();
+    else
+    {
+        Resize(1, REPRESENTATION_UNICODE);
+        GetRawUnicode()[0] = character;
+        GetRawUnicode()[1] = 0;
+    }
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to the given UTF8 character
+//-----------------------------------------------------------------------------
+void SString::SetUTF8(CHAR character)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    if (character == 0)
+        Clear();
+    else
+    {
+        Resize(1, REPRESENTATION_UTF8);
+        GetRawUTF8()[0] = character;
+        GetRawUTF8()[1] = 0;
+    }
+
+    SS_RETURN;
+}
+
+
+//-----------------------------------------------------------------------------
+// Set this string to the given ansi literal.
+// This will share the memory and not make a copy.
+//-----------------------------------------------------------------------------
+void SString::SetLiteral(const ASCII *literal)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(literal));
+        PRECONDITION(CheckASCIIString(literal));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SString s(Literal, literal);
+    Set(s);
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to the given unicode literal.
+// This will share the memory and not make a copy.
+//-----------------------------------------------------------------------------
+void SString::SetLiteral(const WCHAR *literal)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(literal));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    SString s(Literal, literal);
+    Set(s);
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Hash the string contents
+//-----------------------------------------------------------------------------
+ULONG SString::Hash() const
+{
+    SS_CONTRACT(ULONG)
+    {
+        INSTANCE_CHECK;
+        THROWS_UNLESS_NORMALIZED;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToUnicode();
+
+    SS_RETURN HashString(GetRawUnicode());
+}
+
+//-----------------------------------------------------------------------------
+// Hash the string contents
+//-----------------------------------------------------------------------------
+ULONG SString::HashCaseInsensitive() const
+{
+    SS_CONTRACT(ULONG)
+    {
+        INSTANCE_CHECK;
+        THROWS_UNLESS_NORMALIZED;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToIteratable();
+
+    ULONG result;
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+    case REPRESENTATION_EMPTY:
+        result = CaseHashHelper(GetRawUnicode(), GetRawCount());
+        break;
+
+    case REPRESENTATION_ASCII:
+        result = CaseHashHelperA(GetRawASCII(), GetRawCount());
+        break;
+
+    default:
+        UNREACHABLE();
+    }
+
+    SS_RETURN result;
+}
+
+//-----------------------------------------------------------------------------
+// Truncate this string to count characters.
+//-----------------------------------------------------------------------------
+void SString::Truncate(const Iterator &i)
+{
+    SS_CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        SS_POSTCONDITION(GetRawCount() == i - Begin());
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    SS_CONTRACT_END;
+
+    CONSISTENCY_CHECK(IsFixedSize());
+
+    COUNT_T size = i - Begin();
+
+    Resize(size, GetRepresentation(), PRESERVE);
+
+    i.Resync(this, (BYTE *) (GetRawUnicode() + size));
+
+    SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Convert the ASCII representation for this String to Unicode. We can do this
+// quickly and in-place (if this == &dest), which is why it is optimized.
+//-----------------------------------------------------------------------------
+void SString::ConvertASCIIToUnicode(SString &dest) const
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(IsRepresentation(REPRESENTATION_ASCII));
+        POSTCONDITION(dest.IsRepresentation(REPRESENTATION_UNICODE));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    // Handle the empty case.
+    if (IsEmpty())
+    {
+        dest.Clear();
+        RETURN;
+    }
+
+    CONSISTENCY_CHECK(CheckPointer(GetRawASCII()));
+    CONSISTENCY_CHECK(GetRawCount() > 0);
+
+    // If dest is the same as this, then we need to preserve on resize.
+    dest.Resize(GetRawCount(), REPRESENTATION_UNICODE,
+                this == &dest ? PRESERVE : DONT_PRESERVE);
+
+    // Make sure the buffer is big enough.
+    CONSISTENCY_CHECK(dest.GetAllocation() > (GetRawCount() * sizeof(WCHAR)));
+
+    // This is a poor man's widen. Since we know that the representation is ASCII,
+    // we can just pad the string with a bunch of zero-value bytes. Of course,
+    // we move from the end of the string to the start so that we can convert in
+    // place (in the case that &dest == this).
+    WCHAR *outBuf = dest.GetRawUnicode() + dest.GetRawCount();
+    ASCII *inBuf = GetRawASCII() + GetRawCount();
+
+    while (GetRawASCII() <= inBuf)
+    {
+        CONSISTENCY_CHECK(dest.GetRawUnicode() <= outBuf);
+        // The casting zero-extends the value, thus giving us the zero-valued byte.
+        *outBuf = (WCHAR) *inBuf;
+        outBuf--;
+        inBuf--;
+    }
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Convert the internal representation for this String to Unicode.
+//-----------------------------------------------------------------------------
+void SString::ConvertToUnicode() const
+{
+    CONTRACT_VOID
+    {
+        POSTCONDITION(IsRepresentation(REPRESENTATION_UNICODE));
+        if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (!IsRepresentation(REPRESENTATION_UNICODE))
+    {
+        if (IsRepresentation(REPRESENTATION_ASCII))
+        {
+            ConvertASCIIToUnicode(*(const_cast<SString *>(this)));
+        }
+        else
+        {
+            StackSString s;
+            ConvertToUnicode(s);
+            PREFIX_ASSUME(!s.IsImmutable());
+            (const_cast<SString*>(this))->Set(s);
+        }
+    }
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Convert the internal representation for this String to Unicode, while
+// preserving the iterator if the conversion is done.
+//-----------------------------------------------------------------------------
+void SString::ConvertToUnicode(const CIterator &i) const
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(i.Check());
+        POSTCONDITION(IsRepresentation(REPRESENTATION_UNICODE));
+        if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    if (!IsRepresentation(REPRESENTATION_UNICODE))
+    {
+        CONSISTENCY_CHECK(IsFixedSize());
+
+        COUNT_T index = 0;
+        // Get the current index of the iterator
+        if (i.m_ptr != NULL)
+        {
+            CONSISTENCY_CHECK(GetCharacterSizeShift() == 0);
+            index = (COUNT_T) (i.m_ptr - m_buffer);
+        }
+
+        if (IsRepresentation(REPRESENTATION_ASCII))
+        {
+            ConvertASCIIToUnicode(*(const_cast<SString *>(this)));
+        }
+        else
+        {
+            StackSString s;
+            ConvertToUnicode(s);
+            (const_cast<SString*>(this))->Set(s);
+        }
+
+        // Move the iterator to the new location.
+        if (i.m_ptr != NULL)
+        {
+            i.Resync(this, (BYTE *) (GetRawUnicode() + index));
+        }
+    }
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set s to be a copy of this string's contents, but in the unicode format.
+//-----------------------------------------------------------------------------
+void SString::ConvertToUnicode(SString &s) const
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(s.Check());
+        POSTCONDITION(s.IsRepresentation(REPRESENTATION_UNICODE));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    int page = 0;
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_EMPTY:
+        s.Clear();
+        RETURN;
+
+    case REPRESENTATION_UNICODE:
+        s.Set(*this);
+        RETURN;
+
+    case REPRESENTATION_UTF8:
+        page = CP_UTF8;
+        break;
+
+    case REPRESENTATION_ASCII:
+        ConvertASCIIToUnicode(s);
+        RETURN;
+
+    case REPRESENTATION_ANSI:
+        page = CP_ACP;
+        break;
+
+    default:
+        UNREACHABLE();
+    }
+
+    COUNT_T length = WszMultiByteToWideChar(page, 0, GetRawANSI(), GetRawCount()+1, 0, 0);
+    if (length == 0)
+        ThrowLastError();
+
+    s.Resize(length-1, REPRESENTATION_UNICODE);
+
+    length = WszMultiByteToWideChar(page, 0, GetRawANSI(), GetRawCount()+1, s.GetRawUnicode(), length);
+    if (length == 0)
+        ThrowLastError();
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set s to be a copy of this string's contents, but in the ANSI format.
+//-----------------------------------------------------------------------------
+void SString::ConvertToANSI(SString &s) const
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(s.Check());
+        POSTCONDITION(s.IsRepresentation(REPRESENTATION_ANSI));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_EMPTY:
+        s.Clear();
+        RETURN;
+
+    case REPRESENTATION_ASCII:
+    case REPRESENTATION_ANSI:
+        s.Set(*this);
+        RETURN;
+
+    case REPRESENTATION_UTF8:
+        // No direct conversion to ANSI
+        ConvertToUnicode();
+        FALLTHROUGH;
+
+    case REPRESENTATION_UNICODE:
+        break;
+
+    default:
+        UNREACHABLE();
+    }
+
+    // @todo: use WC_NO_BEST_FIT_CHARS
+    COUNT_T length = WszWideCharToMultiByte(CP_ACP, 0, GetRawUnicode(), GetRawCount()+1,
+                                        NULL, 0, NULL, NULL);
+
+    s.Resize(length-1, REPRESENTATION_ANSI);
+
+    // @todo: use WC_NO_BEST_FIT_CHARS
+    length = WszWideCharToMultiByte(CP_ACP, 0, GetRawUnicode(), GetRawCount()+1,
+                                    s.GetRawANSI(), length, NULL, NULL);
+    if (length == 0)
+        ThrowLastError();
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set s to be a copy of this string's contents, but in the utf8 format.
+//-----------------------------------------------------------------------------
+COUNT_T SString::ConvertToUTF8(SString &s) const
+{
+    CONTRACT(COUNT_T)
+    {
+        PRECONDITION(s.Check());
+        POSTCONDITION(s.IsRepresentation(REPRESENTATION_UTF8));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_EMPTY:
+        s.Clear();
+        RETURN 1;
+
+    case REPRESENTATION_ASCII:
+    case REPRESENTATION_UTF8:
+        s.Set(*this);
+        RETURN s.GetRawCount()+1;
+
+    case REPRESENTATION_ANSI:
+        // No direct conversion from ANSI to UTF8
+        ConvertToUnicode();
+        FALLTHROUGH;
+
+    case REPRESENTATION_UNICODE:
+        break;
+
+    default:
+        UNREACHABLE();
+    }
+
+    // <TODO> @todo: use WC_NO_BEST_FIT_CHARS </TODO>
+    bool  allAscii;
+    DWORD length;
+
+    HRESULT hr = FString::Unicode_Utf8_Length(GetRawUnicode(), & allAscii, & length);
+
+    if (SUCCEEDED(hr))
+    {
+        s.Resize(length, REPRESENTATION_UTF8);
+
+       //FString::Unicode_Utf8 expects an array all the time
+        //we optimize the empty string by replacing it with null for SString above in Resize
+        if (length > 0)
+        {
+            hr = FString::Unicode_Utf8(GetRawUnicode(), allAscii, (LPSTR) s.GetRawUTF8(), length);
+        }
+    }
+
+    IfFailThrow(hr);
+
+    RETURN length + 1;
+}
+
+//-----------------------------------------------------------------------------
+// Replace a single character with another character.
+//-----------------------------------------------------------------------------
+void SString::Replace(const Iterator &i, WCHAR c)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i, 1));
+        POSTCONDITION(Match(i, c));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if (IsRepresentation(REPRESENTATION_ASCII) && ((c&~0x7f) == 0))
+    {
+        *(BYTE*)i.m_ptr = (BYTE) c;
+    }
+    else
+    {
+        ConvertToUnicode(i);
+
+        *(USHORT*)i.m_ptr = c;
+    }
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Replace the substring specified by position, length with the given string s.
+//-----------------------------------------------------------------------------
+void SString::Replace(const Iterator &i, COUNT_T length, const SString &s)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i, length));
+        PRECONDITION(s.Check());
+        POSTCONDITION(Match(i, s));
+        THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    Representation representation = GetRepresentation();
+    if (representation == REPRESENTATION_EMPTY)
+    {
+        // This special case contains some optimizations (like literal sharing).
+        Set(s);
+        ConvertToIteratable();
+        i.Resync(this, m_buffer);
+    }
+    else
+    {
+        StackSString temp;
+        const SString &source = GetCompatibleString(s, temp, i);
+
+        COUNT_T deleteSize = length<<GetCharacterSizeShift();
+        COUNT_T insertSize = source.GetRawCount()<<source.GetCharacterSizeShift();
+
+        SBuffer::Replace(i, deleteSize, insertSize);
+        SBuffer::Copy(i, source.m_buffer, insertSize);
+    }
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Find s in this string starting at i. Return TRUE & update iterator if found.
+//-----------------------------------------------------------------------------
+BOOL SString::Find(CIterator &i, const SString &s) const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(s.Check());
+        POSTCONDITION(RETVAL == Match(i, s));
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    // Get a compatible string from s
+    StackSString temp;
+    const SString &source = GetCompatibleString(s, temp, i);
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+        {
+            COUNT_T count = source.GetRawCount();
+            const WCHAR *start = i.GetUnicode();
+            const WCHAR *end = GetUnicode() + GetRawCount() - count;
+            while (start <= end)
+            {
+                if (wcsncmp(start, source.GetRawUnicode(), count) == 0)
+                {
+                    i.Resync(this, (BYTE*) start);
+                    RETURN TRUE;
+                }
+                start++;
+            }
+        }
+        break;
+
+    case REPRESENTATION_ANSI:
+    case REPRESENTATION_ASCII:
+        {
+            COUNT_T count = source.GetRawCount();
+            const CHAR *start = i.GetASCII();
+            const CHAR *end = GetRawASCII() + GetRawCount() - count;
+            while (start <= end)
+            {
+                if (strncmp(start, source.GetRawASCII(), count) == 0)
+                {
+                    i.Resync(this, (BYTE*) start);
+                    RETURN TRUE;
+                }
+                start++;
+            }
+        }
+        break;
+
+    case REPRESENTATION_EMPTY:
+        {
+            if (source.GetRawCount() == 0)
+                RETURN TRUE;
+        }
+        break;
+
+    case REPRESENTATION_UTF8:
+    default:
+        UNREACHABLE();
+    }
+
+    RETURN FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Find s in this string starting at i. Return TRUE & update iterator if found.
+//-----------------------------------------------------------------------------
+BOOL SString::Find(CIterator &i, WCHAR c) const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        POSTCONDITION(RETVAL == Match(i, c));
+        THROWS_UNLESS_NORMALIZED;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    // Get a compatible string
+    if (c & ~0x7f)
+        ConvertToUnicode(i);
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+        {
+            const WCHAR *start = i.GetUnicode();
+            const WCHAR *end = GetUnicode() + GetRawCount() - 1;
+            while (start <= end)
+            {
+                if (*start == c)
+                {
+                    i.Resync(this, (BYTE*) start);
+                    RETURN TRUE;
+                }
+                start++;
+            }
+        }
+        break;
+
+    case REPRESENTATION_ANSI:
+    case REPRESENTATION_ASCII:
+        {
+            const CHAR *start = i.GetASCII();
+            const CHAR *end = GetRawASCII() + GetRawCount() - 1;
+            while (start <= end)
+            {
+                if (*start == c)
+                {
+                    i.Resync(this, (BYTE*) start);
+                    RETURN TRUE;
+                }
+                start++;
+            }
+        }
+        break;
+
+    case REPRESENTATION_EMPTY:
+        break;
+
+    case REPRESENTATION_UTF8:
+    default:
+        UNREACHABLE();
+    }
+
+    RETURN FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Find s in this string, working backwards staring at i.
+// Return TRUE and update iterator if found.
+//-----------------------------------------------------------------------------
+BOOL SString::FindBack(CIterator &i, const SString &s) const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(s.Check());
+        POSTCONDITION(RETVAL == Match(i, s));
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    // Get a compatible string from s
+    StackSString temp;
+    const SString &source = GetCompatibleString(s, temp, i);
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+        {
+            COUNT_T count = source.GetRawCount();
+            const WCHAR *start = GetRawUnicode() + GetRawCount() - count;
+            if (start > i.GetUnicode())
+                start = i.GetUnicode();
+            const WCHAR *end = GetRawUnicode();
+
+            while (start >= end)
+            {
+                if (wcsncmp(start, source.GetRawUnicode(), count) == 0)
+                {
+                    i.Resync(this, (BYTE*) start);
+                    RETURN TRUE;
+                }
+                start--;
+            }
+        }
+        break;
+
+    case REPRESENTATION_ANSI:
+    case REPRESENTATION_ASCII:
+        {
+            COUNT_T count = source.GetRawCount();
+            const CHAR *start = GetRawASCII() + GetRawCount() - count;
+            if (start > i.GetASCII())
+                start = i.GetASCII();
+            const CHAR *end = GetRawASCII();
+
+            while (start >= end)
+            {
+                if (strncmp(start, source.GetRawASCII(), count) == 0)
+                {
+                    i.Resync(this, (BYTE*) start);
+                    RETURN TRUE;
+                }
+                start--;
+            }
+        }
+        break;
+
+    case REPRESENTATION_EMPTY:
+        {
+            if (source.GetRawCount() == 0)
+                RETURN TRUE;
+        }
+        break;
+
+    case REPRESENTATION_UTF8:
+    default:
+        UNREACHABLE();
+    }
+
+    RETURN FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Find s in this string, working backwards staring at i.
+// Return TRUE and update iterator if found.
+//-----------------------------------------------------------------------------
+BOOL SString::FindBack(CIterator &i, WCHAR c) const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        POSTCONDITION(RETVAL == Match(i, c));
+        THROWS_UNLESS_NORMALIZED;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    // Get a compatible string from s
+    if (c & ~0x7f)
+        ConvertToUnicode(i);
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+        {
+            const WCHAR *start = GetRawUnicode() + GetRawCount() - 1;
+            if (start > i.GetUnicode())
+                start = i.GetUnicode();
+            const WCHAR *end = GetRawUnicode();
+
+            while (start >= end)
+            {
+                if (*start == c)
+                {
+                    i.Resync(this, (BYTE*) start);
+                    RETURN TRUE;
+                }
+                start--;
+            }
+        }
+        break;
+
+    case REPRESENTATION_ANSI:
+    case REPRESENTATION_ASCII:
+        {
+            const CHAR *start = GetRawASCII() + GetRawCount() - 1;
+            if (start > i.GetASCII())
+                start = i.GetASCII();
+            const CHAR *end = GetRawASCII();
+
+            while (start >= end)
+            {
+                if (*start == c)
+                {
+                    i.Resync(this, (BYTE*) start);
+                    RETURN TRUE;
+                }
+                start--;
+            }
+        }
+        break;
+
+    case REPRESENTATION_EMPTY:
+        break;
+
+    case REPRESENTATION_UTF8:
+    default:
+        UNREACHABLE();
+    }
+
+    RETURN FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Returns TRUE if this string begins with the contents of s
+//-----------------------------------------------------------------------------
+BOOL SString::BeginsWith(const SString &s) const
+{
+    WRAPPER_NO_CONTRACT;
+
+    return Match(Begin(), s);
+}
+
+//-----------------------------------------------------------------------------
+// Returns TRUE if this string begins with the contents of s
+//-----------------------------------------------------------------------------
+BOOL SString::BeginsWithCaseInsensitive(const SString &s) const
+{
+    WRAPPER_NO_CONTRACT;
+
+    return MatchCaseInsensitive(Begin(), s);
+}
+
+//-----------------------------------------------------------------------------
+// Returns TRUE if this string ends with the contents of s
+//-----------------------------------------------------------------------------
+BOOL SString::EndsWith(const SString &s) const
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Need this check due to iterator arithmetic below.
+    if (GetCount() < s.GetCount())
+    {
+        return FALSE;
+    }
+
+    return Match(End() - s.GetCount(), s);
+}
+
+//-----------------------------------------------------------------------------
+// Returns TRUE if this string ends with the contents of s
+//-----------------------------------------------------------------------------
+BOOL SString::EndsWithCaseInsensitive(const SString &s) const
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Need this check due to iterator arithmetic below.
+    if (GetCount() < s.GetCount())
+    {
+        return FALSE;
+    }
+
+    return MatchCaseInsensitive(End() - s.GetCount(), s);
+}
+
+//-----------------------------------------------------------------------------
+// Compare this string's contents to s's contents.
+// The comparison does not take into account localization issues like case folding.
+// Return 0 if equal, <0 if this < s, >0 is this > s. (same as strcmp).
+//-----------------------------------------------------------------------------
+int SString::Compare(const SString &s) const
+{
+    CONTRACT(int)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s.Check());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    StackSString temp;
+    const SString &source = GetCompatibleString(s, temp);
+
+    COUNT_T smaller;
+    int equals = 0;
+    int result = 0;
+
+    if (GetRawCount() < source.GetRawCount())
+    {
+        smaller = GetRawCount();
+        equals = -1;
+    }
+    else if (GetRawCount() > source.GetRawCount())
+    {
+        smaller = source.GetRawCount();
+        equals = 1;
+    }
+    else
+    {
+        smaller = GetRawCount();
+        equals = 0;
+    }
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+        result = wcsncmp(GetRawUnicode(), source.GetRawUnicode(), smaller);
+        break;
+
+    case REPRESENTATION_ASCII:
+    case REPRESENTATION_ANSI:
+        result = strncmp(GetRawASCII(), source.GetRawASCII(), smaller);
+        break;
+
+    case REPRESENTATION_EMPTY:
+        result = 0;
+        break;
+
+    default:
+    case REPRESENTATION_UTF8:
+        UNREACHABLE();
+    }
+
+    if (result == 0)
+        RETURN equals;
+    else
+        RETURN result;
+}
+
+//-----------------------------------------------------------------------------
+// Compare this string's contents to s's contents.
+// Return 0 if equal, <0 if this < s, >0 is this > s. (same as strcmp).
+//-----------------------------------------------------------------------------
+
+int SString::CompareCaseInsensitive(const SString &s) const
+{
+    CONTRACT(int)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s.Check());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    StackSString temp;
+    const SString &source = GetCompatibleString(s, temp);
+
+    COUNT_T smaller;
+    int equals = 0;
+    int result = 0;
+
+    if (GetRawCount() < source.GetRawCount())
+    {
+        smaller = GetRawCount();
+        equals = -1;
+    }
+    else if (GetRawCount() > source.GetRawCount())
+    {
+        smaller = source.GetRawCount();
+        equals = 1;
+    }
+    else
+    {
+        smaller = GetRawCount();
+        equals = 0;
+    }
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+    case REPRESENTATION_ANSI:
+        result = CaseCompareHelper(GetRawUnicode(), source.GetRawUnicode(), smaller, FALSE, TRUE);
+        break;
+
+    case REPRESENTATION_ASCII:
+        result = CaseCompareHelperA(GetRawASCII(), source.GetRawASCII(), smaller, FALSE, TRUE);
+        break;
+
+    case REPRESENTATION_EMPTY:
+        result = 0;
+        break;
+
+    default:
+    case REPRESENTATION_UTF8:
+        UNREACHABLE();
+    }
+
+    if (result == 0)
+        RETURN equals;
+    else
+        RETURN result;
+}
+
+//-----------------------------------------------------------------------------
+// Compare this string's contents to s's contents.
+// The comparison does not take into account localization issues like case folding.
+// Return 1 if equal, 0 if not.
+//-----------------------------------------------------------------------------
+BOOL SString::Equals(const SString &s) const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s.Check());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        FAULTS_UNLESS_BOTH_NORMALIZED(s, ThrowOutOfMemory());
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    StackSString temp;
+    const SString &source = GetCompatibleString(s, temp);
+
+    COUNT_T count = GetRawCount();
+
+    if (count != source.GetRawCount())
+        RETURN FALSE;
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+        RETURN (wcsncmp(GetRawUnicode(), source.GetRawUnicode(), count) == 0);
+
+    case REPRESENTATION_ASCII:
+    case REPRESENTATION_ANSI:
+        RETURN (strncmp(GetRawASCII(), source.GetRawASCII(), count) == 0);
+
+    case REPRESENTATION_EMPTY:
+        RETURN TRUE;
+
+    default:
+    case REPRESENTATION_UTF8:
+        UNREACHABLE();
+    }
+
+    RETURN FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Compare this string's contents case insensitively to s's contents.
+// Return 1 if equal, 0 if not.
+//-----------------------------------------------------------------------------
+BOOL SString::EqualsCaseInsensitive(const SString &s) const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(s.Check());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        FAULTS_UNLESS_BOTH_NORMALIZED(s, ThrowOutOfMemory());
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    StackSString temp;
+    const SString &source = GetCompatibleString(s, temp);
+
+    COUNT_T count = GetRawCount();
+
+    if (count != source.GetRawCount())
+        RETURN FALSE;
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+    case REPRESENTATION_ANSI:
+        RETURN (CaseCompareHelper(GetRawUnicode(), source.GetRawUnicode(), count, FALSE, TRUE) == 0);
+
+    case REPRESENTATION_ASCII:
+        RETURN (CaseCompareHelperA(GetRawASCII(), source.GetRawASCII(), count, FALSE, TRUE) == 0);
+
+    case REPRESENTATION_EMPTY:
+        RETURN TRUE;
+
+    default:
+    case REPRESENTATION_UTF8:
+        UNREACHABLE();
+    }
+
+    RETURN FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Compare s's contents to the substring starting at position
+// The comparison does not take into account localization issues like case folding.
+// Return TRUE if equal, FALSE if not
+//-----------------------------------------------------------------------------
+BOOL SString::Match(const CIterator &i, const SString &s) const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(s.Check());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    StackSString temp;
+    const SString &source = GetCompatibleString(s, temp, i);
+
+    COUNT_T remaining = End() - i;
+    COUNT_T count = source.GetRawCount();
+
+    if (remaining < count)
+        RETURN FALSE;
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+        RETURN (wcsncmp(i.GetUnicode(), source.GetRawUnicode(), count) == 0);
+
+    case REPRESENTATION_ASCII:
+    case REPRESENTATION_ANSI:
+        RETURN (strncmp(i.GetASCII(), source.GetRawASCII(), count) == 0);
+
+    case REPRESENTATION_EMPTY:
+        RETURN TRUE;
+
+    default:
+    case REPRESENTATION_UTF8:
+        UNREACHABLE();
+    }
+
+    RETURN FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Compare s's contents case insensitively to the substring starting at position
+// Return TRUE if equal, FALSE if not
+//-----------------------------------------------------------------------------
+BOOL SString::MatchCaseInsensitive(const CIterator &i, const SString &s) const
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        PRECONDITION(s.Check());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    StackSString temp;
+    const SString &source = GetCompatibleString(s, temp, i);
+
+    COUNT_T remaining = End() - i;
+    COUNT_T count = source.GetRawCount();
+
+    if (remaining < count)
+        RETURN FALSE;
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_UNICODE:
+    case REPRESENTATION_ANSI:
+        RETURN (CaseCompareHelper(i.GetUnicode(), source.GetRawUnicode(), count, FALSE, TRUE) == 0);
+
+    case REPRESENTATION_ASCII:
+        RETURN (CaseCompareHelperA(i.GetASCII(), source.GetRawASCII(), count, FALSE, TRUE) == 0);
+
+    case REPRESENTATION_EMPTY:
+        RETURN TRUE;
+
+    default:
+    case REPRESENTATION_UTF8:
+        UNREACHABLE();
+    }
+
+    RETURN FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Compare c case insensitively to the character at position
+// Return TRUE if equal, FALSE if not
+//-----------------------------------------------------------------------------
+BOOL SString::MatchCaseInsensitive(const CIterator &i, WCHAR c) const
+{
+    SS_CONTRACT(BOOL)
+    {
+        GC_NOTRIGGER;
+        INSTANCE_CHECK;
+        PRECONDITION(CheckIteratorRange(i));
+        NOTHROW;
+    }
+    SS_CONTRACT_END;
+
+    // End() will not throw here
+    CONTRACT_VIOLATION(ThrowsViolation);
+    if (i >= End())
+        SS_RETURN FALSE;
+
+    WCHAR test = i[0];
+
+    SS_RETURN (test == c
+               || ((CAN_SIMPLE_UPCASE(test) ? SIMPLE_UPCASE(test) : MapChar(test, LCMAP_UPPERCASE))
+                   == (CAN_SIMPLE_UPCASE(c) ? SIMPLE_UPCASE(c) : MapChar(c, LCMAP_UPPERCASE))));
+}
+
+//-----------------------------------------------------------------------------
+// Convert string to unicode lowercase using the invariant culture
+// Note: Please don't use it in PATH as multiple character can map to the same
+// lower case symbol
+//-----------------------------------------------------------------------------
+void SString::LowerCase()
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckPointer(RETVAL));
+        if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToUnicode();
+
+    for (WCHAR *pwch = GetRawUnicode(); pwch < GetRawUnicode() + GetRawCount(); ++pwch)
+    {
+        *pwch = (CAN_SIMPLE_DOWNCASE(*pwch) ? SIMPLE_DOWNCASE(*pwch) : MapChar(*pwch, LCMAP_LOWERCASE));
+    }
+}
+
+//-----------------------------------------------------------------------------
+// Convert null-terminated string to lowercase using the invariant culture
+//-----------------------------------------------------------------------------
+//static
+void SString::LowerCase(__inout_z LPWSTR wszString)
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        NOTHROW;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    if (wszString == NULL)
+    {
+        return;
+    }
+
+    for (WCHAR * pwch = wszString; *pwch != '\0'; ++pwch)
+    {
+        *pwch = (CAN_SIMPLE_DOWNCASE(*pwch) ? SIMPLE_DOWNCASE(*pwch) : MapChar(*pwch, LCMAP_LOWERCASE));
+    }
+}
+
+//-----------------------------------------------------------------------------
+// Convert string to unicode uppercase using the invariant culture
+// Note: Please don't use it in PATH as multiple character can map to the same
+// upper case symbol
+//-----------------------------------------------------------------------------
+void SString::UpperCase()
+{
+    SS_CONTRACT_VOID
+    {
+        GC_NOTRIGGER;
+        PRECONDITION(CheckPointer(this));
+        SS_POSTCONDITION(CheckPointer(RETVAL));
+        if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    SS_CONTRACT_END;
+
+    ConvertToUnicode();
+
+    for (WCHAR *pwch = GetRawUnicode(); pwch < GetRawUnicode() + GetRawCount(); ++pwch)
+    {
+        *pwch = (CAN_SIMPLE_UPCASE(*pwch) ? SIMPLE_UPCASE(*pwch) : MapChar(*pwch, LCMAP_UPPERCASE));
+    }
+}
+
+//-----------------------------------------------------------------------------
+// Get a const pointer to the internal buffer as an ANSI string.
+//-----------------------------------------------------------------------------
+const CHAR *SString::GetANSI(AbstractScratchBuffer &scratch) const
+{
+    SS_CONTRACT(const CHAR *)
+    {
+        INSTANCE_CHECK_NULL;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    SS_CONTRACT_END;
+
+    if (IsRepresentation(REPRESENTATION_ANSI))
+        SS_RETURN GetRawANSI();
+
+    ConvertToANSI((SString&)scratch);
+    SS_RETURN ((SString&)scratch).GetRawANSI();
+}
+
+//-----------------------------------------------------------------------------
+// Get a const pointer to the internal buffer as a UTF8 string.
+//-----------------------------------------------------------------------------
+const UTF8 *SString::GetUTF8(AbstractScratchBuffer &scratch) const
+{
+    CONTRACT(const UTF8 *)
+    {
+        INSTANCE_CHECK_NULL;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if (IsRepresentation(REPRESENTATION_UTF8))
+        RETURN GetRawUTF8();
+
+    ConvertToUTF8((SString&)scratch);
+    RETURN ((SString&)scratch).GetRawUTF8();
+}
+
+const UTF8 *SString::GetUTF8(AbstractScratchBuffer &scratch, COUNT_T *pcbUtf8) const
+{
+    CONTRACT(const UTF8 *)
+    {
+        INSTANCE_CHECK_NULL;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if (IsRepresentation(REPRESENTATION_UTF8))
+    {
+        *pcbUtf8 = GetRawCount() + 1;
+        RETURN GetRawUTF8();
+    }
+
+    *pcbUtf8 = ConvertToUTF8((SString&)scratch);
+    RETURN ((SString&)scratch).GetRawUTF8();
+}
+
+//-----------------------------------------------------------------------------
+// Get a const pointer to the internal buffer which must already be a UTF8 string.
+// This avoids the need to create a scratch buffer we know will never be used.
+//-----------------------------------------------------------------------------
+const UTF8 *SString::GetUTF8NoConvert() const
+{
+    CONTRACT(const UTF8 *)
+    {
+        INSTANCE_CHECK_NULL;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if (IsRepresentation(REPRESENTATION_UTF8))
+        RETURN GetRawUTF8();
+
+    ThrowHR(E_INVALIDARG);
+}
+
+//-----------------------------------------------------------------------------
+// Safe version of sprintf.
+// Prints formatted ansi text w/ var args to this buffer.
+//-----------------------------------------------------------------------------
+void SString::Printf(const CHAR *format, ...)
+{
+    WRAPPER_NO_CONTRACT;
+
+    va_list args;
+    va_start(args, format);
+    VPrintf(format, args);
+    va_end(args);
+}
+
+#ifdef _DEBUG
+//
+// Check the Printf use for potential globalization bugs. %S formatting
+// specifier does Unicode->Ansi or Ansi->Unicode conversion using current
+// C-locale. This almost always means globalization bug in the CLR codebase.
+//
+// Ideally, we would elimitate %S from all format strings. Unfortunately,
+// %S is too widespread in non-shipping code that such cleanup is not feasible.
+//
+static void CheckForFormatStringGlobalizationIssues(const SString &format, const SString &result)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        DEBUG_ONLY;
+    }
+    CONTRACTL_END;
+
+    BOOL fDangerousFormat = FALSE;
+
+    // Check whether the format string contains the %S formatting specifier
+    SString::CIterator itrFormat = format.Begin();
+    while (*itrFormat)
+    {
+        if (*itrFormat++ == '%')
+        {
+            // <TODO>Handle the complex format strings like %blahS</TODO>
+            if (*itrFormat++ == 'S')
+            {
+                fDangerousFormat = TRUE;
+                break;
+            }
+        }
+    }
+
+    if (fDangerousFormat)
+    {
+        BOOL fNonAsciiUsed = FALSE;
+
+        // Now check whether there are any non-ASCII characters in the output.
+
+        // Check whether the result contains non-Ascii characters
+        SString::CIterator itrResult = format.Begin();
+        while (*itrResult)
+        {
+            if (*itrResult++ > 127)
+            {
+                fNonAsciiUsed = TRUE;
+                break;
+            }
+        }
+
+        CONSISTENCY_CHECK_MSGF(!fNonAsciiUsed,
+            ("Non-ASCII string was produced by %%S format specifier. This is likely globalization bug."
+            "To fix this, change the format string to %%s and do the correct encoding at the Printf callsite"));
+    }
+}
+#endif
+
+#ifndef EBADF
+#define EBADF 9
+#endif
+
+#ifndef ENOMEM
+#define ENOMEM 12
+#endif
+
+#ifndef ERANGE
+#define ERANGE 34
+#endif
+
+#if defined(_MSC_VER)
+#undef va_copy
+#define va_copy(dest,src) (dest = src)
+#endif
+
+void SString::VPrintf(const CHAR *format, va_list args)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(format));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    va_list ap;
+    // sprintf gives us no means to know how many characters are written
+    // other than guessing and trying
+
+    if (GetRawCount() > 0)
+    {
+        // First, try to use the existing buffer
+        va_copy(ap, args);
+        int result = _vsnprintf_s(GetRawANSI(), GetRawCount()+1, _TRUNCATE, format, ap);
+        va_end(ap);
+
+        if (result >=0)
+        {
+            // Succeeded in writing. Now resize -
+            Resize(result, REPRESENTATION_ANSI, PRESERVE);
+            SString sss(Ansi, format);
+            INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
+            RETURN;
+        }
+    }
+
+    // Make a guess how long the result will be (note this will be doubled)
+
+    COUNT_T guess = (COUNT_T) strlen(format)+1;
+    if (guess < GetRawCount())
+        guess = GetRawCount();
+    if (guess < MINIMUM_GUESS)
+        guess = MINIMUM_GUESS;
+
+    while (TRUE)
+    {
+        // Double the previous guess - eventually we will get enough space
+        guess *= 2;
+        Resize(guess, REPRESENTATION_ANSI);
+
+        // Clear errno to avoid false alarms
+        errno = 0;
+
+        va_copy(ap, args);
+        int result = _vsnprintf_s(GetRawANSI(), GetRawCount()+1, _TRUNCATE, format, ap);
+        va_end(ap);
+
+        if (result >= 0)
+        {
+            // Succeed in writing. Shrink the buffer to fit exactly.
+            Resize(result, REPRESENTATION_ANSI, PRESERVE);
+            SString sss(Ansi, format);
+            INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
+            RETURN;
+        }
+
+        if (errno==ENOMEM)
+        {
+            ThrowOutOfMemory();
+        }
+        else
+        if (errno!=0 && errno!=EBADF && errno!=ERANGE)
+        {
+            CONSISTENCY_CHECK_MSG(FALSE, "_vsnprintf_s failed. Potential globalization bug.");
+            ThrowHR(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION));
+        }
+    }
+    RETURN;
+}
+
+void SString::Printf(const WCHAR *format, ...)
+{
+    WRAPPER_NO_CONTRACT;
+
+    va_list args;
+    va_start(args, format);
+    VPrintf(format, args);
+    va_end(args);
+}
+
+void SString::PPrintf(const WCHAR *format, ...)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(format));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    va_list argItr;
+    va_start(argItr, format);
+    PVPrintf(format, argItr);
+    va_end(argItr);
+
+    RETURN;
+}
+
+void SString::VPrintf(const WCHAR *format, va_list args)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(format));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    va_list ap;
+    // sprintf gives us no means to know how many characters are written
+    // other than guessing and trying
+
+    if (GetRawCount() > 0)
+    {
+        // First, try to use the existing buffer
+        va_copy(ap, args);
+        int result = _vsnwprintf_s(GetRawUnicode(), GetRawCount()+1, _TRUNCATE, format, ap);
+        va_end(ap);
+
+        if (result >= 0)
+        {
+            // succeeded
+            Resize(result, REPRESENTATION_UNICODE, PRESERVE);
+            SString sss(format);
+            INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
+            RETURN;
+        }
+    }
+
+    // Make a guess how long the result will be (note this will be doubled)
+
+    COUNT_T guess = (COUNT_T) wcslen(format)+1;
+    if (guess < GetRawCount())
+        guess = GetRawCount();
+    if (guess < MINIMUM_GUESS)
+        guess = MINIMUM_GUESS;
+
+    while (TRUE)
+    {
+        // Double the previous guess - eventually we will get enough space
+        guess *= 2;
+        Resize(guess, REPRESENTATION_UNICODE);
+
+        // Clear errno to avoid false alarms
+        errno = 0;
+
+        va_copy(ap, args);
+        int result = _vsnwprintf_s(GetRawUnicode(), GetRawCount()+1, _TRUNCATE, format, ap);
+        va_end(ap);
+
+        if (result >= 0)
+        {
+            Resize(result, REPRESENTATION_UNICODE, PRESERVE);
+            SString sss(format);
+            INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
+            RETURN;
+        }
+
+        if (errno==ENOMEM)
+        {
+            ThrowOutOfMemory();
+        }
+        else
+        if (errno!=0 && errno!=EBADF && errno!=ERANGE)
+        {
+            CONSISTENCY_CHECK_MSG(FALSE, "_vsnwprintf_s failed. Potential globalization bug.");
+            ThrowHR(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION));
+        }
+    }
+    RETURN;
+}
+
+void SString::PVPrintf(const WCHAR *format, va_list args)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        PRECONDITION(CheckPointer(format));
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    va_list ap;
+    // sprintf gives us no means to know how many characters are written
+    // other than guessing and trying
+
+    if (GetRawCount() > 0)
+    {
+        // First, try to use the existing buffer
+        va_copy(ap, args);
+#if defined(FEATURE_CORESYSTEM)
+        int result = _vsnwprintf_s(GetRawUnicode(), GetRawCount()+1, _TRUNCATE, format, ap);
+#else
+        int result = _vswprintf_p(GetRawUnicode(), GetRawCount()+1, format, ap);
+#endif
+        va_end(ap);
+        if (result >= 0)
+        {
+            // succeeded
+            Resize(result, REPRESENTATION_UNICODE, PRESERVE);
+            SString sss(format);
+            INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
+            RETURN;
+        }
+    }
+
+    // Make a guess how long the result will be (note this will be doubled)
+
+    COUNT_T guess = (COUNT_T) wcslen(format)+1;
+    if (guess < GetRawCount())
+        guess = GetRawCount();
+    if (guess < MINIMUM_GUESS)
+        guess = MINIMUM_GUESS;
+
+    while (TRUE)
+    {
+        // Double the previous guess - eventually we will get enough space
+        guess *= 2;
+        Resize(guess, REPRESENTATION_UNICODE, DONT_PRESERVE);
+
+        // Clear errno to avoid false alarms
+        errno = 0;
+
+        va_copy(ap, args);
+#if defined(FEATURE_CORESYSTEM)
+        int result = _vsnwprintf_s(GetRawUnicode(), GetRawCount()+1, _TRUNCATE, format, ap);
+#else
+        int result = _vswprintf_p(GetRawUnicode(), GetRawCount()+1, format, ap);
+#endif
+        va_end(ap);
+
+        if (result >= 0)
+        {
+            Resize(result, REPRESENTATION_UNICODE, PRESERVE);
+            SString sss(format);
+            INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
+            RETURN;
+        }
+
+        if (errno==ENOMEM)
+        {
+            ThrowOutOfMemory();
+        }
+        else
+        if (errno!=0 && errno!=EBADF && errno!=ERANGE)
+        {
+            CONSISTENCY_CHECK_MSG(FALSE, "_vsnwprintf_s failed. Potential globalization bug.");
+            ThrowHR(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION));
+        }
+    }
+    RETURN;
+}
+
+void SString::AppendPrintf(const CHAR *format, ...)
+{
+    WRAPPER_NO_CONTRACT;
+
+    va_list args;
+    va_start(args, format);
+    AppendVPrintf(format, args);
+    va_end(args);
+}
+
+void SString::AppendVPrintf(const CHAR *format, va_list args)
+{
+    WRAPPER_NO_CONTRACT;
+
+    StackSString s;
+    s.VPrintf(format, args);
+    Append(s);
+}
+
+void SString::AppendPrintf(const WCHAR *format, ...)
+{
+    WRAPPER_NO_CONTRACT;
+
+    va_list args;
+    va_start(args, format);
+    AppendVPrintf(format, args);
+    va_end(args);
+}
+
+void SString::AppendVPrintf(const WCHAR *format, va_list args)
+{
+    WRAPPER_NO_CONTRACT;
+
+    StackSString s;
+    s.VPrintf(format, args);
+    Append(s);
+}
+
+//----------------------------------------------------------------------------
+// LoadResource - moved to sstring_com.cpp
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// Format the message and put the contents in this string
+//----------------------------------------------------------------------------
+
+BOOL SString::FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId,
+                            const SString &arg1, const SString &arg2,
+                            const SString &arg3, const SString &arg4,
+                            const SString &arg5, const SString &arg6,
+                            const SString &arg7, const SString &arg8,
+                            const SString &arg9, const SString &arg10)
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    const WCHAR *args[] = {arg1.GetUnicode(), arg2.GetUnicode(), arg3.GetUnicode(), arg4.GetUnicode(),
+                           arg5.GetUnicode(), arg6.GetUnicode(), arg7.GetUnicode(), arg8.GetUnicode(),
+                           arg9.GetUnicode(), arg10.GetUnicode()};
+
+    if (GetRawCount() > 0)
+    {
+        // First, try to use our existing buffer to hold the result.
+        Resize(GetRawCount(), REPRESENTATION_UNICODE);
+
+        DWORD result = ::WszFormatMessage(dwFlags | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+                                          lpSource, dwMessageId, dwLanguageId,
+                                          GetRawUnicode(), GetRawCount()+1, (va_list*)args);
+
+        // Although we cannot directly detect truncation, we can tell if we
+        // used up all the space (in which case we will assume truncation.)
+
+        if (result != 0 && result < GetRawCount())
+        {
+            if (GetRawUnicode()[result-1] == W(' '))
+            {
+                GetRawUnicode()[result-1] = W('\0');
+                result -= 1;
+            }
+            Resize(result, REPRESENTATION_UNICODE, PRESERVE);
+            RETURN TRUE;
+        }
+    }
+
+    // We don't have enough space in our buffer, do dynamic allocation.
+    LocalAllocHolder<WCHAR> string;
+
+    DWORD result = ::WszFormatMessage(dwFlags | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+                                      lpSource, dwMessageId, dwLanguageId,
+                                      (LPWSTR)(LPWSTR*)&string, 0, (va_list*)args);
+
+    if (result == 0)
+        RETURN FALSE;
+    else
+    {
+        if (string[result-1] == W(' '))
+            string[result-1] = W('\0');
+
+        Set(string);
+        RETURN TRUE;
+    }
+}
+
+#if 1
+//----------------------------------------------------------------------------
+// Helper
+//----------------------------------------------------------------------------
+
+// @todo -this should be removed and placed outside of SString
+void SString::MakeFullNamespacePath(const SString &nameSpace, const SString &name)
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        THROWS;
+        GC_NOTRIGGER;
+    }
+    CONTRACT_END;
+
+    if (nameSpace.GetRepresentation() == REPRESENTATION_UTF8
+        && name.GetRepresentation() == REPRESENTATION_UTF8)
+    {
+        const UTF8 *ns = nameSpace.GetRawUTF8();
+        const UTF8 *n = name.GetRawUTF8();
+        COUNT_T count = ns::GetFullLength(ns, n)-1;
+        Resize(count, REPRESENTATION_UTF8);
+        if (count > 0)
+            ns::MakePath(GetRawUTF8(), count+1, ns, n);
+    }
+    else
+    {
+        const WCHAR *ns = nameSpace;
+        const WCHAR *n = name;
+        COUNT_T count = ns::GetFullLength(ns, n)-1;
+        Resize(count, REPRESENTATION_UNICODE);
+        if (count > 0)
+            ns::MakePath(GetRawUnicode(), count+1, ns, n);
+    }
+
+    RETURN;
+}
+#endif
+
+
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Check to see if the string fits the suggested representation
+//----------------------------------------------------------------------------
+BOOL SString::IsRepresentation(Representation representation) const
+{
+    CONTRACT(BOOL)
+    {
+        PRECONDITION(CheckRepresentation(representation));
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    Representation currentRepresentation = GetRepresentation();
+
+    // If representations are the same, cool.
+    if (currentRepresentation == representation)
+        RETURN TRUE;
+
+    // If we have an empty representation, we match everything
+    if (currentRepresentation == REPRESENTATION_EMPTY)
+        RETURN TRUE;
+
+    // If we're a 1 byte charset, there are some more chances to match
+    if (currentRepresentation != REPRESENTATION_UNICODE
+        && representation != REPRESENTATION_UNICODE)
+    {
+        // If we're ASCII, we can be any 1 byte rep
+        if (currentRepresentation == REPRESENTATION_ASCII)
+            RETURN TRUE;
+
+        // We really want to be ASCII - scan to see if we qualify
+        if (ScanASCII())
+            RETURN TRUE;
+    }
+
+    // Sorry, must convert.
+    RETURN FALSE;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Get the contents of the given string in a form which is compatible with our
+// string (and is in a fixed character set.)  Updates the given iterator
+// if necessary to keep it in sync.
+//----------------------------------------------------------------------------
+const SString &SString::GetCompatibleString(const SString &s, SString &scratch, const CIterator &i) const
+{
+    CONTRACTL
+    {
+        PRECONDITION(s.Check());
+        PRECONDITION(scratch.Check());
+        PRECONDITION(scratch.CheckEmpty());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACTL_END;
+
+    // Since we have an iterator, we should be fixed size already
+    CONSISTENCY_CHECK(IsFixedSize());
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_EMPTY:
+        return s;
+
+    case REPRESENTATION_ASCII:
+        if (s.IsRepresentation(REPRESENTATION_ASCII))
+            return s;
+
+        // We can't in general convert to ASCII, so try unicode.
+        ConvertToUnicode(i);
+        FALLTHROUGH;
+
+    case REPRESENTATION_UNICODE:
+        if (s.IsRepresentation(REPRESENTATION_UNICODE))
+            return s;
+
+        // @todo: we could convert s to unicode - is that a good policy????
+        s.ConvertToUnicode(scratch);
+        return scratch;
+
+    case REPRESENTATION_UTF8:
+    case REPRESENTATION_ANSI:
+        // These should all be impossible since we have an CIterator on us.
+    default:
+        UNREACHABLE_MSG("Unexpected string representation");
+    }
+
+    return s;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Get the contents of the given string in a form which is compatible with our
+// string (and is in a fixed character set.)
+// May convert our string to unicode.
+//----------------------------------------------------------------------------
+const SString &SString::GetCompatibleString(const SString &s, SString &scratch) const
+{
+    CONTRACTL
+    {
+        PRECONDITION(s.Check());
+        PRECONDITION(scratch.Check());
+        PRECONDITION(scratch.CheckEmpty());
+        THROWS_UNLESS_BOTH_NORMALIZED(s);
+        GC_NOTRIGGER;
+    }
+    CONTRACTL_END;
+
+    // First, make sure we have a fixed size.
+    ConvertToFixed();
+
+    switch (GetRepresentation())
+    {
+    case REPRESENTATION_EMPTY:
+        return s;
+
+    case REPRESENTATION_ANSI:
+        if (s.IsRepresentation(REPRESENTATION_ANSI))
+            return s;
+
+        s.ConvertToANSI(scratch);
+        return scratch;
+
+    case REPRESENTATION_ASCII:
+        if (s.IsRepresentation(REPRESENTATION_ASCII))
+            return s;
+
+        // We can't in general convert to ASCII, so try unicode.
+        ConvertToUnicode();
+        FALLTHROUGH;
+
+    case REPRESENTATION_UNICODE:
+        if (s.IsRepresentation(REPRESENTATION_UNICODE))
+            return s;
+
+        // @todo: we could convert s to unicode in place - is that a good policy????
+        s.ConvertToUnicode(scratch);
+        return scratch;
+
+    case REPRESENTATION_UTF8:
+    default:
+        UNREACHABLE();
+    }
+
+    return s;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// If we have a 1 byte representation, scan the buffer to see if we can gain
+// some conversion flexibility by labelling it ASCII
+//----------------------------------------------------------------------------
+BOOL SString::ScanASCII() const
+{
+    CONTRACT(BOOL)
+    {
+        POSTCONDITION(IsRepresentation(REPRESENTATION_ASCII) || IsASCIIScanned());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC;
+    }
+    CONTRACT_END;
+
+    if (!IsASCIIScanned())
+    {
+        const CHAR *c = GetRawANSI();
+        const CHAR *cEnd = c + GetRawCount();
+        while (c < cEnd)
+        {
+            if (*c & 0x80)
+                break;
+            c++;
+        }
+        if (c == cEnd)
+        {
+            const_cast<SString *>(this)->SetRepresentation(REPRESENTATION_ASCII);
+            RETURN TRUE;
+        }
+        else
+            const_cast<SString *>(this)->SetASCIIScanned();
+    }
+    RETURN FALSE;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Resize updates the geometry of the string and ensures that
+// the space can be written to.
+// count - number of characters (not including null) to hold
+// preserve - if we realloc, do we copy data from old to new?
+//----------------------------------------------------------------------------
+
+void SString::Resize(COUNT_T count, SString::Representation representation, Preserve preserve)
+{
+    CONTRACT_VOID
+    {
+        PRECONDITION(CountToSize(count) >= count);
+        POSTCONDITION(IsRepresentation(representation));
+        POSTCONDITION(GetRawCount() == count);
+        if (count == 0) NOTHROW; else THROWS;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    // If we are resizing to zero, Clear is more efficient
+    if (count == 0)
+    {
+        Clear();
+    }
+    else
+    {
+        SetRepresentation(representation);
+
+        COUNT_T size = CountToSize(count);
+
+        // detect overflow
+        if (size < count)
+            ThrowOutOfMemory();
+
+        ClearNormalized();
+
+        SBuffer::Resize(size, preserve);
+
+        if (IsImmutable())
+            EnsureMutable();
+
+        NullTerminate();
+    }
+
+    RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// This is essentially a specialized version of the above for size 0
+//-----------------------------------------------------------------------------
+void SString::Clear()
+{
+    CONTRACT_VOID
+    {
+        INSTANCE_CHECK;
+        POSTCONDITION(IsEmpty());
+        NOTHROW;
+        GC_NOTRIGGER;
+        SUPPORTS_DAC_HOST_ONLY;
+    }
+    CONTRACT_END;
+
+    SetRepresentation(REPRESENTATION_EMPTY);
+
+    if (IsImmutable())
+    {
+        // Use shared empty string rather than allocating a new buffer
+        SBuffer::SetImmutable(s_EmptyBuffer, sizeof(s_EmptyBuffer));
+    }
+    else
+    {
+        // Leave allocated buffer for future growth
+        SBuffer::TweakSize(sizeof(WCHAR));
+        GetRawUnicode()[0] = 0;
+    }
+
+    RETURN;
+}
+
+
+#ifdef DACCESS_COMPILE
+
+//---------------------------------------------------------------------------------------
+//
+// Return a pointer to the raw buffer
+//
+// Returns:
+//    A pointer to the raw string buffer.
+//
+void * SString::DacGetRawContent() const
+{
+    if (IsEmpty())
+    {
+        return NULL;
+    }
+
+    switch (GetRepresentation())
+    {
+        case REPRESENTATION_EMPTY:
+            return NULL;
+
+        case REPRESENTATION_UNICODE:
+        case REPRESENTATION_UTF8:
+        case REPRESENTATION_ASCII:
+        case REPRESENTATION_ANSI:
+            // Note: no need to call DacInstantiateString because we know the exact length already.
+            return SBuffer::DacGetRawContent();
+
+        default:
+            DacNotImpl();
+            return NULL;
+    }
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Return a pointer to the raw buffer as a pointer to a unicode string.  Does not
+// do conversion, and thus requires that the representation already be in unicode.
+//
+// Returns:
+//    A pointer to the raw string buffer as a unicode string.
+//
+const WCHAR * SString::DacGetRawUnicode() const
+{
+    if (IsEmpty() || (GetRepresentation() == REPRESENTATION_EMPTY))
+    {
+        return W("");
+    }
+
+    if (GetRepresentation() != REPRESENTATION_UNICODE)
+    {
+        DacError(E_UNEXPECTED);
+    }
+
+    HRESULT status = S_OK;
+    WCHAR* wszBuf = NULL;
+    EX_TRY
+    {
+        wszBuf = static_cast<WCHAR*>(SBuffer::DacGetRawContent());
+    }
+    EX_CATCH_HRESULT(status);
+
+    if (SUCCEEDED(status))
+    {
+        return wszBuf;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Copy the string from the target into the provided buffer, converting to unicode if necessary
+//
+// Arguments:
+//    cBufChars - size of pBuffer in count of unicode characters.
+//    pBuffer - a buffer of cBufChars unicode chars.
+//    pcNeedChars - space to store the number of unicode chars in the SString.
+//
+// Returns:
+//    true if successful - and buffer is filled with the unicode representation of
+//       the string.
+//    false if unsuccessful.
+//
+bool SString::DacGetUnicode(COUNT_T                                   cBufChars,
+                            _Inout_updates_z_(cBufChars) WCHAR * pBuffer,
+                            COUNT_T *                                 pcNeedChars) const
+{
+    SUPPORTS_DAC;
+
+    PVOID pContent = NULL;
+    int iPage = CP_ACP;
+
+    if (IsEmpty() || (GetRepresentation() == REPRESENTATION_EMPTY))
+    {
+        if (pcNeedChars)
+        {
+            *pcNeedChars = 1;
+        }
+        if (pBuffer && cBufChars)
+        {
+            pBuffer[0] = 0;
+        }
+        return true;
+    }
+
+    HRESULT status = S_OK;
+    EX_TRY
+    {
+        pContent = SBuffer::DacGetRawContent();
+    }
+    EX_CATCH_HRESULT(status);
+
+    if (SUCCEEDED(status) && pContent != NULL)
+    {
+        switch (GetRepresentation())
+        {
+
+        case REPRESENTATION_UNICODE:
+
+            if (pcNeedChars)
+            {
+                *pcNeedChars = GetCount() + 1;
+            }
+
+            if (pBuffer && cBufChars)
+            {
+                if (cBufChars > GetCount() + 1)
+                {
+                    cBufChars = GetCount() + 1;
+                }
+                memcpy(pBuffer, pContent, cBufChars * sizeof(*pBuffer));
+                pBuffer[cBufChars - 1] = 0;
+            }
+
+            return true;
+
+        case REPRESENTATION_UTF8:
+            iPage = CP_UTF8;
+            FALLTHROUGH;
+        case REPRESENTATION_ASCII:
+        case REPRESENTATION_ANSI:
+            // iPage defaults to CP_ACP.
+            if (pcNeedChars)
+            {
+                *pcNeedChars = WszMultiByteToWideChar(iPage, 0, reinterpret_cast<PSTR>(pContent), -1, NULL, 0);
+            }
+            if (pBuffer && cBufChars)
+            {
+                if (!WszMultiByteToWideChar(iPage, 0, reinterpret_cast<PSTR>(pContent), -1, pBuffer, cBufChars))
+                {
+                    return false;
+                }
+            }
+            return true;
+
+        default:
+            DacNotImpl();
+            return false;
+        }
+    }
+    return false;
+}
+
+#endif //DACCESS_COMPILE
diff --git a/src/utilcode/sstring_com.cpp b/src/utilcode/sstring_com.cpp
new file mode 100644 (file)
index 0000000..396ec95
--- /dev/null
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ---------------------------------------------------------------------------
+// SString_COM.cpp
+
+// ---------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "sstring.h"
+#include "ex.h"
+#include "holder.h"
+
+#define DEFAULT_RESOURCE_STRING_SIZE 255
+
+//----------------------------------------------------------------------------
+// Load the string resource into this string.
+//----------------------------------------------------------------------------
+BOOL SString::LoadResource(CCompRC::ResourceCategory eCategory, int resourceID)
+{
+    return SUCCEEDED(LoadResourceAndReturnHR(eCategory, resourceID));
+}
+
+HRESULT SString::LoadResourceAndReturnHR(CCompRC::ResourceCategory eCategory, int resourceID)
+{
+    WRAPPER_NO_CONTRACT;
+    return LoadResourceAndReturnHR(NULL, eCategory,resourceID);
+}
+
+HRESULT SString::LoadResourceAndReturnHR(CCompRC* pResourceDLL, CCompRC::ResourceCategory eCategory, int resourceID)
+{
+    CONTRACT(BOOL)
+    {
+        INSTANCE_CHECK;
+        NOTHROW;
+    }
+    CONTRACT_END;
+
+    HRESULT hr = E_FAIL;
+
+#ifndef FEATURE_UTILCODE_NO_DEPENDENCIES
+    if (pResourceDLL == NULL)
+    {
+        pResourceDLL = CCompRC::GetDefaultResourceDll();
+    }
+
+    if (pResourceDLL != NULL)
+    {
+
+        int size = 0;
+
+        EX_TRY
+        {
+            if (GetRawCount() == 0)
+                Resize(DEFAULT_RESOURCE_STRING_SIZE, REPRESENTATION_UNICODE);
+
+            while (TRUE)
+            {
+                // First try and load the string in the amount of space that we have.
+                // In fatal error reporting scenarios, we may not have enough memory to
+                // allocate a larger buffer.
+
+                hr = pResourceDLL->LoadString(eCategory, resourceID, GetRawUnicode(), GetRawCount()+1, &size);
+                if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+                {
+                    if (FAILED(hr))
+                    {
+                        Clear();
+                        break;
+                    }
+
+                    // Although we cannot generally detect truncation, we can tell if we
+                    // used up all the space (in which case we will assume truncation.)
+                    if (size < (int)GetRawCount())
+                    {
+                        break;
+                    }
+                }
+
+                // Double the size and try again.
+                Resize(size*2, REPRESENTATION_UNICODE);
+
+            }
+
+            if (SUCCEEDED(hr))
+            {
+                Truncate(Begin() + (COUNT_T) wcslen(GetRawUnicode()));
+            }
+
+            Normalize();
+
+        }
+        EX_CATCH
+        {
+            hr = E_FAIL;
+        }
+        EX_END_CATCH(SwallowAllExceptions);
+    }
+#endif //!FEATURE_UTILCODE_NO_DEPENDENCIES
+
+    RETURN hr;
+} // SString::LoadResourceAndReturnHR
diff --git a/src/utilcode/stdafx.h b/src/utilcode/stdafx.h
new file mode 100644 (file)
index 0000000..f04d0e4
--- /dev/null
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// stdafx.h
+//
+
+//
+// Common include file for utility code.
+//*****************************************************************************
+#pragma once
+
+#include <switches.h>
+#include <crtwrap.h>
+
+#define IN_WINFIX_CPP
+
+#include <winwrap.h>
+
+#include "volatile.h"
+#include "static_assert.h"
+
diff --git a/src/utilcode/utilcode.vcxproj b/src/utilcode/utilcode.vcxproj
new file mode 100644 (file)
index 0000000..7fe96f2
--- /dev/null
@@ -0,0 +1,340 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <PreferredToolArchitecture>x64</PreferredToolArchitecture>
+  </PropertyGroup>
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Checked|x64">
+      <Configuration>Checked</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="RelWithDebInfo|x64">
+      <Configuration>RelWithDebInfo</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{8C35FEF8-1101-38F6-ACD0-462A1EA53A7D}</ProjectGuid>
+    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <Keyword>Win32Proj</Keyword>
+    <Platform>x64</Platform>
+    <ProjectName>utilcode</ProjectName>
+    <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Checked|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.20506.1</_ProjectFileVersion>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode\Debug\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">utilcodestaticnohost.dir\Debug\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">utilcodestaticnohost</TargetName>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.lib</TargetExt>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode\Checked\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">utilcodestaticnohost.dir\Checked\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">utilcodestaticnohost</TargetName>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">.lib</TargetExt>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode\Release\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">utilcodestaticnohost.dir\Release\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">utilcodestaticnohost</TargetName>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.lib</TargetExt>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode\RelWithDebInfo\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">utilcodestaticnohost.dir\RelWithDebInfo\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">utilcodestaticnohost</TargetName>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">.lib</TargetExt>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont /Zm200 /Zc:strictStrings /w34092 /w34121 /w34125 /w34130 /w34132 /w34212 /w34530 /w35038 /w44177 /ZH:SHA_256 /source-charset:utf-8 /homeparams</AdditionalOptions>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <ControlFlowGuard>Guard</ControlFlowGuard>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4065;4100;4127;4189;4200;4201;4245;4291;4456;4457;4458;4733;4838;4960;4961;5105;4603;4627;4459;4091</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <FloatingPointModel>Precise</FloatingPointModel>
+      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>Disabled</Optimization>
+      <RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatSpecificWarningsAsErrors>4007;4013;4102;4551;4700;4640;4806</TreatSpecificWarningsAsErrors>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <UseFullPaths>true</UseFullPaths>
+      <WarningLevel>Level3</WarningLevel>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Debug;BUILDENV_DEBUG=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;DEBUG;_DBG;URTBLDENV_FRIENDLY=Debug;BUILDENV_DEBUG=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+    <MASM>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Debug;BUILDENV_DEBUG=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR="Debug";;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <IncludePaths>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(IncludePaths)</IncludePaths>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont</AdditionalOptions>
+    </MASM>
+    <Midl>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
+      <HeaderFileName>%(Filename).h</HeaderFileName>
+      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
+      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
+    </Midl>
+    <Lib>
+      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /IGNORE:4221</AdditionalOptions>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Checked|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont /Zm200 /Zc:strictStrings /w34092 /w34121 /w34125 /w34130 /w34132 /w34212 /w34530 /w35038 /w44177 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <ControlFlowGuard>Guard</ControlFlowGuard>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4065;4100;4127;4189;4200;4201;4245;4291;4456;4457;4458;4733;4838;4960;4961;5105;4603;4627;4459;4091</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <FloatingPointModel>Precise</FloatingPointModel>
+      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>MaxSpeed</Optimization>
+      <RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatSpecificWarningsAsErrors>4007;4013;4102;4551;4700;4640;4806</TreatSpecificWarningsAsErrors>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <UseFullPaths>true</UseFullPaths>
+      <WarningLevel>Level3</WarningLevel>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR="Checked";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR=\"Checked\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+    <MASM>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;DEBUG;_DEBUG;_DBG;URTBLDENV_FRIENDLY=Checked;BUILDENV_CHECKED=1;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR="Checked";;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <IncludePaths>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(IncludePaths)</IncludePaths>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont</AdditionalOptions>
+    </MASM>
+    <Midl>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
+      <HeaderFileName>%(Filename).h</HeaderFileName>
+      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
+      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
+    </Midl>
+    <Lib>
+      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /IGNORE:4221</AdditionalOptions>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont /Zm200 /Zc:strictStrings /w34092 /w34121 /w34125 /w34130 /w34132 /w34212 /w34530 /w35038 /w44177 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <ControlFlowGuard>Guard</ControlFlowGuard>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4065;4100;4127;4189;4200;4201;4245;4291;4456;4457;4458;4733;4838;4960;4961;5105;4603;4627;4459;4091</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <FloatingPointModel>Precise</FloatingPointModel>
+      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>Full</Optimization>
+      <RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatSpecificWarningsAsErrors>4007;4013;4102;4551;4700;4640;4806</TreatSpecificWarningsAsErrors>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <UseFullPaths>true</UseFullPaths>
+      <WarningLevel>Level3</WarningLevel>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR="Release";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+    <MASM>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR="Release";;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <IncludePaths>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(IncludePaths)</IncludePaths>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont</AdditionalOptions>
+    </MASM>
+    <Midl>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
+      <HeaderFileName>%(Filename).h</HeaderFileName>
+      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
+      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
+    </Midl>
+    <Lib>
+      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /IGNORE:4221</AdditionalOptions>
+      <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont /Zm200 /Zc:strictStrings /w34092 /w34121 /w34125 /w34130 /w34132 /w34212 /w34530 /w35038 /w44177 /ZH:SHA_256 /source-charset:utf-8</AdditionalOptions>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <ControlFlowGuard>Guard</ControlFlowGuard>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4065;4100;4127;4189;4200;4201;4245;4291;4456;4457;4458;4733;4838;4960;4961;5105;4603;4627;4459;4091</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <FloatingPointModel>Precise</FloatingPointModel>
+      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>MaxSpeed</Optimization>
+      <RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatSpecificWarningsAsErrors>4007;4013;4102;4551;4700;4640;4806</TreatSpecificWarningsAsErrors>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <UseFullPaths>true</UseFullPaths>
+      <WarningLevel>Level3</WarningLevel>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+    <MASM>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_CRTIMP=;FEATURE_UTILCODE_NO_DEPENDENCIES;SELF_NO_HOST;URTBLDENV_FRIENDLY=Retail;HOST_AMD64;HOST_64BIT;HOST_WINDOWS;_FILE_OFFSET_BITS=64;TARGET_AMD64;TARGET_64BIT;TARGET_WINDOWS;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;FEATURE_CORESYSTEM;FEATURE_COMINTEROP;FEATURE_HIJACK;_BLD_CLR;CMAKE_INTDIR="RelWithDebInfo";;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <IncludePaths>$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(IncludePaths)</IncludePaths>
+      <AdditionalOptions>%(AdditionalOptions) /guard:ehcont</AdditionalOptions>
+    </MASM>
+    <Midl>
+      <AdditionalIncludeDirectories>$(ArtifactsObjDir)\Windows_NT.x64.Debug\src\utilcode;$(RepoRoot)src\utilcode;$(ArtifactsObjDir);$(RepoRoot)src;$(RepoRoot)src\pal\prebuilt\inc;$(RepoRoot)src\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
+      <HeaderFileName>%(Filename).h</HeaderFileName>
+      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>
+      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>%(Filename)_p.c</ProxyFileName>
+    </Midl>
+    <Lib>
+      <AdditionalOptions>%(AdditionalOptions) /machine:x64 /IGNORE:4221</AdditionalOptions>
+      <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="clrhost_nodependencies.cpp">
+    </ClCompile>
+    <ClCompile Include="ex.cpp">
+    </ClCompile>
+    <ClCompile Include="sbuffer.cpp">
+    </ClCompile>
+    <ClCompile Include="sstring_com.cpp">
+    </ClCompile>
+    <ClCompile Include="fstring.cpp">
+    </ClCompile>
+    <ClCompile Include="namespaceutil.cpp">
+    </ClCompile>
+    <ClCompile Include="check.cpp">
+    </ClCompile>
+    <ClCompile Include="sstring.cpp">
+    </ClCompile>
+    <ClCompile Include="safewrap.cpp">
+    </ClCompile>
+    <ClCompile Include="debug.cpp">
+    </ClCompile>
+    <ClCompile Include="pedecoder.cpp">
+    </ClCompile>
+    <ClCompile Include="longfilepathwrappers.cpp">
+    </ClCompile>
+    <ClCompile Include="dlwrap.cpp">
+    </ClCompile>
+    <ClCompile Include="securitywrapper.cpp">
+    </ClCompile>
+    <ClCompile Include="securityutil.cpp">
+    </ClCompile>
+    <ClCompile Include="hostimpl.cpp">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="CMakeLists.txt" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="stdafx.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/utilcode/utilcode.vcxproj.filters b/src/utilcode/utilcode.vcxproj.filters
new file mode 100644 (file)
index 0000000..622fe67
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="clrhost_nodependencies.cpp">
+    </ClCompile>
+    <ClCompile Include="ex.cpp">
+    </ClCompile>
+    <ClCompile Include="sbuffer.cpp">
+    </ClCompile>
+    <ClCompile Include="sstring_com.cpp">
+    </ClCompile>
+    <ClCompile Include="fstring.cpp">
+    </ClCompile>
+    <ClCompile Include="namespaceutil.cpp">
+    </ClCompile>
+    <ClCompile Include="check.cpp">
+    </ClCompile>
+    <ClCompile Include="sstring.cpp">
+    </ClCompile>
+    <ClCompile Include="safewrap.cpp">
+    </ClCompile>
+    <ClCompile Include="debug.cpp">
+    </ClCompile>
+    <ClCompile Include="pedecoder.cpp">
+    </ClCompile>
+    <ClCompile Include="longfilepathwrappers.cpp">
+    </ClCompile>
+    <ClCompile Include="dlwrap.cpp">
+    </ClCompile>
+    <ClCompile Include="securitywrapper.cpp">
+    </ClCompile>
+    <ClCompile Include="securityutil.cpp">
+    </ClCompile>
+    <ClCompile Include="hostimpl.cpp">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="CMakeLists.txt" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="stdafx.h" />
+  </ItemGroup>
+</Project>
\ No newline at end of file