Merge pull request #11406 from sdmaclea/PR-ARM64-ENABLE-FEATURE_TAILCALL_OPT
authorBruce Forstall <brucefo@microsoft.com>
Tue, 9 May 2017 19:05:20 +0000 (12:05 -0700)
committerGitHub <noreply@github.com>
Tue, 9 May 2017 19:05:20 +0000 (12:05 -0700)
[Arm64] Enable FEATURE_TAILCALL_OPT

165 files changed:
Documentation/design-docs/eh-writethru.md
Documentation/design-docs/first-class-structs.md
Documentation/project-docs/ci-trigger-phrases.md
Documentation/project-docs/contributing-workflow.md
Documentation/project-docs/dotnet-standards.md
Documentation/project-docs/garbage-collector-guidelines.md
build-test.cmd
build.sh
clr.defines.targets
clrdefinitions.cmake
dependencies.props
netci.groovy
perf.groovy
src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Linux.Microsoft.NETCore.Runtime.CoreCLR.props
src/ToolBox/SOS/NETCore/SOS.NETCore.csproj
src/debug/createdump/threadinfo.cpp
src/dlls/mscordac/mscordac_unixexports.src
src/dlls/mscoree/coreclr/CMakeLists.txt
src/inc/daccess.h
src/jit/codegenarm.cpp
src/jit/codegenarm64.cpp
src/jit/codegenarmarch.cpp
src/jit/codegencommon.cpp
src/jit/codegenlinear.cpp
src/jit/codegenlinear.h
src/jit/codegenxarch.cpp
src/jit/importer.cpp
src/jit/lower.cpp
src/jit/target.h
src/mscorlib/Resources/Strings.resx
src/mscorlib/System.Private.CoreLib.csproj
src/mscorlib/shared/Interop/Unix/System.Globalization.Native/Interop.Collation.cs [moved from src/mscorlib/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs with 97% similarity]
src/mscorlib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs
src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs [moved from src/mscorlib/src/System/Diagnostics/Debug.Unix.cs with 100% similarity]
src/mscorlib/shared/System/Globalization/CalendarData.Unix.cs [moved from src/mscorlib/src/System/Globalization/CalendarData.Unix.cs with 93% similarity]
src/mscorlib/shared/System/Globalization/CultureData.Unix.cs [moved from src/mscorlib/src/System/Globalization/CultureData.Unix.cs with 100% similarity]
src/mscorlib/shared/System/Globalization/HijriCalendar.Unix.cs [moved from src/mscorlib/src/System/Globalization/HijriCalendar.Unix.cs with 100% similarity]
src/mscorlib/shared/System/Globalization/HijriCalendar.Win32.cs [moved from src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs with 100% similarity]
src/mscorlib/shared/System/Globalization/HijriCalendar.WinRT.cs [moved from src/mscorlib/src/System/Globalization/HijriCalendar.WinRT.cs with 100% similarity]
src/mscorlib/shared/System/Globalization/IdnMapping.Unix.cs [moved from src/mscorlib/src/System/Globalization/IdnMapping.Unix.cs with 98% similarity]
src/mscorlib/shared/System/Globalization/JapaneseCalendar.Unix.cs [moved from src/mscorlib/src/System/Globalization/JapaneseCalendar.Unix.cs with 100% similarity]
src/mscorlib/shared/System/Globalization/JapaneseCalendar.Win32.cs [moved from src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs with 100% similarity]
src/mscorlib/shared/System/Globalization/JapaneseCalendar.WinRT.cs [moved from src/mscorlib/src/System/Globalization/JapaneseCalendar.WinRT.cs with 100% similarity]
src/mscorlib/shared/System/Globalization/NumberFormatInfo.cs [moved from src/mscorlib/src/System/Globalization/NumberFormatInfo.cs with 97% similarity]
src/mscorlib/shared/System/Globalization/SortKey.cs [moved from src/mscorlib/src/System/Globalization/SortKey.cs with 92% similarity]
src/mscorlib/shared/System/Globalization/StringInfo.cs [moved from src/mscorlib/src/System/Globalization/StringInfo.cs with 98% similarity]
src/mscorlib/shared/System/IO/EncodingCache.cs [moved from src/mscorlib/src/System/IO/EncodingCache.cs with 100% similarity]
src/mscorlib/shared/System/IO/FileStream.Windows.cs
src/mscorlib/shared/System/IO/Path.cs
src/mscorlib/shared/System/IO/PinnedBufferMemoryStream.cs [moved from src/mscorlib/src/System/IO/PinnedBufferMemoryStream.cs with 75% similarity]
src/mscorlib/shared/System/IO/UnmanagedMemoryStream.cs [moved from src/mscorlib/src/System/IO/UnmanagedMemoryStream.cs with 76% similarity]
src/mscorlib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs [moved from src/mscorlib/src/System/IO/UnmanagedMemoryStreamWrapper.cs with 91% similarity]
src/mscorlib/shared/System/OperationCanceledException.cs [moved from src/mscorlib/src/System/OperationCanceledException.cs with 100% similarity]
src/mscorlib/shared/System/Resources/RuntimeResourceSet.cs
src/mscorlib/src/Microsoft/Win32/Win32Native.cs
src/mscorlib/src/System/Activator.cs
src/mscorlib/src/System/AppDomain.cs
src/mscorlib/src/System/BCLDebug.cs
src/mscorlib/src/System/Collections/ArrayList.cs [deleted file]
src/mscorlib/src/System/Collections/Generic/Dictionary.cs
src/mscorlib/src/System/DelegateSerializationHolder.cs
src/mscorlib/src/System/Diagnostics/Debugger.cs
src/mscorlib/src/System/Diagnostics/log.cs
src/mscorlib/src/System/Empty.cs
src/mscorlib/src/System/Environment.cs
src/mscorlib/src/System/Globalization/CalendarData.Windows.cs
src/mscorlib/src/System/Globalization/CultureData.Windows.cs
src/mscorlib/src/System/Globalization/EncodingDataItem.cs
src/mscorlib/src/System/IO/__Error.cs
src/mscorlib/src/System/MissingFieldException.cs
src/mscorlib/src/System/MissingMemberException.cs
src/mscorlib/src/System/OperatingSystem.cs [deleted file]
src/mscorlib/src/System/PlatformID.cs [deleted file]
src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs
src/mscorlib/src/System/Reflection/CustomAttribute.cs
src/mscorlib/src/System/Reflection/RuntimeAssembly.cs
src/mscorlib/src/System/RtType.cs
src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs
src/mscorlib/src/System/Runtime/InteropServices/ComEventsHelper.cs
src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs
src/mscorlib/src/System/Runtime/Remoting/ObjectHandle.cs [deleted file]
src/mscorlib/src/System/Runtime/Serialization/FormatterServices.cs
src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs
src/mscorlib/src/System/SharedStatics.cs
src/mscorlib/src/System/Text/Encoding.cs
src/mscorlib/src/System/Threading/Monitor.cs
src/mscorlib/src/System/Threading/PinnableBufferCache.cs [moved from src/mscorlib/Common/PinnableBufferCache.cs with 100% similarity]
src/mscorlib/src/System/Threading/WaitHandle.cs
src/mscorlib/src/System/TypeLoadException.cs
src/pal/inc/pal.h
src/pal/src/CMakeLists.txt
src/pal/src/config.h.in
src/pal/src/configure.cmake
src/pal/src/include/pal/context.h
src/pal/src/include/pal/virtual.h
src/pal/src/map/map.cpp
src/pal/src/map/virtual.cpp
src/pal/src/thread/process.cpp
src/scripts/genEventPipe.py [new file with mode: 0644]
src/scripts/genXplatEventing.py
src/scripts/genXplatLttng.py
src/utilcode/util.cpp
src/vm/CMakeLists.txt
src/vm/arm/asmhelpers.S
src/vm/arm/asmhelpers.asm
src/vm/arm/cgencpu.h
src/vm/arm/stubs.cpp
src/vm/arm64/asmhelpers.S
src/vm/arm64/stubs.cpp
src/vm/assemblynative.cpp
src/vm/assemblynative.hpp
src/vm/ceemain.cpp
src/vm/class.h
src/vm/ecalllist.h
src/vm/eepolicy.cpp
src/vm/eventpipe.cpp
src/vm/eventpipe.h
src/vm/eventpipeconfiguration.cpp [new file with mode: 0644]
src/vm/eventpipeconfiguration.h [new file with mode: 0644]
src/vm/eventpipeevent.cpp [new file with mode: 0644]
src/vm/eventpipeevent.h [new file with mode: 0644]
src/vm/eventpipeeventinstance.cpp [new file with mode: 0644]
src/vm/eventpipeeventinstance.h [new file with mode: 0644]
src/vm/eventpipefile.cpp [new file with mode: 0644]
src/vm/eventpipefile.h [new file with mode: 0644]
src/vm/eventpipejsonfile.cpp
src/vm/eventpipejsonfile.h
src/vm/eventpipeprovider.cpp [new file with mode: 0644]
src/vm/eventpipeprovider.h [new file with mode: 0644]
src/vm/eventtrace.cpp
src/vm/fastserializableobject.h [new file with mode: 0644]
src/vm/fastserializer.cpp [new file with mode: 0644]
src/vm/fastserializer.h [new file with mode: 0644]
src/vm/method.cpp
src/vm/method.hpp
src/vm/mscorlib.h
src/vm/precode.cpp
src/vm/precode.h
src/vm/prestub.cpp
src/vm/sampleprofiler.cpp
src/vm/sampleprofiler.h
tests/helixprep.proj
tests/issues.targets
tests/scripts/run-gc-reliability-framework.cmd [new file with mode: 0644]
tests/scripts/run-gc-reliability-framework.sh [new file with mode: 0755]
tests/scripts/run-xunit-perf.cmd
tests/src/Common/PerfHarness/project.json
tests/src/Common/build_against_pkg_dependencies/project.json
tests/src/Common/external/project.json
tests/src/Common/netcoreapp/project.json
tests/src/Common/targeting_pack_ref/project.json
tests/src/Common/test_dependencies/project.json
tests/src/Common/test_runtime/project.json
tests/src/GC/Stress/Framework/ReliabilityFramework.csproj
tests/src/JIT/Regression/JitBlue/GitHub_11343/GitHub_11343.cs [new file with mode: 0644]
tests/src/JIT/Regression/JitBlue/GitHub_11343/GitHub_11343.csproj [new file with mode: 0644]
tests/src/JIT/Regression/JitBlue/GitHub_11408/GitHub_11408.cs [new file with mode: 0644]
tests/src/JIT/Regression/JitBlue/GitHub_11408/GitHub_11408.csproj [new file with mode: 0644]
tests/src/JIT/config/benchmark+roslyn/project.json
tests/src/JIT/config/benchmark+serialize/project.json
tests/src/JIT/config/benchmark/project.json
tests/src/TestWrappersConfig/project.json
tests/src/performance/project.json
tests/testsFailingOutsideWindows.txt

index 0afa5a7..311ca2c 100644 (file)
 # Exception Handling Write Through Optimization.
 
-Write through is an optimization done on local variables that live across exception handling flow like a handler, filter, or finally so that they can be enregistered - treated as a register candidate - throughout a method.  For each variable live across one of these constructs, the minimum requirement is that a store to the variables location on the stack is placed between a reaching definition and any point of control flow leading to the handler, as well as a load between any return from a filter or finally and an upward exposed use.  Conceptually this maintains the value of the variable on the stack across the exceptional flow which would kill any live registers.  This transformation splits a local variable into multiple enregisterable compiler temporaries backed by the local variable on the stack. For local vars that additionally have appearances within a eh construct, a load from the stack local is inserted to a temp that will be enregistered within the handler.
+Write through is an optimization done on local variables that live across
+exception handling flow like a handler, filter, or finally so that they can be
+enregistered - treated as a register candidate - throughout a method.  For each
+variable live across one of these constructs, the minimum requirement is that a
+store to the variables location on the stack is placed between a reaching
+definition and any point of control flow leading to the handler, as well as a
+load between any return from a filter or finally and an upward exposed use.
+Conceptually this maintains the value of the variable on the stack across the
+exceptional flow which would kill any live registers.  This transformation splits
+a local variable into an enregisterable compiler temporary backed by
+the local variable on the stack. For local vars that additionally have
+appearances within an eh construct, a load from the stack local is inserted to
+a temp that will be enregistered within the handler.
 
 ## Motivation
 
-Historically the JIT has not done this transformation because exception handling was rare and thus the transformation was not worth the compile time.  Additionally it was easy to make the recomendation to users to remove EH from performance critical methods since they had control of where the EH appeared.  Neither of these points remain true as we increase our focus on cloud workloads.  The use of non-blocking async calls are common in performance critical paths for these workloads and async injects exception handling constructs to implement the feature.  This in combination with the long standing use of EH in 'foreach' and 'using' statements means that we are seeing EH constructs that are difficult for the user to manage or remove high in the profile (Techempower on Kestrel is a good example).  Given these cloud workloads doing the transformation would be a clear benefit.
+Historically the JIT has not done this transformation because exception
+handling was rare and thus the transformation was not worth the compile time.
+Additionally it was easy to make the recomendation to users to remove EH from
+performance critical methods since they had control of where the EH appeared.
+Neither of these points remain true as we increase our focus on cloud
+workloads.  The use of non-blocking async calls are common in performance
+critical paths for these workloads and async injects exception handling
+constructs to implement the feature.  This in combination with the long
+standing use of EH in 'foreach' and 'using' statements means that we are seeing
+EH constructs that are difficult for the user to manage or remove high in the
+profile (Techempower on Kestrel is a good example).  It's also good to consider
+that in MSIL, basic operations can raise semantically meaningful exceptions
+(unlike say C++, where an explicit throw is required to raise an exception) so
+injected handlers can end up pessimizing a number of local variables in the
+method. Given this combination of issues in cloud workloads doing the
+transformation should be a clear benefit.
 
 ## Design
 
-The goal of the design is to preserve the constraints listed above - i.e. preserve a correct value on the stack for any local var that crosses an EH edge in the flow graph. To ensure that the broad set of global optimizations can act on the IR shape produced by this transformation and that phase ordering issues do not block enregistration opportunities the write through phase will be staged just prior to SSA build after morph and it will do a full walk of the IR rewriting appearances to proxies as well as inserting reloads at the appropriate blocks in the flow graph as indicated by EH control flow semantics. To preserve the needed values on the stack a store will also be inserted after every definition to copy the new value in the proxy back to the stack location.  This will leave non optimal number of stores (too many) but with the strategy that the more expensive analysis to eliminate/better place stores will be staged as a global optimization in a higher compilation tier.
+The goal of the design is to preserve the constraints listed above - i.e.
+preserve a correct value on the stack for any local var that crosses an EH edge
+in the flow graph. To ensure that the broad set of global optimizations can act
+on the IR shape produced by this transformation and that phase ordering issues
+do not block enregistration opportunities the write through phase will be
+staged just prior to SSA build after morph and it will do a full walk of the
+IR rewriting appearances to proxies as well as inserting reloads at the
+appropriate blocks in the flow graph as indicated by EH control flow semantics.
+To preserve the needed values on the stack a store will also be inserted after
+every definition to copy the new value in the proxy back to the stack location.
+This will leave non optimal number of stores (too many) but with the strategy
+that the more expensive analysis to eliminate/better place stores will be
+staged as a global optimization in a higher compilation tier.
+
+There are a number of wrinkles informing this design based on how the JIT models EH:
+- The jit does not explicitly model the exception flow, so a given block and
+  even a given statement within a block may have multiple exception-raising sites.
+- For statements within protected regions, and for all variables live into any
+  reachable handler, the jit assumes all definitions within the region can
+  potentially reach uses in the handlers, since the exact interleaving of
+  definition points and exception points is not known. Hence every definition
+  is a reaching definition, even both values back from to back stores with no
+  read of the variable in between.
+- The jit does not model which handlers are reachable from a given protected region,
+  so considers a variable live into a handler if it is live into any handler in the method.
+
+It is posible to do better than the "store every definition" approch outlined
+in the design, but the expectation is that this would require posibly
+modifying the model in the JIT and staging more throughput intensive analyses.
+With these considerations this design was selected and further improvements
+left to future optimization.
 
 ### Throughput
 
-To identify EH crossing local vars global liveness is necessary.  This comes at the significant cost of the liveness analysis.  To mitigate this the write through phase is staged immediately before SSA build for the global optimizer.  Since the typical case is that there is no EH, the liveness analysis in write through can be reused directly by SSA build.  For the case where EH local vars are present liveness today must be rebuilt for SSA since new local vars have been added, but incremental update to the RyuJIT liveness analysis can be implemented (worklist based live analysis) to improve the throughput.  Additionally the write through transformation does a full IR walk - also expensive - to replace EH local var appearances with proxies and insert transfers to and from the stack for EH flow, given this initial implementations may need to be staged as part of AOT (crossgen) compiles until tiering can move the more expensive analysis out of the startup path.
+To identify EH crossing local vars global liveness is necessary.  This comes at
+the significant cost of the liveness analysis.  To mitigate this the write
+through phase is staged immediately before SSA build for the global optimizer.
+Since the typical case is that there is no EH, the liveness analysis in write
+through can be reused directly by SSA build.  For the case where EH local vars
+are present liveness today must be rebuilt for SSA since new local vars have
+been added, but incremental update to the RyuJIT liveness analysis can be
+implemented (worklist based live analysis) to improve the throughput.
+Additionally the write through transformation does a full IR walk - also
+expensive - to replace EH local var appearances with proxies and insert
+transfers to and from the stack for EH flow, given this initial implementations
+may need to be staged as part of AOT (crossgen) compiles until tiering can move
+the more expensive analysis out of the startup path.
 
 ### Algorithm
+
 On the IR directly before SSA build:
-- Run global liveness to identify local vars that cross EH boundaries (as a byproduct of this these local vars are marked "do not enregister")
+- Run global liveness to identify local vars that cross EH boundaries (as a
+  byproduct of this these local vars are marked "do not enregister")
 - Foreach EH local var create a new local var "proxy" that can be enregisterd.
 - Iterate each block in the flow graph doing the following:
   * Foreach tree in block do a post order traversal and
     - Replace all appearances of EH local vars with the defined proxy
     - Insert a copy of proxy definition back to the EH local var (on the stack)
-  * If EH handler entry block insert reloads from EH local var to proxy at block head
-  * If finally or filter exit, insert reloads from EH local var to proxy at successor block heads
-- For method entry block, insert reloads from parameter EH local vars to proxies
+  * If EH handler entry block insert reloads from EH local var to proxy at
+    block head
+  * If finally or filter exit, insert reloads from EH local var to proxy at
+    successor block heads
+- For method entry block, insert reloads from parameter EH local vars to
+  proxies
 
-At end no proxy should be live across EH flow and all value updates will be written back to the stack location.
+At end no proxy should be live across EH flow and all value updates will be
+written back to the stack location.
 
 ## Next steps
 
-The initial prototype that produced the example bellow is currently being improved to make it production ready.  At the same time a more extensive suite of example tests are being developed. 
+The initial prototype that produced the example bellow is currently being
+improved to make it production ready.  At the same time a more extensive suite
+of example tests are being developed. 
 
 - [X] Proof of concept prototype.
 - [ ] Production implementation of WriteThru phase.
@@ -42,7 +119,8 @@ The initial prototype that produced the example bellow is currently being improv
 
 ## Example
 
-The following is a simple example that shows enregistration for a local var live, and modified, through a catch.
+The following is a simple example that shows enregistration for a local var
+live, and modified, through a catch.
 
 #### Source code snippet
 
index fd6a376..f7bd9b6 100644 (file)
@@ -21,7 +21,7 @@ Struct-Related Issues in RyuJIT
 The following issues illustrate some of the motivation for improving the handling of value types
 (structs) in RyuJIT:
 
-* VSO Bug 98404: .NET JIT x86 - poor code generated for value type initialization
+* [\#11407 [RyuJIT] Fully enregister structs that fit into a single register when profitable](https://github.com/dotnet/coreclr/issues/11407), also VSO Bug 98404: .NET JIT x86 - poor code generated for value type initialization
  * This is a simple test case that should generate simply `xor eax; ret` on x86 and x64, but
    instead generates many unnecessary copies. It is addressed by full enregistration of
    structs that fit into a register:
index dd0e981..f57be03 100644 (file)
@@ -11,7 +11,10 @@ To trigger a job, post a comment on your PR with "@dotnet-bot {trigger-phrase}".
 
 - **Windows_NT x64 Release Priority 1 Build & Test:** "test Windows_NT pri1"
 - **Windows_NT x64 Release IL RoundTrip Build & Test:** "test Windows_NT ilrt"
-- **Windows_NT x64 Release Long-Running GC Build & Test:**: "test Windows_NT x64 Release longgc"
+- **Windows_NT x64 Release Long-Running GC Build & Test:**: "test Windows_NT Release longgc"
+- **Windows_NT x64 Release GC Simulator:**: "test Windows_NT Release gcsimulator"
+- **Windows_NT x64 Release Standalone GC:**: "test Windows_NT Release standalone_gc"
+- **Windows_NT x64 Release GC Reliability Framework:**: "test Windows_NT Release gc_reliability_framework"
 - **Windows_NT x64 Release Ready-To-Run Priority 0 Build & Test:** "test Windows_NT Release r2r"
 - **Windows_NT x64 Checked Ready-To-Run Priority 0 Build & Test:** "test Windows_NT Checked r2r"
 - **Windows_NT x64 Release Ready-To-Run Priority 1 Build & Test:** "test Windows_NT Release pri1r2r"
@@ -69,6 +72,8 @@ To trigger a job, post a comment on your PR with "@dotnet-bot {trigger-phrase}".
 - **Windows_NT x64 Checked GCStress=0xc JitStress=2 Build & Test:** "test Windows_NT gcstress0xc_jitstress2"
 - **Windows_NT x64 Checked GCStress=0xc MinOpts Heap Verify 1 Build & Test:** "test Windows_NT gcstress0xc_minopts_heapverify1"
 - **Windows_NT x64 Checked Long-Running GC Build & Test:**: "test Windows_NT x64 Checked longgc"
+- **Windows_NT x64 Checked Standalone GC:**: "test Windows_NT Checked standalone_gc"
+- **Windows_NT x64 Checked GC Reliability Framework:**: "test Windows_NT Checked gc_reliability_framework"
 - **Windows_NT x64 Formatting:**: "test Windows_NT formatting"
 - **Windows_NT x64 Checked CoreFX Baseline Build & Test:** "test Windows_NT corefx_baseline"
 - **Windows_NT x64 Checked CoreFX MinOpts Build & Test:** "test Windows_NT corefx_minopts"
@@ -166,6 +171,11 @@ To trigger a job, post a comment on your PR with "@dotnet-bot {trigger-phrase}".
 - **Ubuntu x64 Release Priority 1 Build & Test:** "test Ubuntu pri1"
 - **Ubuntu x64 Release IL RoundTrip Build & Test:** "test Ubuntu ilrt"
 - **Ubuntu x64 Release Long-Running GC Build & Test:**: "test Ubuntu Release longgc"
+- **Ubuntu x64 Release GC Simulator:**: "test Ubuntu Release gcsimulator"
+- **Ubuntu x64 Release Standalone GC:**: "test Ubuntu Release standalone_gc"
+- **Ubuntu x64 Checked Standalone GC:**: "test Ubuntu Checked standalone_gc"
+- **Ubuntu x64 Release GC Reliability Framework:**: "test Ubuntu Release gc_reliability_framework"
+- **Ubuntu x64 Checked GC Reliability Framework:**: "test Ubuntu Checked gc_reliability_framework"
 - **Ubuntu x64 Release Ready-To-Run Priority 0 Build & Test:** "test Ubuntu Release r2r"
 - **Ubuntu x64 Checked Ready-To-Run Priority 0 Build & Test:** "test Ubuntu Checked r2r"
 - **Ubuntu x64 Release Ready-To-Run Priority 1 Build & Test:** "test Ubuntu Release pri1r2r"
@@ -248,6 +258,11 @@ To trigger a job, post a comment on your PR with "@dotnet-bot {trigger-phrase}".
 - **OSX x64 Release Priority 1 Build & Test:** "test OSX pri1"
 - **OSX x64 Release IL RoundTrip Build & Test:** "test OSX ilrt"
 - **OSX x64 Release Long-Running GC Build & Test:**: "test OSX Release longgc"
+- **OSX x64 Release GC Simulator:**: "test OSX10.12 Release gcsimulator"
+- **OSX x64 Release Standalone GC:**: "test OSX10.12 Release standalone_gc"
+- **OSX x64 Checked Standalone GC:**: "test OSX10.12 Checked standalone_gc"
+- **OSX x64 Release GC Reliability Framework:**: "test OSX10.12 Release gc_reliability_framework"
+- **OSX x64 Checked GC Reliability Framework:**: "test OSX10.12 Checked gc_reliability_framework"
 - **OSX x64 Release Ready-To-Run Priority 0 Build & Test:** "test OSX Release r2r"
 - **OSX x64 Checked Ready-To-Run Priority 0 Build & Test:** "test OSX Checked r2r"
 - **OSX x64 Release Ready-To-Run Priority 1 Build & Test:** "test OSX Release pri1r2r"
index ff21143..3634802 100644 (file)
@@ -83,24 +83,24 @@ Suggested Workflow
 We use and recommend the following workflow:
 
 1. Create an issue for your work. 
-  - You can skip this step for trivial changes.
-  - Reuse an existing issue on the topic, if there is one.
-  - Use [CODE_OWNERS.TXT](https://github.com/dotnet/coreclr/blob/master/CODE_OWNERS.TXT) to find relevant maintainers and @ mention them to ask for feedback on your issue.
-  - Get agreement from the team and the community that your proposed change is a good one.
-  - If your change adds a new API, follow the [API Review Process](https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/api-review-process.md). 
-  - Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
+    - You can skip this step for trivial changes.
+    - Reuse an existing issue on the topic, if there is one.
+    - Use [CODE_OWNERS.TXT](https://github.com/dotnet/coreclr/blob/master/CODE_OWNERS.TXT) to find relevant maintainers and @ mention them to ask for feedback on your issue.
+    - Get agreement from the team and the community that your proposed change is a good one.
+    - If your change adds a new API, follow the [API Review Process](https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/api-review-process.md). 
+    - Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
 2. Create a personal fork of the repository on GitHub (if you don't already have one).
 3. Create a branch off of master (`git checkout -b mybranch`). 
-  - Name the branch so that it clearly communicates your intentions, such as issue-123 or githubhandle-issue. 
-  - Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
+    - Name the branch so that it clearly communicates your intentions, such as issue-123 or githubhandle-issue. 
+    - Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
 4. Make and commit your changes.
-  - Please follow our [Commit Messages](https://github.com/dotnet/coreclr/blob/master/Documentation/project-docs/contributing-workflow.md#commit-messages) guidance.
+    - Please follow our [Commit Messages](https://github.com/dotnet/coreclr/blob/master/Documentation/project-docs/contributing-workflow.md#commit-messages) guidance.
 5. Add new tests corresponding to your change, if applicable.
 6. Build the repository with your changes.
-  - Make sure that the builds are clean.
-  - Make sure that the tests are all passing, including your new tests.
+    - Make sure that the builds are clean.
+    - Make sure that the tests are all passing, including your new tests.
 7. Create a pull request (PR) against the upstream repository's **master** branch.
-  - Push your changes to your fork on GitHub (if you haven't already).
+    - Push your changes to your fork on GitHub (if you haven't already).
 
 Note: It is OK for your PR to include a large number of commits. Once your change is accepted, you will be asked to squash your commits into one or some appropriately small number of commits before your PR is merged.
 
index 452c703..d726836 100644 (file)
@@ -49,7 +49,7 @@ ECMA 372 - C++/CLI
 
 The C++/CLI language was standardized as [ECMA 372](http://www.ecma-international.org/publications/standards/Ecma-372.htm) in 2005.
 
-EMCA 372 is supported by the .NET Framework, but not .NET Core.
+ECMA 372 is supported by the .NET Framework, but not .NET Core.
 
 **ECMA 372 Resources**
 
index 66d4c69..1981c8a 100644 (file)
@@ -26,12 +26,43 @@ Required Testing: Validation of the behavior of the affected APIs.
 ## Stress Testing ##
 Stress testing must run for at least **48 hours** against a debug build.
 
-Instructions for running stress are located in the repo at tests\src\GC\Stress\stress_run_readme.txt.
+Stress testing for checked and release builds can be done on pull requests with The .NET CI infrastructure.
+A stress run can be requested using the trigger phrase:
+
+```
+@dotnet_bot test <platform> <flavor> gc_reliability_framework
+```
+
+This will run the stress framework for the default amount of time (15 hours) on the given platform and build flavor.
 
 ## Functional Testing ##
 A functional test run executes the same code as a stress run, but only runs for 30 minutes.
 
 Instructions for running stress are located in the repo at tests\src\GC\Stress\stress_run_readme.txt.
 
+It is recommended that you run at least some of the below PR-triggered CI jobs:
+
+```
+@dotnet_bot test Windows_NT Checked longgc
+@dotnet_bot test OSX10.12 Checked longgc
+@dotnet_bot test Ubuntu Checked longgc
+@dotnet_bot test Windows_NT Checked standalone_gc
+@dotnet_bot test OSX10.12 Checked standalone_gc
+@dotnet_bot test Ubuntu Checked standalone_gc
+```
+
+The "Long GC" tests are a series of GC tests whose running time is too long or memory usage is too high to run with
+the rest of the Priority 0 unit tests. The "Standalone GC" build mode builds and runs the GC in a semi-standalone manner
+(see https://github.com/dotnet/coreclr/projects/3).
+
+You may also wish to run the GC Simulator tests. They may take up to 24 hours to complete and are known to sometimes fail on Ubuntu
+due to poor interactions with the Linux OOM killer. However, they have proven to be quite useful in finding bugs in the past:
+
+```
+@dotnet_bot test Windows_NT Release gcsimulator
+@dotnet_bot test Ubuntu Release gcsimulator
+@dotnet_bot test OSX10.12 Release gcsimulator
+```
+
 ## Performance Testing ##
 Coming soon.
index 9142eee..21f54ef 100644 (file)
@@ -512,7 +512,7 @@ if /I "%2" == "mscorlib.ni.dll" exit /b 0
 REM don't precompile anything from CoreCLR
 if /I exist %CORE_ROOT_STAGE%\%2 exit /b 0
 
-"%CORE_ROOT_STAGE%\crossgen.exe" /Platform_Assemblies_Paths "%CORE_ROOT%" "%1" >nul 2>nul
+"%CORE_ROOT_STAGE%\crossgen.exe" /Platform_Assemblies_Paths "%CORE_ROOT%" /in "%1" /out "%CORE_ROOT%/temp.ni.dll" >nul 2>nul
 set /a __exitCode = %errorlevel%
 if "%__exitCode%" == "-2146230517" (
     echo %2 is not a managed assembly.
@@ -523,6 +523,10 @@ if %__exitCode% neq 0 (
     echo Unable to precompile %2
     exit /b 0
 )
+
+:: Delete original .dll & replace it with the Crossgened .dll
+del %1
+ren "%CORE_ROOT%\temp.ni.dll" %2
     
 echo Successfully precompiled %2
 exit /b 0
index 12b7b72..39e96dd 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -154,15 +154,27 @@ generate_event_logging_sources()
 # Event Logging Infrastructure
    __GeneratedIntermediate="$__IntermediatesDir/Generated"
    __GeneratedIntermediateEventProvider="$__GeneratedIntermediate/eventprovider_new"
+   __GeneratedIntermediateEventPipe="$__GeneratedIntermediate/eventpipe_new"
+
     if [[ -d "$__GeneratedIntermediateEventProvider" ]]; then
         rm -rf  "$__GeneratedIntermediateEventProvider"
     fi
 
+    if [[ -d "$__GeneratedIntermediateEventPipe" ]]; then
+        rm -rf  "$__GeneratedIntermediateEventPipe"
+    fi
+
     if [[ ! -d "$__GeneratedIntermediate/eventprovider" ]]; then
         mkdir -p "$__GeneratedIntermediate/eventprovider"
     fi
 
+    if [[ ! -d "$__GeneratedIntermediate/eventpipe" ]]; then
+        mkdir -p "$__GeneratedIntermediate/eventpipe"
+    fi
+
     mkdir -p "$__GeneratedIntermediateEventProvider"
+    mkdir -p "$__GeneratedIntermediateEventPipe"
+    
     if [[ $__SkipCoreCLR == 0 || $__ConfigureOnly == 1 ]]; then
         echo "Laying out dynamically generated files consumed by the build system "
         echo "Laying out dynamically generated Event Logging Test files"
@@ -172,6 +184,18 @@ generate_event_logging_sources()
             exit
         fi
 
+        case $__BuildOS in
+            Linux)
+                echo "Laying out dynamically generated EventPipe Implementation"
+                $PYTHON -B -Wall -Werror "$__ProjectRoot/src/scripts/genEventPipe.py" --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --intermediate "$__GeneratedIntermediateEventPipe" --exc "$__ProjectRoot/src/vm/ClrEtwAllMeta.lst"
+                if  [[ $? != 0 ]]; then
+                    exit
+                fi
+                ;;
+            *)
+                ;;
+        esac
+
         #determine the logging system
         case $__BuildOS in
             Linux)
@@ -193,6 +217,14 @@ generate_event_logging_sources()
     fi
 
     rm -rf "$__GeneratedIntermediateEventProvider"
+
+    echo "Cleaning the temp folder of dynamically generated EventPipe files"
+    $PYTHON -B -Wall -Werror -c "import sys;sys.path.insert(0,\"$__ProjectRoot/src/scripts\"); from Utilities import *;UpdateDirectory(\"$__GeneratedIntermediate/eventpipe\",\"$__GeneratedIntermediateEventPipe\")"
+    if  [[ $? != 0 ]]; then
+        exit
+    fi
+
+    rm -rf "$__GeneratedIntermediateEventPipe"
 }
 
 build_native()
index 2f97c8d..1dd41f1 100644 (file)
@@ -18,7 +18,6 @@
         <DefineConstants Condition="'$(FeatureMacl)' == 'true'">$(DefineConstants);FEATURE_MACL</DefineConstants>
         <DefineConstants Condition="'$(FeatureManagedEtw)' == 'true'">$(DefineConstants);FEATURE_MANAGED_ETW</DefineConstants>
         <DefineConstants Condition="'$(FeatureManagedEtwChannels)' == 'true'">$(DefineConstants);FEATURE_MANAGED_ETW_CHANNELS</DefineConstants>
-        <DefineConstants Condition="'$(FeatureNongenericCollections)' == 'true'">$(DefineConstants);FEATURE_NONGENERIC_COLLECTIONS</DefineConstants>
         <DefineConstants Condition="'$(FeaturePal)' == 'true'">$(DefineConstants);FEATURE_PAL</DefineConstants>
         <DefineConstants Condition="'$(FeaturePathCompat)' == 'true'">$(DefineConstants);FEATURE_PATHCOMPAT</DefineConstants>
         <DefineConstants Condition="'$(FeatureXplatEventSource)' == 'true'">$(DefineConstants);FEATURE_EVENTSOURCE_XPLAT</DefineConstants>
index c2493f0..4dacae9 100644 (file)
@@ -111,7 +111,9 @@ endif(FEATURE_DBGIPC)
 if(FEATURE_EVENT_TRACE)
     add_definitions(-DFEATURE_EVENT_TRACE=1)
 endif(FEATURE_EVENT_TRACE)
-add_definitions(-DFEATURE_PERFTRACING)
+if(CLR_CMAKE_PLATFORM_LINUX)
+    add_definitions(-DFEATURE_PERFTRACING)
+endif(CLR_CMAKE_PLATFORM_LINUX)
 if(CLR_CMAKE_PLATFORM_UNIX)
     add_definitions(-DFEATURE_EVENTSOURCE_XPLAT=1)
 endif(CLR_CMAKE_PLATFORM_UNIX)
@@ -177,10 +179,10 @@ if(CLR_CMAKE_PLATFORM_UNIX_AMD64)
   add_definitions(-DFEATURE_UNIX_AMD64_STRUCT_PASSING)
 endif (CLR_CMAKE_PLATFORM_UNIX_AMD64)
 add_definitions(-DFEATURE_USE_ASM_GC_WRITE_BARRIERS)
-if(CLR_CMAKE_PLATFORM_ARCH_AMD64 AND NOT WIN32)
+if((CLR_CMAKE_PLATFORM_ARCH_AMD64 OR CLR_CMAKE_PLATFORM_ARCH_ARM64) AND NOT WIN32)
   add_definitions(-DFEATURE_MANUALLY_MANAGED_CARD_BUNDLES)
   add_definitions(-DFEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP)
-endif(CLR_CMAKE_PLATFORM_ARCH_AMD64 AND NOT WIN32)
+endif((CLR_CMAKE_PLATFORM_ARCH_AMD64 OR CLR_CMAKE_PLATFORM_ARCH_ARM64) AND NOT WIN32)
 if(WIN32)
     add_definitions(-DFEATURE_VERSIONING_LOG)
 endif(WIN32)
index 1279c3c..d68d664 100644 (file)
@@ -1,18 +1,18 @@
 <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <!-- Source of truth for dependency tooling: the commit hash of the dotnet/versions master branch as of the last auto-upgrade. -->
   <PropertyGroup>
-    <CoreFxCurrentRef>4a2c8b78ad4065f39c0894ccba79902822989b2c</CoreFxCurrentRef>
-    <CoreClrCurrentRef>4a2c8b78ad4065f39c0894ccba79902822989b2c</CoreClrCurrentRef>
+    <CoreFxCurrentRef>b78ca796620b226c33af1583ca49e889c83c722c</CoreFxCurrentRef>
+    <CoreClrCurrentRef>b78ca796620b226c33af1583ca49e889c83c722c</CoreClrCurrentRef>
   </PropertyGroup>
 
   <!-- Auto-upgraded properties for each build info dependency. -->
   <PropertyGroup>
-    <CoreFxExpectedPrerelease>preview2-25303-04</CoreFxExpectedPrerelease>
+    <CoreFxExpectedPrerelease>preview2-25309-01</CoreFxExpectedPrerelease>
   </PropertyGroup>
 
   <!-- Full package version strings that are used in other parts of the build. -->
   <PropertyGroup>
-    <CoreClrPackageVersion>2.0.0-preview2-25303-03</CoreClrPackageVersion>
+    <CoreClrPackageVersion>2.0.0-preview2-25309-01</CoreClrPackageVersion>
     <XunitPackageVersion>2.2.0-beta2-build3300</XunitPackageVersion>
   </PropertyGroup>
 
index 94d7ad5..6a97cba 100755 (executable)
@@ -137,6 +137,7 @@ class Constants {
                'gcsimulator',
                'jitdiff',              
                'standalone_gc',
+               'gc_reliability_framework',
                'illink'] + r2rJitStressScenarios
 
     def static configurationList = ['Debug', 'Checked', 'Release']
@@ -205,6 +206,14 @@ def static isJitDiff(def scenario) {
     return (scenario == 'jitdiff')
 }
 
+def static isGcReliabilityFramework(def scenario) {
+    return (scenario == 'gc_reliability_framework')
+}
+
+def static scenarioNeedsPri1Build(def scenario) {
+    return (scenario == 'pri1' || scenario == 'pri1r2r' || scenario == 'gcstress15_pri1r2r'|| scenario == 'coverage' || isGcReliabilityFramework(scenario))
+}
+
 def static setTestJobTimeOut(newJob, scenario) {
     if (isGCStressRelatedTesting(scenario)) {
         Utilities.setJobTimeout(newJob, 4320)
@@ -227,6 +236,9 @@ def static setTestJobTimeOut(newJob, scenario) {
     else if (isJitDiff(scenario)) {
         Utilities.setJobTimeout(newJob, 240)
     }
+    else if (isGcReliabilityFramework(scenario)) {
+        Utilities.setJobTimeout(newJob, 1440)
+    }
     // Non-test jobs use the default timeout value.
 }
 
@@ -497,6 +509,11 @@ def static addNonPRTriggers(def job, def branch, def isPR, def architecture, def
             // addEmailPublisher(job, 'dotnetgctests@microsoft.com')
             Utilities.addPeriodicTrigger(job, '@weekly')
             break
+        case 'gc_reliability_framework':
+            assert (os == 'Ubuntu' || os == 'Windows_NT' || os == 'OSX10.12')
+            assert (configuration == 'Release' || configuration == 'Checked')
+            // Only triggered by phrase.
+            break
         case 'ilrt':
             assert !(os in bidailyCrossList)
             // ILASM/ILDASM roundtrip one gets a daily build, and only for release
@@ -766,6 +783,16 @@ def static addTriggers(def job, def branch, def isPR, def architecture, def os,
                                 Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} GC Simulator", "(?i).*test\\W+${os}\\W+${configuration}\\W+${scenario}.*")
                             }
                             break
+                        case 'standalone_gc':
+                            if (configuration == 'Release' || configuration == 'Checked') {
+                                Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} Standalone GC", "(?i).*test\\W+${os}\\W+${configuration}\\W+${scenario}.*")
+                            }
+                            break
+                        case 'gc_reliability_framework':
+                            if (configuration == 'Release' || configuration == 'Checked') {
+                                Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} GC Reliability Framework", "(?i).*test\\W+${os}\\W+${configuration}\\W+${scenario}.*")
+                            }
+                            break
                         case 'minopts':
                         case 'forcerelocs':
                         case 'jitstress1':
@@ -939,6 +966,11 @@ def static addTriggers(def job, def branch, def isPR, def architecture, def os,
                                 Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} Standalone GC", "(?i).*test\\W+${os}\\W+${configuration}\\W+${scenario}.*")
                             }
                             break
+                        case 'gc_reliability_framework':
+                            if (configuration == 'Release' || configuration == 'Checked') {
+                                Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} GC Reliability Framework", "(?i).*test\\W+${os}\\W+${configuration}\\W+${scenario}.*")
+                            }
+                            break
                         case 'minopts':
                         case 'forcerelocs':
                         case 'jitstress1':
@@ -1307,7 +1339,7 @@ def static calculateBuildCommands(def newJob, def scenario, def branch, def isPR
                     // binaries are sent to a default directory whose name is about
                     // 35 characters long.
 
-                    else if (scenario == 'pri1' || scenario == 'pri1r2r' || scenario == 'gcstress15_pri1r2r'|| scenario == 'coverage') {
+                    else if (scenarioNeedsPri1Build(scenario)) {
                         buildCommands += "set __TestIntermediateDir=int&&build.cmd ${lowerConfiguration} ${arch} ${buildOpts} -priority=1"
                     }
                     else if (isLongGc(scenario)) {
@@ -1435,6 +1467,12 @@ def static calculateBuildCommands(def newJob, def scenario, def branch, def isPR
                                 buildCommands += "%WORKSPACE%\\tests\\runtest.cmd ${runtestArguments} TestEnv ${stepScriptLocation}"
                             }
                         }
+                        else if (isGcReliabilityFramework(scenario)) {
+                            buildCommands += "tests\\runtest.cmd ${runtestArguments} GenerateLayoutOnly"
+                            buildCommands += "tests\\scripts\\run-gc-reliability-framework.cmd ${arch} ${configuration}"
+                            Utilities.addArchival(newJob, "stdout.txt")
+                            Utilities.addArchival(newJob, "Logs/**")
+                        }
                         else if (architecture == 'x64' || architecture == 'x86') {
                             buildCommands += "tests\\runtest.cmd ${runtestArguments}"
                         }
@@ -1507,7 +1545,7 @@ def static calculateBuildCommands(def newJob, def scenario, def branch, def isPR
                            Utilities.setJobTimeout(newJob, 240)
                        }
 
-                       buildCommands += "set __TestIntermediateDir=int&&build.cmd skiptests ${lowerConfiguration} ${architecture} toolset_dir C:\\ats2"
+                       buildCommands += "set __TestIntermediateDir=int&&build.cmd ${lowerConfiguration} ${architecture} toolset_dir C:\\ats2 -priority=1"
                        // Test build and run are launched together.
                        buildCommands += "python tests\\scripts\\arm64_post_build.py -repo_root %WORKSPACE% -arch ${architecture} -build_type ${lowerConfiguration} -scenario ${scenario} -key_location C:\\tools\\key.txt"
                        //Utilities.addXUnitDotNETResults(newJob, 'bin/tests/testResults.xml')
@@ -1870,6 +1908,7 @@ combinedScenarios.each { scenario ->
                                     return
                                 }
                                 break
+                            case 'gc_reliability_framework':
                             case 'standalone_gc':
                                 if (os != 'Windows_NT' && os != 'Ubuntu' && os != 'OSX10.12') {
                                     return
@@ -2120,10 +2159,12 @@ combinedScenarios.each { scenario ->
                                     return
                                 }
                                 break
+                            case 'gc_reliability_framework':
                             case 'standalone_gc':
                                 if (configuration != 'Release' && configuration != 'Checked') {
                                     return
                                 }
+                                break
                             case 'coverage':
                                 //We only want Ubuntu Release for coverage
                                 if (os != 'Ubuntu') {
@@ -2164,7 +2205,7 @@ combinedScenarios.each { scenario ->
                     // so we didn't create a build only job for windows_nt specific to that stress mode.  Just copy
                     // from the default scenario
                     def testBuildScenario = scenario
-                    if (testBuildScenario == 'coverage' || testBuildScenario == 'pri1r2r'|| testBuildScenario == 'gcstress15_pri1r2r') {
+                    if (scenarioNeedsPri1Build(scenario)) {
                         testBuildScenario = 'pri1'
                     }
                     else if ( testBuildScenario == 'r2r' || Constants.r2rJitStressScenarios.indexOf(testBuildScenario) != -1 || isLongGc(testBuildScenario)) {
@@ -2210,6 +2251,7 @@ combinedScenarios.each { scenario ->
                     def runilasmroundtripStr = ''
                     def gcstressStr = ''
                     def illinkStr = ''
+                    def layoutOnlyStr =''
 
                     if (scenario == 'r2r' ||
                         scenario == 'pri1r2r' ||
@@ -2286,6 +2328,10 @@ combinedScenarios.each { scenario ->
                         }
                     }
 
+                    if (isGcReliabilityFramework(scenario)) {
+                        layoutOnlyStr = '--build-overlay-only'
+                    }
+
                     def folder = getJobFolder(scenario)
                     def newJob = job(Utilities.getFullJobName(project, jobName, isPR, folder)) {
                         // Add parameters for the inputs
@@ -2438,11 +2484,29 @@ combinedScenarios.each { scenario ->
                 --mscorlibDir=\"\${WORKSPACE}/bin/Product/${osGroup}.${architecture}.${configuration}\" \\
                 --coreFxBinDir=\"\${WORKSPACE}/bin/CoreFxBinDir\" \\
                 --limitedDumpGeneration \\
-                ${testEnvOpt} ${serverGCString} ${gcstressStr} ${crossgenStr} ${runcrossgentestsStr} ${runjitstressStr} ${runjitstressregsStr} ${runjitmioptsStr} ${runjitforcerelocsStr} ${runjitdisasmStr} ${runilasmroundtripStr} ${illinkStr} ${sequentialString} ${playlistString}""")
+                ${testEnvOpt} ${serverGCString} ${gcstressStr} ${crossgenStr} ${runcrossgentestsStr} ${runjitstressStr} \\
+                ${runjitstressregsStr} ${runjitmioptsStr} ${runjitforcerelocsStr} ${runjitdisasmStr} ${runilasmroundtripStr} \\
+                ${illinkStr} ${sequentialString} ${playlistString} ${layoutOnlyStr}""")
+
+                                if (isGcReliabilityFramework(scenario)) {
+                                    // runtest.sh doesn't actually execute the reliability framework - do it here.
+                                    if (serverGCString != '') {
+                                        shell("export COMPlus_gcServer=1")
+                                    }
+
+                                    shell("./tests/scripts/run-gc-reliability-framework.sh ${architecture} ${configuration}")
+                                }
                             }
                         }
                     }
 
+                    if (isGcReliabilityFramework(scenario))
+                    {
+                        // Both of these are emitted by the RF
+                        Utilities.addArchival(newJob, "stdout.txt")
+                        Utilities.addArchival(newJob, "Logs/**")
+                    }
+
                     if (scenario == 'coverage') {
                         // Publish coverage reports
                         Utilities.addHtmlPublisher(newJob, '${WORKSPACE}/coverage/Coverage/reports', 'Code Coverage Report', 'coreclr.html')
index 2d09c31..27aef34 100644 (file)
@@ -62,8 +62,16 @@ def static getOSGroup(def os) {
                 {
                     parameters
                     {
-                        stringParam('XUNIT_PERFORMANCE_MAX_ITERATION', '2', 'Sets the number of iterations to one.  We want to do this so that we can run as fast as possible as this is just for smoke testing')
-                        stringParam('XUNIT_PERFORMANCE_MAX_ITERATION_INNER_SPECIFIED', '2', 'Sets the number of iterations to one.  We want to do this so that we can run as fast as possible as this is just for smoke testing')
+                        stringParam('XUNIT_PERFORMANCE_MAX_ITERATION', '2', 'Sets the number of iterations to two.  We want to do this so that we can run as fast as possible as this is just for smoke testing')
+                        stringParam('XUNIT_PERFORMANCE_MAX_ITERATION_INNER_SPECIFIED', '2', 'Sets the number of iterations to two.  We want to do this so that we can run as fast as possible as this is just for smoke testing')
+                    }
+                }
+                else
+                {
+                    parameters
+                    {
+                        stringParam('XUNIT_PERFORMANCE_MAX_ITERATION', '21', 'Sets the number of iterations to twenty one.  We are doing this to limit the amount of data that we upload as 20 iterations is enought to get a good sample')
+                        stringParam('XUNIT_PERFORMANCE_MAX_ITERATION_INNER_SPECIFIED', '21', 'Sets the number of iterations to twenty one.  We are doing this to limit the amount of data that we upload as 20 iterations is enought to get a good sample')
                     }
                 }
                 def configuration = 'Release'
@@ -96,8 +104,13 @@ def static getOSGroup(def os) {
 
                         batchFile("tests\\runtest.cmd ${configuration} ${architecture} GenerateLayoutOnly")
 
+                        // Run with just stopwatch
                         batchFile("tests\\scripts\\run-xunit-perf.cmd -arch ${arch} -configuration ${configuration} -testBinLoc bin\\tests\\${os}.${architecture}.${configuration}\\performance\\perflab\\Perflab -library -generateBenchviewData \"%WORKSPACE%\\Microsoft.Benchview.JSONFormat\\tools\" ${uploadString} -runtype ${runType}")
                         batchFile("tests\\scripts\\run-xunit-perf.cmd -arch ${arch} -configuration ${configuration} -testBinLoc bin\\tests\\${os}.${architecture}.${configuration}\\Jit\\Performance\\CodeQuality -generateBenchviewData \"%WORKSPACE%\\Microsoft.Benchview.JSONFormat\\tools\" ${uploadString} -runtype ${runType}")
+                        
+                        // Run with the full set of counters enabled
+                        batchFile("tests\\scripts\\run-xunit-perf.cmd -arch ${arch} -configuration ${configuration} -testBinLoc bin\\tests\\${os}.${architecture}.${configuration}\\performance\\perflab\\Perflab -library -generateBenchviewData \"%WORKSPACE%\\Microsoft.Benchview.JSONFormat\\tools\" ${uploadString} -runtype ${runType} -collectionFlags default+BranchMispredictions+CacheMisses+InstructionRetired+gcapi")
+                        batchFile("tests\\scripts\\run-xunit-perf.cmd -arch ${arch} -configuration ${configuration} -testBinLoc bin\\tests\\${os}.${architecture}.${configuration}\\Jit\\Performance\\CodeQuality -generateBenchviewData \"%WORKSPACE%\\Microsoft.Benchview.JSONFormat\\tools\" ${uploadString} -runtype ${runType} -collectionFlags default+BranchMispredictions+CacheMisses+InstructionRetired+gcapi")
                     }
                 }
                 
index e910d63..5f244a9 100644 (file)
@@ -1,9 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
-    <_PlatformDoesNotSupportNiFiles Condition="'$(Platform)' == 'arm'">true</_PlatformDoesNotSupportNiFiles>
-    <_PlatformDoesNotSupportNiFiles Condition="'$(Platform)' == 'armel'">true</_PlatformDoesNotSupportNiFiles>
-    <_PlatformDoesNotSupportNiFiles Condition="'$(Platform)' == 'x86'">true</_PlatformDoesNotSupportNiFiles>
+    <_PlatformDoesNotSupportCreatedump Condition="'$(Platform)' == 'arm'">true</_PlatformDoesNotSupportCreatedump>
+    <_PlatformDoesNotSupportCreatedump Condition="'$(Platform)' == 'armel'">true</_PlatformDoesNotSupportCreatedump>
+    <_PlatformDoesNotSupportCreatedump Condition="'$(Platform)' == 'x86'">true</_PlatformDoesNotSupportCreatedump>
+    <_PlatformDoesNotSupportCreatedump Condition="'$(_runtimeOSFamily)' == 'tizen'">true</_PlatformDoesNotSupportCreatedump>
     <_PlatformDoesNotSupportEventTrace Condition="'$(_runtimeOSFamily)' == 'tizen'">true</_PlatformDoesNotSupportEventTrace>
     <_PlatformDoesNotSupportEventTrace Condition="'$(Platform)' == 'x86'">true</_PlatformDoesNotSupportEventTrace>
   </PropertyGroup>
@@ -18,6 +19,7 @@
     <NativeBinary Include="$(BinDir)System.Globalization.Native.so" />
     <NativeBinary Include="$(BinDir)sosdocsunix.txt" />
     <NativeBinary Include="$(BinDir)System.Private.CoreLib.dll" />
+    <NativeBinary Condition="'$(_PlatformDoesNotSupportCreatedump)' != 'true'" Include="$(BinDir)createdump" />
     <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" />
     <ArchitectureSpecificToolFile Include="$(BinDir)crossgen" />
   </ItemGroup>
index 440cff5..44019bc 100644 (file)
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <NoStdLib>true</NoStdLib>
     <NoCompilerStandardLib>true</NoCompilerStandardLib>
+    <IsDotNetFrameworkProductAssembly>true</IsDotNetFrameworkProductAssembly>
     <UseOpenKey Condition="'$(UseOpenKey)'==''">true</UseOpenKey>
 
     <!-- We don't use any of MSBuild's resolution logic for resolving the framework, so just set these two properties to any folder that exists to skip
          the GenerateReferenceAssemblyPaths task (not target) and to prevent it from outputting a warning (MSB3644). -->
     <_TargetFrameworkDirectories>$(MSBuildThisFileDirectory)/Documentation</_TargetFrameworkDirectories>
     <_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)/Documentation</_FullFrameworkReferenceAssemblyPaths>
-    
   </PropertyGroup>
 
   <!-- Default configurations to help VS understand the options -->
index 8e73fcf..e2c10fc 100644 (file)
@@ -38,7 +38,7 @@ ThreadInfo::Initialize(ICLRDataTarget* dataTarget)
             return false;
         }
     }
-    TRACE("Thread %04x RIP %016llx RSP %016llx\n", m_tid, m_gpRegisters.rip, m_gpRegisters.rsp);
+    TRACE("Thread %04x RIP %016llx RSP %016llx\n", m_tid, (unsigned long long)m_gpRegisters.rip, (unsigned long long)m_gpRegisters.rsp);
     return true;
 }
 
index b0c3b04..9881def 100644 (file)
@@ -39,6 +39,7 @@ PAL_fprintf
 PAL__wcstoui64
 PAL_wcstoul
 PAL_iswprint
+PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange
 PAL_wcslen
 PAL_wcsncmp
 PAL_wcsrchr
index afa253f..7a4617f 100644 (file)
@@ -141,6 +141,12 @@ if(CLR_CMAKE_PLATFORM_UNIX AND FEATURE_EVENT_TRACE)
   )
 endif(CLR_CMAKE_PLATFORM_UNIX AND FEATURE_EVENT_TRACE)
 
+if(CLR_CMAKE_PLATFORM_LINUX)
+    list(APPEND CORECLR_LIBRARIES
+        eventpipe
+  )
+endif(CLR_CMAKE_PLATFORM_LINUX)
+
 target_link_libraries(coreclr ${CORECLR_LIBRARIES}) 
 
 if(WIN32)
index 7d82e86..40aba86 100644 (file)
@@ -617,6 +617,11 @@ typedef struct _DacGlobals
     ULONG fn__ThreadpoolMgr__AsyncTimerCallbackCompletion;
     ULONG fn__DACNotifyCompilationFinished;
     ULONG fn__ThePreStub;
+
+#ifdef _TARGET_ARM_
+    ULONG fn__ThePreStubCompactARM;
+#endif // _TARGET_ARM_
+
     ULONG fn__ThePreStubPatchLabel;
     ULONG fn__PrecodeFixupThunk;
     ULONG fn__StubDispatchFixupStub;
@@ -2345,6 +2350,7 @@ typedef ArrayDPTR(signed char) PTR_SBYTE;
 typedef ArrayDPTR(const BYTE) PTR_CBYTE;
 typedef DPTR(INT8)    PTR_INT8;
 typedef DPTR(INT16)   PTR_INT16;
+typedef DPTR(UINT16)  PTR_UINT16;
 typedef DPTR(WORD)    PTR_WORD;
 typedef DPTR(USHORT)  PTR_USHORT;
 typedef DPTR(DWORD)   PTR_DWORD;
index 0795299..320c6d6 100644 (file)
@@ -259,6 +259,11 @@ void CodeGen::genReturn(GenTreePtr treeNode)
     GenTreePtr op1        = treeNode->gtGetOp1();
     var_types  targetType = treeNode->TypeGet();
 
+    // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
+    // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
+    // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
+    assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
+
 #ifdef DEBUG
     if (targetType == TYP_VOID)
     {
@@ -315,398 +320,6 @@ void CodeGen::genReturn(GenTreePtr treeNode)
 }
 
 //------------------------------------------------------------------------
-// genCodeForTreeNode Generate code for a single node in the tree.
-//
-// Preconditions:
-//    All operands have been evaluated.
-//
-void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
-{
-    regNumber targetReg  = treeNode->gtRegNum;
-    var_types targetType = treeNode->TypeGet();
-    emitter*  emit       = getEmitter();
-
-#ifdef DEBUG
-    lastConsumedNode = nullptr;
-    if (compiler->verbose)
-    {
-        unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
-        compiler->gtDispLIRNode(treeNode, "Generating: ");
-    }
-#endif
-
-    // contained nodes are part of their parents for codegen purposes
-    // ex : immediates, most LEAs
-    if (treeNode->isContained())
-    {
-        return;
-    }
-
-    switch (treeNode->gtOper)
-    {
-        case GT_LCLHEAP:
-            genLclHeap(treeNode);
-            break;
-
-        case GT_CNS_INT:
-        case GT_CNS_DBL:
-            genSetRegToConst(targetReg, targetType, treeNode);
-            genProduceReg(treeNode);
-            break;
-
-        case GT_NOT:
-        case GT_NEG:
-            genCodeForNegNot(treeNode);
-            break;
-
-        case GT_OR:
-        case GT_XOR:
-        case GT_AND:
-            assert(varTypeIsIntegralOrI(treeNode));
-            __fallthrough;
-
-        case GT_ADD_LO:
-        case GT_ADD_HI:
-        case GT_SUB_LO:
-        case GT_SUB_HI:
-        case GT_ADD:
-        case GT_SUB:
-        case GT_MUL:
-            genConsumeOperands(treeNode->AsOp());
-            genCodeForBinary(treeNode);
-            break;
-
-        case GT_LSH:
-        case GT_RSH:
-        case GT_RSZ:
-        case GT_ROR:
-            genCodeForShift(treeNode);
-            break;
-
-        case GT_LSH_HI:
-        case GT_RSH_LO:
-            genCodeForShiftLong(treeNode);
-            break;
-
-        case GT_CAST:
-            // Cast is never contained (?)
-            noway_assert(targetReg != REG_NA);
-
-            if (varTypeIsFloating(targetType) && varTypeIsFloating(treeNode->gtOp.gtOp1))
-            {
-                // Casts float/double <--> double/float
-                genFloatToFloatCast(treeNode);
-            }
-            else if (varTypeIsFloating(treeNode->gtOp.gtOp1))
-            {
-                // Casts float/double --> int32/int64
-                genFloatToIntCast(treeNode);
-            }
-            else if (varTypeIsFloating(targetType))
-            {
-                // Casts int32/uint32/int64/uint64 --> float/double
-                genIntToFloatCast(treeNode);
-            }
-            else
-            {
-                // Casts int <--> int
-                genIntToIntCast(treeNode);
-            }
-            // The per-case functions call genProduceReg()
-            break;
-
-        case GT_LCL_FLD_ADDR:
-        case GT_LCL_VAR_ADDR:
-        {
-            // Address of a local var.  This by itself should never be allocated a register.
-            // If it is worth storing the address in a register then it should be cse'ed into
-            // a temp and that would be allocated a register.
-            noway_assert(targetType == TYP_BYREF);
-            noway_assert(!treeNode->InReg());
-
-            inst_RV_TT(INS_lea, targetReg, treeNode, 0, EA_BYREF);
-        }
-            genProduceReg(treeNode);
-            break;
-
-        case GT_LCL_FLD:
-            genCodeForLclFld(treeNode->AsLclFld());
-            break;
-
-        case GT_LCL_VAR:
-            genCodeForLclVar(treeNode->AsLclVar());
-            break;
-
-        case GT_STORE_LCL_FLD:
-            genCodeForStoreLclFld(treeNode->AsLclFld());
-            break;
-
-        case GT_STORE_LCL_VAR:
-            genCodeForStoreLclVar(treeNode->AsLclVar());
-            break;
-
-        case GT_RETFILT:
-            // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in
-            // the return register, if it's not already there. The processing is the same as GT_RETURN.
-            if (targetType != TYP_VOID)
-            {
-                // For filters, the IL spec says the result is type int32. Further, the only specified legal values
-                // are 0 or 1, with the use of other values "undefined".
-                assert(targetType == TYP_INT);
-            }
-
-            __fallthrough;
-
-        case GT_RETURN:
-            genReturn(treeNode);
-            break;
-
-        case GT_LEA:
-            // if we are here, it is the case where there is an LEA that cannot
-            // be folded into a parent instruction
-            genLeaInstruction(treeNode->AsAddrMode());
-            break;
-
-        case GT_IND:
-            genConsumeAddress(treeNode->AsIndir()->Addr());
-            emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(treeNode), targetReg, treeNode->AsIndir());
-            genProduceReg(treeNode);
-            break;
-
-        case GT_MOD:
-        case GT_UDIV:
-        case GT_UMOD:
-            // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
-            // helper call by front-end.  Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
-            // on float/double args.
-            noway_assert(!varTypeIsFloating(treeNode));
-            __fallthrough;
-
-        case GT_DIV:
-        {
-            genConsumeOperands(treeNode->AsOp());
-
-            noway_assert(targetReg != REG_NA);
-
-            GenTreePtr  dst    = treeNode;
-            GenTreePtr  src1   = treeNode->gtGetOp1();
-            GenTreePtr  src2   = treeNode->gtGetOp2();
-            instruction ins    = genGetInsForOper(treeNode->OperGet(), targetType);
-            emitAttr    attr   = emitTypeSize(treeNode);
-            regNumber   result = REG_NA;
-
-            // dst can only be a reg
-            assert(!dst->isContained());
-
-            // src can be only reg
-            assert(!src1->isContained() || !src2->isContained());
-
-            if (varTypeIsFloating(targetType))
-            {
-                // Floating point divide never raises an exception
-
-                emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
-            }
-            else // an signed integer divide operation
-            {
-                // TODO-ARM-Bug: handle zero division exception.
-
-                emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
-            }
-
-            genProduceReg(treeNode);
-        }
-        break;
-
-        case GT_INTRINSIC:
-            genIntrinsic(treeNode);
-            break;
-
-        case GT_EQ:
-        case GT_NE:
-        case GT_LT:
-        case GT_LE:
-        case GT_GE:
-        case GT_GT:
-            genCodeForCompare(treeNode->AsOp());
-            break;
-
-        case GT_JTRUE:
-            genCodeForJumpTrue(treeNode);
-            break;
-
-        case GT_JCC:
-        {
-            GenTreeJumpCC* jcc = treeNode->AsJumpCC();
-
-            assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
-
-            CompareKind  compareKind = ((jcc->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
-            emitJumpKind jumpKind    = genJumpKindForOper(jcc->gtCondition, compareKind);
-
-            inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
-        }
-        break;
-
-        case GT_RETURNTRAP:
-            genCodeForReturnTrap(treeNode->AsOp());
-            break;
-
-        case GT_STOREIND:
-            genCodeForStoreInd(treeNode->AsStoreInd());
-            break;
-
-        case GT_COPY:
-            // This is handled at the time we call genConsumeReg() on the GT_COPY
-            break;
-
-        case GT_LIST:
-        case GT_FIELD_LIST:
-        case GT_ARGPLACE:
-            // Nothing to do
-            break;
-
-        case GT_PUTARG_STK:
-            genPutArgStk(treeNode->AsPutArgStk());
-            break;
-
-        case GT_PUTARG_REG:
-            genPutArgReg(treeNode->AsOp());
-            break;
-
-        case GT_CALL:
-            genCallInstruction(treeNode->AsCall());
-            break;
-
-        case GT_LOCKADD:
-        case GT_XCHG:
-        case GT_XADD:
-            genLockedInstructions(treeNode->AsOp());
-            break;
-
-        case GT_MEMORYBARRIER:
-            instGen_MemoryBarrier();
-            break;
-
-        case GT_CMPXCHG:
-            NYI("GT_CMPXCHG");
-            genProduceReg(treeNode);
-            break;
-
-        case GT_RELOAD:
-            // do nothing - reload is just a marker.
-            // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
-            // into the register specified in this node.
-            break;
-
-        case GT_NOP:
-            break;
-
-        case GT_NO_OP:
-            if (treeNode->gtFlags & GTF_NO_OP_NO)
-            {
-                noway_assert(!"GTF_NO_OP_NO should not be set");
-            }
-            else
-            {
-                instGen(INS_nop);
-            }
-            break;
-
-        case GT_ARR_BOUNDS_CHECK:
-            genRangeCheck(treeNode);
-            break;
-
-        case GT_PHYSREG:
-            if (treeNode->gtRegNum != treeNode->AsPhysReg()->gtSrcReg)
-            {
-                inst_RV_RV(INS_mov, treeNode->gtRegNum, treeNode->AsPhysReg()->gtSrcReg, targetType);
-
-                genTransferRegGCState(treeNode->gtRegNum, treeNode->AsPhysReg()->gtSrcReg);
-            }
-            break;
-
-        case GT_PHYSREGDST:
-            break;
-
-        case GT_NULLCHECK:
-        {
-            assert(!treeNode->gtOp.gtOp1->isContained());
-            regNumber addrReg = genConsumeReg(treeNode->gtOp.gtOp1);
-            emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
-        }
-        break;
-
-        case GT_CATCH_ARG:
-
-            noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
-
-            /* Catch arguments get passed in a register. genCodeForBBlist()
-               would have marked it as holding a GC object, but not used. */
-
-            noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
-            genConsumeReg(treeNode);
-            break;
-
-        case GT_PINVOKE_PROLOG:
-            noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
-
-            // the runtime side requires the codegen here to be consistent
-            emit->emitDisableRandomNops();
-            break;
-
-        case GT_LABEL:
-            genPendingCallLabel       = genCreateTempLabel();
-            treeNode->gtLabel.gtLabBB = genPendingCallLabel;
-            emit->emitIns_J_R(INS_adr, EA_PTRSIZE, genPendingCallLabel, treeNode->gtRegNum);
-            break;
-
-        case GT_CLS_VAR_ADDR:
-            emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
-            genProduceReg(treeNode);
-            break;
-
-        case GT_STORE_DYN_BLK:
-        case GT_STORE_BLK:
-            genCodeForStoreBlk(treeNode->AsBlk());
-            break;
-
-        case GT_JMPTABLE:
-            genJumpTable(treeNode);
-            break;
-
-        case GT_SWITCH_TABLE:
-            genTableBasedSwitch(treeNode);
-            break;
-
-        case GT_ARR_INDEX:
-            genCodeForArrIndex(treeNode->AsArrIndex());
-            break;
-
-        case GT_ARR_OFFSET:
-            genCodeForArrOffset(treeNode->AsArrOffs());
-            break;
-
-        case GT_IL_OFFSET:
-            // Do nothing; these nodes are simply markers for debug info.
-            break;
-
-        default:
-        {
-#ifdef DEBUG
-            char message[256];
-            _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
-                        GenTree::NodeName(treeNode->OperGet()));
-            NYIRAW(message);
-#else
-            NYI("unimplemented node");
-#endif
-        }
-        break;
-    }
-}
-
-//------------------------------------------------------------------------
 // genLockedInstructions: Generate code for the locked operations.
 //
 // Notes:
@@ -1168,45 +781,6 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
     NYI_ARM("genCodeForInitBlkUnroll");
 }
 
-void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
-{
-    if (blkOp->gtBlkOpGcUnsafe)
-    {
-        getEmitter()->emitDisableGC();
-    }
-    bool isCopyBlk = blkOp->OperIsCopyBlkOp();
-
-    switch (blkOp->gtBlkOpKind)
-    {
-        case GenTreeBlk::BlkOpKindHelper:
-            if (isCopyBlk)
-            {
-                genCodeForCpBlk(blkOp);
-            }
-            else
-            {
-                genCodeForInitBlk(blkOp);
-            }
-            break;
-        case GenTreeBlk::BlkOpKindUnroll:
-            if (isCopyBlk)
-            {
-                genCodeForCpBlkUnroll(blkOp);
-            }
-            else
-            {
-                genCodeForInitBlkUnroll(blkOp);
-            }
-            break;
-        default:
-            unreached();
-    }
-    if (blkOp->gtBlkOpGcUnsafe)
-    {
-        getEmitter()->emitEnableGC();
-    }
-}
-
 //------------------------------------------------------------------------
 // genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
 //
@@ -1486,6 +1060,58 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
 }
 
 //------------------------------------------------------------------------
+// genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV/GT_MOD/GT_UMOD node.
+//
+// Arguments:
+//    tree - the node
+//
+void CodeGen::genCodeForDivMod(GenTreeOp* tree)
+{
+    assert(tree->OperIs(GT_DIV, GT_UDIV, GT_MOD, GT_UMOD));
+
+    // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
+    // helper call by front-end. Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
+    // on float/double args.
+    noway_assert(tree->OperIs(GT_DIV) || !varTypeIsFloating(tree));
+
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+    emitter*  emit       = getEmitter();
+
+    genConsumeOperands(tree);
+
+    noway_assert(targetReg != REG_NA);
+
+    GenTreePtr  dst    = tree;
+    GenTreePtr  src1   = tree->gtGetOp1();
+    GenTreePtr  src2   = tree->gtGetOp2();
+    instruction ins    = genGetInsForOper(tree->OperGet(), targetType);
+    emitAttr    attr   = emitTypeSize(tree);
+    regNumber   result = REG_NA;
+
+    // dst can only be a reg
+    assert(!dst->isContained());
+
+    // src can be only reg
+    assert(!src1->isContained() || !src2->isContained());
+
+    if (varTypeIsFloating(targetType))
+    {
+        // Floating point divide never raises an exception
+
+        emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
+    }
+    else // an signed integer divide operation
+    {
+        // TODO-ARM-Bug: handle zero division exception.
+
+        emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
+    }
+
+    genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
 // genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node.
 //
 // Arguments:
@@ -1566,6 +1192,22 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
 }
 
 //------------------------------------------------------------------------
+// genCodeForJcc: Produce code for a GT_JCC node.
+//
+// Arguments:
+//    tree - the node
+//
+void CodeGen::genCodeForJcc(GenTreeJumpCC* tree)
+{
+    assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
+
+    CompareKind  compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
+    emitJumpKind jumpKind    = genJumpKindForOper(tree->gtCondition, compareKind);
+
+    inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
+}
+
+//------------------------------------------------------------------------
 // genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
 //
 // Arguments:
index 20eb585..8c87bc1 100644 (file)
@@ -1503,18 +1503,13 @@ void CodeGen::genCodeForMulHi(GenTreeOp* treeNode)
     {
         inst_RV_RV(INS_mov, targetReg, REG_RDX, targetType);
     }
+
+    genProduceReg(treeNode);
 #else  // !0
     NYI("genCodeForMulHi");
 #endif // !0
 }
 
-// generate code for a DIV or MOD operation
-//
-void CodeGen::genCodeForDivMod(GenTreeOp* treeNode)
-{
-    // unused on ARM64
-}
-
 // Generate code for ADD, SUB, MUL, DIV, UDIV, AND, OR and XOR
 // This method is expected to have called genConsumeOperands() before calling it.
 void CodeGen::genCodeForBinary(GenTree* treeNode)
@@ -1942,6 +1937,11 @@ void CodeGen::genReturn(GenTreePtr treeNode)
     GenTreePtr op1        = treeNode->gtGetOp1();
     var_types  targetType = treeNode->TypeGet();
 
+    // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
+    // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
+    // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
+    assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
+
 #ifdef DEBUG
     if (targetType == TYP_VOID)
     {
@@ -2011,539 +2011,6 @@ void CodeGen::genReturn(GenTreePtr treeNode)
 #endif
 }
 
-/*****************************************************************************
- *
- * Generate code for a single node in the tree.
- * Preconditions: All operands have been evaluated
- *
- */
-void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
-{
-    regNumber targetReg  = treeNode->gtRegNum;
-    var_types targetType = treeNode->TypeGet();
-    emitter*  emit       = getEmitter();
-
-#ifdef DEBUG
-    // Validate that all the operands for the current node are consumed in order.
-    // This is important because LSRA ensures that any necessary copies will be
-    // handled correctly.
-    lastConsumedNode = nullptr;
-    if (compiler->verbose)
-    {
-        unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
-        compiler->gtDispLIRNode(treeNode, "Generating: ");
-    }
-#endif // DEBUG
-
-    // Is this a node whose value is already in a register?  LSRA denotes this by
-    // setting the GTF_REUSE_REG_VAL flag.
-    if (treeNode->IsReuseRegVal())
-    {
-        // For now, this is only used for constant nodes.
-        assert((treeNode->OperGet() == GT_CNS_INT) || (treeNode->OperGet() == GT_CNS_DBL));
-        JITDUMP("  TreeNode is marked ReuseReg\n");
-        return;
-    }
-
-    // contained nodes are part of their parents for codegen purposes
-    // ex : immediates, most LEAs
-    if (treeNode->isContained())
-    {
-        return;
-    }
-
-    switch (treeNode->gtOper)
-    {
-        case GT_START_NONGC:
-            getEmitter()->emitDisableGC();
-            break;
-
-        case GT_PROF_HOOK:
-            // We should be seeing this only if profiler hook is needed
-            noway_assert(compiler->compIsProfilerHookNeeded());
-
-#ifdef PROFILING_SUPPORTED
-            // Right now this node is used only for tail calls. In future if
-            // we intend to use it for Enter or Leave hooks, add a data member
-            // to this node indicating the kind of profiler hook. For example,
-            // helper number can be used.
-            genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
-#endif // PROFILING_SUPPORTED
-            break;
-
-        case GT_LCLHEAP:
-            genLclHeap(treeNode);
-            break;
-
-        case GT_CNS_INT:
-        case GT_CNS_DBL:
-            genSetRegToConst(targetReg, targetType, treeNode);
-            genProduceReg(treeNode);
-            break;
-
-        case GT_NOT:
-        case GT_NEG:
-            genCodeForNegNot(treeNode);
-            break;
-
-        case GT_DIV:
-        case GT_UDIV:
-            genConsumeOperands(treeNode->AsOp());
-
-            if (varTypeIsFloating(targetType))
-            {
-                // Floating point divide never raises an exception
-                genCodeForBinary(treeNode);
-            }
-            else // an integer divide operation
-            {
-                GenTreePtr divisorOp = treeNode->gtGetOp2();
-                emitAttr   size      = EA_ATTR(genTypeSize(genActualType(treeNode->TypeGet())));
-
-                if (divisorOp->IsIntegralConst(0))
-                {
-                    // We unconditionally throw a divide by zero exception
-                    genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);
-
-                    // We still need to call genProduceReg
-                    genProduceReg(treeNode);
-                }
-                else // the divisor is not the constant zero
-                {
-                    regNumber divisorReg = divisorOp->gtRegNum;
-
-                    // Generate the require runtime checks for GT_DIV or GT_UDIV
-                    if (treeNode->gtOper == GT_DIV)
-                    {
-                        BasicBlock* sdivLabel = genCreateTempLabel();
-
-                        // Two possible exceptions:
-                        //     (AnyVal /  0) => DivideByZeroException
-                        //     (MinInt / -1) => ArithmeticException
-                        //
-                        bool checkDividend = true;
-
-                        // Do we have an immediate for the 'divisorOp'?
-                        //
-                        if (divisorOp->IsCnsIntOrI())
-                        {
-                            GenTreeIntConCommon* intConstTree  = divisorOp->AsIntConCommon();
-                            ssize_t              intConstValue = intConstTree->IconValue();
-                            assert(intConstValue != 0); // already checked above by IsIntegralConst(0))
-                            if (intConstValue != -1)
-                            {
-                                checkDividend = false; // We statically know that the dividend is not -1
-                            }
-                        }
-                        else // insert check for divison by zero
-                        {
-                            // Check if the divisor is zero throw a DivideByZeroException
-                            emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
-                            emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
-                            genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
-                        }
-
-                        if (checkDividend)
-                        {
-                            // Check if the divisor is not -1 branch to 'sdivLabel'
-                            emit->emitIns_R_I(INS_cmp, size, divisorReg, -1);
-
-                            emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
-                            inst_JMP(jmpNotEqual, sdivLabel);
-                            // If control flow continues past here the 'divisorReg' is known to be -1
-
-                            regNumber dividendReg = treeNode->gtGetOp1()->gtRegNum;
-                            // At this point the divisor is known to be -1
-                            //
-                            // Issue the 'adds  zr, dividendReg, dividendReg' instruction
-                            // this will set both the Z and V flags only when dividendReg is MinInt
-                            //
-                            emit->emitIns_R_R_R(INS_adds, size, REG_ZR, dividendReg, dividendReg);
-                            inst_JMP(jmpNotEqual, sdivLabel);             // goto sdiv if the Z flag is clear
-                            genJumpToThrowHlpBlk(EJ_vs, SCK_ARITH_EXCPN); // if the V flags is set throw
-                                                                          // ArithmeticException
-
-                            genDefineTempLabel(sdivLabel);
-                        }
-                        genCodeForBinary(treeNode); // Generate the sdiv instruction
-                    }
-                    else // (treeNode->gtOper == GT_UDIV)
-                    {
-                        // Only one possible exception
-                        //     (AnyVal /  0) => DivideByZeroException
-                        //
-                        // Note that division by the constant 0 was already checked for above by the
-                        // op2->IsIntegralConst(0) check
-                        //
-                        if (!divisorOp->IsCnsIntOrI())
-                        {
-                            // divisorOp is not a constant, so it could be zero
-                            //
-                            emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
-                            emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
-                            genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
-                        }
-                        genCodeForBinary(treeNode);
-                    }
-                }
-            }
-            break;
-
-        case GT_OR:
-        case GT_XOR:
-        case GT_AND:
-            assert(varTypeIsIntegralOrI(treeNode));
-            __fallthrough;
-        case GT_ADD:
-        case GT_SUB:
-        case GT_MUL:
-            genConsumeOperands(treeNode->AsOp());
-            genCodeForBinary(treeNode);
-            break;
-
-        case GT_LSH:
-        case GT_RSH:
-        case GT_RSZ:
-        case GT_ROR:
-            genCodeForShift(treeNode);
-            // genCodeForShift() calls genProduceReg()
-            break;
-
-        case GT_CAST:
-            if (varTypeIsFloating(targetType) && varTypeIsFloating(treeNode->gtOp.gtOp1))
-            {
-                // Casts float/double <--> double/float
-                genFloatToFloatCast(treeNode);
-            }
-            else if (varTypeIsFloating(treeNode->gtOp.gtOp1))
-            {
-                // Casts float/double --> int32/int64
-                genFloatToIntCast(treeNode);
-            }
-            else if (varTypeIsFloating(targetType))
-            {
-                // Casts int32/uint32/int64/uint64 --> float/double
-                genIntToFloatCast(treeNode);
-            }
-            else
-            {
-                // Casts int <--> int
-                genIntToIntCast(treeNode);
-            }
-            // The per-case functions call genProduceReg()
-            break;
-
-        case GT_LCL_FLD_ADDR:
-        case GT_LCL_VAR_ADDR:
-            // Address of a local var.  This by itself should never be allocated a register.
-            // If it is worth storing the address in a register then it should be cse'ed into
-            // a temp and that would be allocated a register.
-            noway_assert(targetType == TYP_BYREF);
-            noway_assert(!treeNode->InReg());
-
-            inst_RV_TT(INS_lea, targetReg, treeNode, 0, EA_BYREF);
-            genProduceReg(treeNode);
-            break;
-
-        case GT_LCL_FLD:
-            genCodeForLclFld(treeNode->AsLclFld());
-            break;
-
-        case GT_LCL_VAR:
-            genCodeForLclVar(treeNode->AsLclVar());
-            break;
-
-        case GT_STORE_LCL_FLD:
-            genCodeForStoreLclFld(treeNode->AsLclFld());
-            break;
-
-        case GT_STORE_LCL_VAR:
-            genCodeForStoreLclVar(treeNode->AsLclVar());
-            break;
-
-        case GT_RETFILT:
-            // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in
-            // the return register, if it's not already there. The processing is the same as GT_RETURN.
-            if (targetType != TYP_VOID)
-            {
-                // For filters, the IL spec says the result is type int32. Further, the only specified legal values
-                // are 0 or 1, with the use of other values "undefined".
-                assert(targetType == TYP_INT);
-            }
-
-            __fallthrough;
-
-        case GT_RETURN:
-            genReturn(treeNode);
-            break;
-
-        case GT_LEA:
-            // if we are here, it is the case where there is an LEA that cannot
-            // be folded into a parent instruction
-            genLeaInstruction(treeNode->AsAddrMode());
-            break;
-
-        case GT_IND:
-            genConsumeAddress(treeNode->AsIndir()->Addr());
-            emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(treeNode), targetReg, treeNode->AsIndir());
-            genProduceReg(treeNode);
-            break;
-
-        case GT_MULHI:
-            genCodeForMulHi(treeNode->AsOp());
-            genProduceReg(treeNode);
-            break;
-
-        case GT_MOD:
-        case GT_UMOD:
-            // Integer MOD should have been morphed into a sequence of sub, mul, div in fgMorph.
-            //
-            // We shouldn't be seeing GT_MOD on float/double as it is morphed into a helper call by front-end.
-            noway_assert(!"Codegen for GT_MOD/GT_UMOD");
-            break;
-
-        case GT_INTRINSIC:
-            genIntrinsic(treeNode);
-            break;
-
-#ifdef FEATURE_SIMD
-        case GT_SIMD:
-            genSIMDIntrinsic(treeNode->AsSIMD());
-            break;
-#endif // FEATURE_SIMD
-
-        case GT_CKFINITE:
-            genCkfinite(treeNode);
-            break;
-
-        case GT_EQ:
-        case GT_NE:
-        case GT_LT:
-        case GT_LE:
-        case GT_GE:
-        case GT_GT:
-            genCodeForCompare(treeNode->AsOp());
-            break;
-
-        case GT_JTRUE:
-            genCodeForJumpTrue(treeNode);
-            break;
-
-        case GT_RETURNTRAP:
-            genCodeForReturnTrap(treeNode->AsOp());
-            break;
-
-        case GT_STOREIND:
-            genCodeForStoreInd(treeNode->AsStoreInd());
-            break;
-
-        case GT_COPY:
-            // This is handled at the time we call genConsumeReg() on the GT_COPY
-            break;
-
-        case GT_SWAP:
-            genCodeForSwap(treeNode->AsOp());
-            break;
-
-        case GT_LIST:
-        case GT_FIELD_LIST:
-        case GT_ARGPLACE:
-            // Nothing to do
-            break;
-
-        case GT_PUTARG_STK:
-            genPutArgStk(treeNode->AsPutArgStk());
-            break;
-
-        case GT_PUTARG_REG:
-            genPutArgReg(treeNode->AsOp());
-            break;
-
-        case GT_CALL:
-            genCallInstruction(treeNode->AsCall());
-            break;
-
-        case GT_JMP:
-            genJmpMethod(treeNode);
-            break;
-
-        case GT_LOCKADD:
-        case GT_XCHG:
-        case GT_XADD:
-            genLockedInstructions(treeNode->AsOp());
-            break;
-
-        case GT_MEMORYBARRIER:
-            instGen_MemoryBarrier();
-            break;
-
-        case GT_CMPXCHG:
-            NYI("GT_CMPXCHG");
-            break;
-
-        case GT_RELOAD:
-            // do nothing - reload is just a marker.
-            // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
-            // into the register specified in this node.
-            break;
-
-        case GT_NOP:
-            break;
-
-        case GT_NO_OP:
-            if (treeNode->gtFlags & GTF_NO_OP_NO)
-            {
-                noway_assert(!"GTF_NO_OP_NO should not be set");
-            }
-            else
-            {
-                instGen(INS_nop);
-            }
-            break;
-
-        case GT_ARR_BOUNDS_CHECK:
-#ifdef FEATURE_SIMD
-        case GT_SIMD_CHK:
-#endif // FEATURE_SIMD
-            genRangeCheck(treeNode);
-            break;
-
-        case GT_PHYSREG:
-            if (targetReg != treeNode->AsPhysReg()->gtSrcReg)
-            {
-                inst_RV_RV(ins_Copy(targetType), targetReg, treeNode->AsPhysReg()->gtSrcReg, targetType);
-
-                genTransferRegGCState(targetReg, treeNode->AsPhysReg()->gtSrcReg);
-            }
-            genProduceReg(treeNode);
-            break;
-
-        case GT_PHYSREGDST:
-            break;
-
-        case GT_NULLCHECK:
-        {
-            assert(!treeNode->gtOp.gtOp1->isContained());
-            regNumber reg = genConsumeReg(treeNode->gtOp.gtOp1);
-            emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, reg, 0);
-        }
-        break;
-
-        case GT_CATCH_ARG:
-
-            noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
-
-            /* Catch arguments get passed in a register. genCodeForBBlist()
-               would have marked it as holding a GC object, but not used. */
-
-            noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
-            genConsumeReg(treeNode);
-            break;
-
-        case GT_PINVOKE_PROLOG:
-            noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
-
-            // the runtime side requires the codegen here to be consistent
-            emit->emitDisableRandomNops();
-            break;
-
-        case GT_LABEL:
-            genPendingCallLabel       = genCreateTempLabel();
-            treeNode->gtLabel.gtLabBB = genPendingCallLabel;
-
-            // For long address (default): `adrp + add` will be emitted.
-            // For short address (proven later): `adr` will be emitted.
-            emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
-            break;
-
-        case GT_STORE_OBJ:
-            if (treeNode->OperIsCopyBlkOp())
-            {
-                assert(treeNode->AsObj()->gtGcPtrCount != 0);
-                genCodeForCpObj(treeNode->AsObj());
-                break;
-            }
-            __fallthrough;
-
-        case GT_STORE_DYN_BLK:
-        case GT_STORE_BLK:
-        {
-            GenTreeBlk* blkOp = treeNode->AsBlk();
-            if (blkOp->gtBlkOpGcUnsafe)
-            {
-                getEmitter()->emitDisableGC();
-            }
-            bool isCopyBlk = blkOp->OperIsCopyBlkOp();
-
-            switch (blkOp->gtBlkOpKind)
-            {
-                case GenTreeBlk::BlkOpKindHelper:
-                    if (isCopyBlk)
-                    {
-                        genCodeForCpBlk(blkOp);
-                    }
-                    else
-                    {
-                        genCodeForInitBlk(blkOp);
-                    }
-                    break;
-                case GenTreeBlk::BlkOpKindUnroll:
-                    if (isCopyBlk)
-                    {
-                        genCodeForCpBlkUnroll(blkOp);
-                    }
-                    else
-                    {
-                        genCodeForInitBlkUnroll(blkOp);
-                    }
-                    break;
-                default:
-                    unreached();
-            }
-            if (blkOp->gtBlkOpGcUnsafe)
-            {
-                getEmitter()->emitEnableGC();
-            }
-        }
-        break;
-
-        case GT_JMPTABLE:
-            genJumpTable(treeNode);
-            break;
-
-        case GT_SWITCH_TABLE:
-            genTableBasedSwitch(treeNode);
-            break;
-
-        case GT_ARR_INDEX:
-            genCodeForArrIndex(treeNode->AsArrIndex());
-            break;
-
-        case GT_ARR_OFFSET:
-            genCodeForArrOffset(treeNode->AsArrOffs());
-            break;
-
-        case GT_CLS_VAR_ADDR:
-            NYI("GT_CLS_VAR_ADDR");
-            break;
-
-        case GT_IL_OFFSET:
-            // Do nothing; these nodes are simply markers for debug info.
-            break;
-
-        default:
-        {
-#ifdef DEBUG
-            char message[256];
-            _snprintf_s(message, _countof(message), _TRUNCATE, "Unimplemented node type %s\n",
-                        GenTree::NodeName(treeNode->OperGet()));
-#endif
-            assert(!"Unknown node in codegen");
-        }
-        break;
-    }
-}
-
 /***********************************************************************************************
  *  Generate code for localloc
  */
@@ -2915,6 +2382,122 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
     genProduceReg(tree);
 }
 
+//------------------------------------------------------------------------
+// genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV node. We don't see MOD:
+// (1) integer MOD is morphed into a sequence of sub, mul, div in fgMorph;
+// (2) float/double MOD is morphed into a helper call by front-end.
+//
+// Arguments:
+//    tree - the node
+//
+void CodeGen::genCodeForDivMod(GenTreeOp* tree)
+{
+    assert(tree->OperIs(GT_DIV, GT_UDIV));
+
+    var_types targetType = tree->TypeGet();
+    emitter*  emit       = getEmitter();
+
+    genConsumeOperands(tree);
+
+    if (varTypeIsFloating(targetType))
+    {
+        // Floating point divide never raises an exception
+        genCodeForBinary(tree);
+    }
+    else // an integer divide operation
+    {
+        GenTreePtr divisorOp = tree->gtGetOp2();
+        emitAttr   size      = EA_ATTR(genTypeSize(genActualType(tree->TypeGet())));
+
+        if (divisorOp->IsIntegralConst(0))
+        {
+            // We unconditionally throw a divide by zero exception
+            genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);
+
+            // We still need to call genProduceReg
+            genProduceReg(tree);
+        }
+        else // the divisor is not the constant zero
+        {
+            regNumber divisorReg = divisorOp->gtRegNum;
+
+            // Generate the require runtime checks for GT_DIV or GT_UDIV
+            if (tree->gtOper == GT_DIV)
+            {
+                BasicBlock* sdivLabel = genCreateTempLabel();
+
+                // Two possible exceptions:
+                //     (AnyVal /  0) => DivideByZeroException
+                //     (MinInt / -1) => ArithmeticException
+                //
+                bool checkDividend = true;
+
+                // Do we have an immediate for the 'divisorOp'?
+                //
+                if (divisorOp->IsCnsIntOrI())
+                {
+                    GenTreeIntConCommon* intConstTree  = divisorOp->AsIntConCommon();
+                    ssize_t              intConstValue = intConstTree->IconValue();
+                    assert(intConstValue != 0); // already checked above by IsIntegralConst(0))
+                    if (intConstValue != -1)
+                    {
+                        checkDividend = false; // We statically know that the dividend is not -1
+                    }
+                }
+                else // insert check for divison by zero
+                {
+                    // Check if the divisor is zero throw a DivideByZeroException
+                    emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
+                    emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+                    genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
+                }
+
+                if (checkDividend)
+                {
+                    // Check if the divisor is not -1 branch to 'sdivLabel'
+                    emit->emitIns_R_I(INS_cmp, size, divisorReg, -1);
+
+                    emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
+                    inst_JMP(jmpNotEqual, sdivLabel);
+                    // If control flow continues past here the 'divisorReg' is known to be -1
+
+                    regNumber dividendReg = tree->gtGetOp1()->gtRegNum;
+                    // At this point the divisor is known to be -1
+                    //
+                    // Issue the 'adds  zr, dividendReg, dividendReg' instruction
+                    // this will set both the Z and V flags only when dividendReg is MinInt
+                    //
+                    emit->emitIns_R_R_R(INS_adds, size, REG_ZR, dividendReg, dividendReg);
+                    inst_JMP(jmpNotEqual, sdivLabel);             // goto sdiv if the Z flag is clear
+                    genJumpToThrowHlpBlk(EJ_vs, SCK_ARITH_EXCPN); // if the V flags is set throw
+                                                                  // ArithmeticException
+
+                    genDefineTempLabel(sdivLabel);
+                }
+                genCodeForBinary(tree); // Generate the sdiv instruction
+            }
+            else // (tree->gtOper == GT_UDIV)
+            {
+                // Only one possible exception
+                //     (AnyVal /  0) => DivideByZeroException
+                //
+                // Note that division by the constant 0 was already checked for above by the
+                // op2->IsIntegralConst(0) check
+                //
+                if (!divisorOp->IsCnsIntOrI())
+                {
+                    // divisorOp is not a constant, so it could be zero
+                    //
+                    emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
+                    emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+                    genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
+                }
+                genCodeForBinary(tree);
+            }
+        }
+    }
+}
+
 // Generate code for InitBlk by performing a loop unroll
 // Preconditions:
 //   a) Both the size and fill byte value are integer constants.
index ae8b4cc..aea4327 100644 (file)
@@ -25,6 +25,378 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 #include "emit.h"
 
 //------------------------------------------------------------------------
+// genCodeForTreeNode Generate code for a single node in the tree.
+//
+// Preconditions:
+//    All operands have been evaluated.
+//
+void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
+{
+    regNumber targetReg  = treeNode->gtRegNum;
+    var_types targetType = treeNode->TypeGet();
+    emitter*  emit       = getEmitter();
+
+#ifdef DEBUG
+    // Validate that all the operands for the current node are consumed in order.
+    // This is important because LSRA ensures that any necessary copies will be
+    // handled correctly.
+    lastConsumedNode = nullptr;
+    if (compiler->verbose)
+    {
+        unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
+        compiler->gtDispLIRNode(treeNode, "Generating: ");
+    }
+#endif // DEBUG
+
+#ifdef _TARGET_ARM64_ // TODO-ARM: is this applicable to ARM32?
+    // Is this a node whose value is already in a register?  LSRA denotes this by
+    // setting the GTF_REUSE_REG_VAL flag.
+    if (treeNode->IsReuseRegVal())
+    {
+        // For now, this is only used for constant nodes.
+        assert((treeNode->OperGet() == GT_CNS_INT) || (treeNode->OperGet() == GT_CNS_DBL));
+        JITDUMP("  TreeNode is marked ReuseReg\n");
+        return;
+    }
+#endif // _TARGET_ARM64_
+
+    // contained nodes are part of their parents for codegen purposes
+    // ex : immediates, most LEAs
+    if (treeNode->isContained())
+    {
+        return;
+    }
+
+    switch (treeNode->gtOper)
+    {
+#ifdef _TARGET_ARM64_
+
+        case GT_START_NONGC:
+            getEmitter()->emitDisableGC();
+            break;
+
+        case GT_PROF_HOOK:
+            // We should be seeing this only if profiler hook is needed
+            noway_assert(compiler->compIsProfilerHookNeeded());
+
+#ifdef PROFILING_SUPPORTED
+            // Right now this node is used only for tail calls. In future if
+            // we intend to use it for Enter or Leave hooks, add a data member
+            // to this node indicating the kind of profiler hook. For example,
+            // helper number can be used.
+            genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
+#endif // PROFILING_SUPPORTED
+            break;
+
+#endif // _TARGET_ARM64_
+
+        case GT_LCLHEAP:
+            genLclHeap(treeNode);
+            break;
+
+        case GT_CNS_INT:
+        case GT_CNS_DBL:
+            genSetRegToConst(targetReg, targetType, treeNode);
+            genProduceReg(treeNode);
+            break;
+
+        case GT_NOT:
+        case GT_NEG:
+            genCodeForNegNot(treeNode);
+            break;
+
+        case GT_MOD:
+        case GT_UMOD:
+        case GT_DIV:
+        case GT_UDIV:
+            genCodeForDivMod(treeNode->AsOp());
+            break;
+
+        case GT_OR:
+        case GT_XOR:
+        case GT_AND:
+            assert(varTypeIsIntegralOrI(treeNode));
+
+            __fallthrough;
+
+#ifdef _TARGET_ARM_
+        case GT_ADD_LO:
+        case GT_ADD_HI:
+        case GT_SUB_LO:
+        case GT_SUB_HI:
+#endif // _TARGET_ARM_
+
+        case GT_ADD:
+        case GT_SUB:
+        case GT_MUL:
+            genConsumeOperands(treeNode->AsOp());
+            genCodeForBinary(treeNode);
+            break;
+
+        case GT_LSH:
+        case GT_RSH:
+        case GT_RSZ:
+        case GT_ROR:
+            genCodeForShift(treeNode);
+            break;
+
+#ifdef _TARGET_ARM_
+
+        case GT_LSH_HI:
+        case GT_RSH_LO:
+            genCodeForShiftLong(treeNode);
+            break;
+
+#endif // _TARGET_ARM_
+
+        case GT_CAST:
+            genCodeForCast(treeNode->AsOp());
+            break;
+
+        case GT_LCL_FLD_ADDR:
+        case GT_LCL_VAR_ADDR:
+            genCodeForLclAddr(treeNode);
+            break;
+
+        case GT_LCL_FLD:
+            genCodeForLclFld(treeNode->AsLclFld());
+            break;
+
+        case GT_LCL_VAR:
+            genCodeForLclVar(treeNode->AsLclVar());
+            break;
+
+        case GT_STORE_LCL_FLD:
+            genCodeForStoreLclFld(treeNode->AsLclFld());
+            break;
+
+        case GT_STORE_LCL_VAR:
+            genCodeForStoreLclVar(treeNode->AsLclVar());
+            break;
+
+        case GT_RETFILT:
+        case GT_RETURN:
+            genReturn(treeNode);
+            break;
+
+        case GT_LEA:
+            // if we are here, it is the case where there is an LEA that cannot
+            // be folded into a parent instruction
+            genLeaInstruction(treeNode->AsAddrMode());
+            break;
+
+        case GT_IND:
+            genCodeForIndir(treeNode->AsIndir());
+            break;
+
+#ifdef _TARGET_ARM64_
+
+        case GT_MULHI:
+            genCodeForMulHi(treeNode->AsOp());
+            break;
+
+        case GT_CKFINITE:
+            genCkfinite(treeNode);
+            break;
+
+        case GT_SWAP:
+            genCodeForSwap(treeNode->AsOp());
+            break;
+
+        case GT_JMP:
+            genJmpMethod(treeNode);
+            break;
+
+#endif // _TARGET_ARM64_
+
+        case GT_INTRINSIC:
+            genIntrinsic(treeNode);
+            break;
+
+#ifdef FEATURE_SIMD
+        case GT_SIMD:
+            genSIMDIntrinsic(treeNode->AsSIMD());
+            break;
+#endif // FEATURE_SIMD
+
+        case GT_EQ:
+        case GT_NE:
+        case GT_LT:
+        case GT_LE:
+        case GT_GE:
+        case GT_GT:
+            genCodeForCompare(treeNode->AsOp());
+            break;
+
+        case GT_JTRUE:
+            genCodeForJumpTrue(treeNode);
+            break;
+
+#ifdef _TARGET_ARM_
+
+        case GT_JCC:
+            genCodeForJcc(treeNode->AsJumpCC());
+            break;
+
+#endif // _TARGET_ARM_
+
+        case GT_RETURNTRAP:
+            genCodeForReturnTrap(treeNode->AsOp());
+            break;
+
+        case GT_STOREIND:
+            genCodeForStoreInd(treeNode->AsStoreInd());
+            break;
+
+        case GT_COPY:
+            // This is handled at the time we call genConsumeReg() on the GT_COPY
+            break;
+
+        case GT_LIST:
+        case GT_FIELD_LIST:
+        case GT_ARGPLACE:
+            // Nothing to do
+            break;
+
+        case GT_PUTARG_STK:
+            genPutArgStk(treeNode->AsPutArgStk());
+            break;
+
+        case GT_PUTARG_REG:
+            genPutArgReg(treeNode->AsOp());
+            break;
+
+        case GT_CALL:
+            genCallInstruction(treeNode->AsCall());
+            break;
+
+        case GT_LOCKADD:
+        case GT_XCHG:
+        case GT_XADD:
+            genLockedInstructions(treeNode->AsOp());
+            break;
+
+        case GT_MEMORYBARRIER:
+            instGen_MemoryBarrier();
+            break;
+
+        case GT_CMPXCHG:
+            NYI("GT_CMPXCHG");
+            break;
+
+        case GT_RELOAD:
+            // do nothing - reload is just a marker.
+            // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
+            // into the register specified in this node.
+            break;
+
+        case GT_NOP:
+            break;
+
+        case GT_NO_OP:
+            if (treeNode->gtFlags & GTF_NO_OP_NO)
+            {
+                noway_assert(!"GTF_NO_OP_NO should not be set");
+            }
+            else
+            {
+                instGen(INS_nop);
+            }
+            break;
+
+        case GT_ARR_BOUNDS_CHECK:
+#ifdef FEATURE_SIMD
+        case GT_SIMD_CHK:
+#endif // FEATURE_SIMD
+            genRangeCheck(treeNode);
+            break;
+
+        case GT_PHYSREG:
+            genCodeForPhysReg(treeNode->AsPhysReg());
+            break;
+
+        case GT_PHYSREGDST:
+            break;
+
+        case GT_NULLCHECK:
+            genCodeForNullCheck(treeNode->AsOp());
+            break;
+
+        case GT_CATCH_ARG:
+
+            noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
+
+            /* Catch arguments get passed in a register. genCodeForBBlist()
+               would have marked it as holding a GC object, but not used. */
+
+            noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
+            genConsumeReg(treeNode);
+            break;
+
+        case GT_PINVOKE_PROLOG:
+            noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
+
+            // the runtime side requires the codegen here to be consistent
+            emit->emitDisableRandomNops();
+            break;
+
+        case GT_LABEL:
+            genPendingCallLabel       = genCreateTempLabel();
+            treeNode->gtLabel.gtLabBB = genPendingCallLabel;
+            emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
+            break;
+
+        case GT_STORE_OBJ:
+        case GT_STORE_DYN_BLK:
+        case GT_STORE_BLK:
+            genCodeForStoreBlk(treeNode->AsBlk());
+            break;
+
+        case GT_JMPTABLE:
+            genJumpTable(treeNode);
+            break;
+
+        case GT_SWITCH_TABLE:
+            genTableBasedSwitch(treeNode);
+            break;
+
+        case GT_ARR_INDEX:
+            genCodeForArrIndex(treeNode->AsArrIndex());
+            break;
+
+        case GT_ARR_OFFSET:
+            genCodeForArrOffset(treeNode->AsArrOffs());
+            break;
+
+#ifdef _TARGET_ARM_
+
+        case GT_CLS_VAR_ADDR:
+            emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
+            genProduceReg(treeNode);
+            break;
+
+#endif // _TARGET_ARM_
+
+        case GT_IL_OFFSET:
+            // Do nothing; these nodes are simply markers for debug info.
+            break;
+
+        default:
+        {
+#ifdef DEBUG
+            char message[256];
+            _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
+                        GenTree::NodeName(treeNode->OperGet()));
+            NYIRAW(message);
+#else
+            NYI("unimplemented node");
+#endif
+        }
+        break;
+    }
+}
+
+//------------------------------------------------------------------------
 // genSetRegToIcon: Generate code that will set the given register to the integer constant.
 //
 void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags)
@@ -51,6 +423,8 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla
 //
 void CodeGen::genIntrinsic(GenTreePtr treeNode)
 {
+    assert(treeNode->OperIs(GT_INTRINSIC));
+
     // Both operand and its result must be of the same floating point type.
     GenTreePtr srcNode = treeNode->gtOp.gtOp1;
     assert(varTypeIsFloating(srcNode));
@@ -459,7 +833,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
 // genPutArgReg - generate code for a GT_PUTARG_REG node
 //
 // Arguments
-//    treeNode - the GT_PUTARG_REG node
+//    tree - the GT_PUTARG_REG node
 //
 // Return value:
 //    None
@@ -607,6 +981,54 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
     genJumpToThrowHlpBlk(jmpKind, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
 }
 
+//---------------------------------------------------------------------
+// genCodeForPhysReg - generate code for a GT_PHYSREG node
+//
+// Arguments
+//    tree - the GT_PHYSREG node
+//
+// Return value:
+//    None
+//
+void CodeGen::genCodeForPhysReg(GenTreePhysReg* tree)
+{
+    assert(tree->OperIs(GT_PHYSREG));
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+
+    if (targetReg != tree->gtSrcReg)
+    {
+        inst_RV_RV(ins_Copy(targetType), targetReg, tree->gtSrcReg, targetType);
+        genTransferRegGCState(targetReg, tree->gtSrcReg);
+    }
+
+    genProduceReg(tree);
+}
+
+//---------------------------------------------------------------------
+// genCodeForNullCheck - generate code for a GT_NULLCHECK node
+//
+// Arguments
+//    tree - the GT_NULLCHECK node
+//
+// Return value:
+//    None
+//
+void CodeGen::genCodeForNullCheck(GenTreeOp* tree)
+{
+    assert(tree->OperIs(GT_NULLCHECK));
+    assert(!tree->gtOp1->isContained());
+    regNumber addrReg = genConsumeReg(tree->gtOp1);
+
+#ifdef _TARGET_ARM64_
+    regNumber targetReg = REG_ZR;
+#else
+    regNumber targetReg = tree->gtRegNum;
+#endif
+
+    getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
+}
+
 //------------------------------------------------------------------------
 // genOffsetOfMDArrayLowerBound: Returns the offset from the Array object to the
 //   lower bound for the given dimension.
@@ -815,6 +1237,68 @@ void CodeGen::genCodeForShift(GenTreePtr tree)
 }
 
 //------------------------------------------------------------------------
+// genCodeForCast: Generates the code for GT_CAST.
+//
+// Arguments:
+//    tree - the GT_CAST node.
+//
+void CodeGen::genCodeForCast(GenTreeOp* tree)
+{
+    assert(tree->OperIs(GT_CAST));
+
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+
+    // Cast is never contained (?)
+    noway_assert(targetReg != REG_NA);
+
+    if (varTypeIsFloating(targetType) && varTypeIsFloating(tree->gtOp1))
+    {
+        // Casts float/double <--> double/float
+        genFloatToFloatCast(tree);
+    }
+    else if (varTypeIsFloating(tree->gtOp1))
+    {
+        // Casts float/double --> int32/int64
+        genFloatToIntCast(tree);
+    }
+    else if (varTypeIsFloating(targetType))
+    {
+        // Casts int32/uint32/int64/uint64 --> float/double
+        genIntToFloatCast(tree);
+    }
+    else
+    {
+        // Casts int <--> int
+        genIntToIntCast(tree);
+    }
+    // The per-case functions call genProduceReg()
+}
+
+//------------------------------------------------------------------------
+// genCodeForLclAddr: Generates the code for GT_LCL_FLD_ADDR/GT_LCL_VAR_ADDR.
+//
+// Arguments:
+//    tree - the node.
+//
+void CodeGen::genCodeForLclAddr(GenTree* tree)
+{
+    assert(tree->OperIs(GT_LCL_FLD_ADDR, GT_LCL_VAR_ADDR));
+
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+
+    // Address of a local var.  This by itself should never be allocated a register.
+    // If it is worth storing the address in a register then it should be cse'ed into
+    // a temp and that would be allocated a register.
+    noway_assert(targetType == TYP_BYREF);
+    noway_assert(!tree->InReg());
+
+    inst_RV_TT(INS_lea, targetReg, tree, 0, EA_BYREF);
+    genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
 // genCodeForLclFld: Produce code for a GT_LCL_FLD node.
 //
 // Arguments:
@@ -822,6 +1306,8 @@ void CodeGen::genCodeForShift(GenTreePtr tree)
 //
 void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
 {
+    assert(tree->OperIs(GT_LCL_FLD));
+
     var_types targetType = tree->TypeGet();
     regNumber targetReg  = tree->gtRegNum;
     emitter*  emit       = getEmitter();
@@ -856,6 +1342,25 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
     genProduceReg(tree);
 }
 
+//------------------------------------------------------------------------
+// genCodeForIndir: Produce code for a GT_IND node.
+//
+// Arguments:
+//    tree - the GT_IND node
+//
+void CodeGen::genCodeForIndir(GenTreeIndir* tree)
+{
+    assert(tree->OperIs(GT_IND));
+
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+    emitter*  emit       = getEmitter();
+
+    genConsumeAddress(tree->Addr());
+    emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(tree), targetReg, tree);
+    genProduceReg(tree);
+}
+
 // Generate code for a CpBlk node by the means of the VM memcpy helper call
 // Preconditions:
 // a) The size argument of the CpBlk is not an integer constant
@@ -1833,6 +2338,69 @@ void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
     }
 }
 
+//------------------------------------------------------------------------
+// genCodeForStoreBlk: Produce code for a GT_STORE_OBJ/GT_STORE_DYN_BLK/GT_STORE_BLK node.
+//
+// Arguments:
+//    tree - the node
+//
+void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
+{
+    assert(blkOp->OperIs(GT_STORE_OBJ, GT_STORE_DYN_BLK, GT_STORE_BLK));
+
+#ifdef _TARGET_ARM_
+    NYI_IF(blkOp->OperIs(GT_STORE_OBJ), "GT_STORE_OBJ");
+#endif // _TARGET_ARM_
+
+#ifndef _TARGET_ARM_ // NYI for ARM
+    if (blkOp->OperIs(GT_STORE_OBJ) && blkOp->OperIsCopyBlkOp())
+    {
+        assert(blkOp->AsObj()->gtGcPtrCount != 0);
+        genCodeForCpObj(blkOp->AsObj());
+        return;
+    }
+#endif // !_TARGET_ARM_
+
+    if (blkOp->gtBlkOpGcUnsafe)
+    {
+        getEmitter()->emitDisableGC();
+    }
+    bool isCopyBlk = blkOp->OperIsCopyBlkOp();
+
+    switch (blkOp->gtBlkOpKind)
+    {
+        case GenTreeBlk::BlkOpKindHelper:
+            if (isCopyBlk)
+            {
+                genCodeForCpBlk(blkOp);
+            }
+            else
+            {
+                genCodeForInitBlk(blkOp);
+            }
+            break;
+
+        case GenTreeBlk::BlkOpKindUnroll:
+            if (isCopyBlk)
+            {
+                genCodeForCpBlkUnroll(blkOp);
+            }
+            else
+            {
+                genCodeForInitBlkUnroll(blkOp);
+            }
+            break;
+
+        default:
+            unreached();
+    }
+
+    if (blkOp->gtBlkOpGcUnsafe)
+    {
+        getEmitter()->emitEnableGC();
+    }
+}
+
 #endif // _TARGET_ARMARCH_
 
 #endif // !LEGACY_BACKEND
index 1f5bec8..94cc9b9 100644 (file)
@@ -7446,7 +7446,17 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
 
             var_types storeType = varDsc->lvaArgType();
             regNumber argReg    = varDsc->lvArgReg;
-            getEmitter()->emitIns_S_R(ins_Store(storeType), emitTypeSize(storeType), argReg, varNum, 0);
+
+            instruction store_ins = ins_Store(storeType);
+
+#ifdef FEATURE_SIMD
+            if ((storeType == TYP_SIMD8) && genIsValidIntReg(argReg))
+            {
+                store_ins = INS_mov;
+            }
+#endif // FEATURE_SIMD
+
+            getEmitter()->emitIns_S_R(store_ins, emitTypeSize(storeType), argReg, varNum, 0);
         }
     }
 
@@ -7509,7 +7519,17 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
 
         var_types loadType = varDsc->lvaArgType();
         regNumber argReg   = varDsc->lvArgReg;
-        getEmitter()->emitIns_R_S(ins_Load(loadType), emitTypeSize(loadType), argReg, varNum, 0);
+
+        instruction load_ins = ins_Load(loadType);
+
+#ifdef FEATURE_SIMD
+        if ((loadType == TYP_SIMD8) && genIsValidIntReg(argReg))
+        {
+            load_ins = INS_mov;
+        }
+#endif // FEATURE_SIMD
+
+        getEmitter()->emitIns_R_S(load_ins, emitTypeSize(loadType), argReg, varNum, 0);
 
 #if FEATURE_VARARG
         if (compiler->info.compIsVarArgs && varTypeIsFloating(loadType))
index b0fb36f..afc7db3 100644 (file)
@@ -1228,7 +1228,7 @@ void CodeGen::genConsumeRegs(GenTree* tree)
             genConsumeAddress(tree->AsIndir()->Addr());
         }
 #ifdef _TARGET_XARCH_
-        else if (tree->OperGet() == GT_LCL_VAR)
+        else if (tree->OperIsLocalRead())
         {
             // A contained lcl var must be living on stack and marked as reg optional, or not be a
             // register candidate.
index d0281a0..3bd0eac 100644 (file)
@@ -11,9 +11,7 @@
 #ifndef LEGACY_BACKEND // Not necessary (it's this way in the #include location), but helpful to IntelliSense
 
 void genSetRegToConst(regNumber targetReg, var_types targetType, GenTreePtr tree);
-
 void genCodeForTreeNode(GenTreePtr treeNode);
-
 void genCodeForBinary(GenTreePtr treeNode);
 
 #if defined(_TARGET_X86_)
@@ -21,11 +19,8 @@ void genCodeForLongUMod(GenTreeOp* node);
 #endif // _TARGET_X86_
 
 void genCodeForDivMod(GenTreeOp* treeNode);
-
 void genCodeForMulHi(GenTreeOp* treeNode);
-
 void genLeaInstruction(GenTreeAddrMode* lea);
-
 void genSetRegToCond(regNumber dstReg, GenTreePtr tree);
 
 #if !defined(_TARGET_64BIT_)
@@ -33,21 +28,13 @@ void genLongToIntCast(GenTreePtr treeNode);
 #endif
 
 void genIntToIntCast(GenTreePtr treeNode);
-
 void genFloatToFloatCast(GenTreePtr treeNode);
-
 void genFloatToIntCast(GenTreePtr treeNode);
-
 void genIntToFloatCast(GenTreePtr treeNode);
-
 void genCkfinite(GenTreePtr treeNode);
-
 void genCodeForCompare(GenTreeOp* tree);
-
 void genIntrinsic(GenTreePtr treeNode);
-
 void genPutArgStk(GenTreePutArgStk* treeNode);
-
 void genPutArgReg(GenTreeOp* tree);
 
 #if defined(_TARGET_XARCH_)
@@ -59,7 +46,6 @@ unsigned getFirstArgWithStackSlot();
 #endif // _TARGET_XARCH_ || _TARGET_ARM64_
 
 void genCompareFloat(GenTreePtr treeNode);
-
 void genCompareInt(GenTreePtr treeNode);
 
 #if !defined(_TARGET_64BIT_)
@@ -94,7 +80,6 @@ void genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode);
 void genSIMDIntrinsicShuffleSSE2(GenTreeSIMD* simdNode);
 void genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode);
 void genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode);
-
 void genSIMDIntrinsic(GenTreeSIMD* simdNode);
 void genSIMDCheck(GenTree* treeNode);
 
@@ -122,11 +107,8 @@ void genStoreLongLclVar(GenTree* treeNode);
 #endif // !defined(_TARGET_64BIT_)
 
 void genProduceReg(GenTree* tree);
-
 void genUnspillRegIfNeeded(GenTree* tree);
-
 regNumber genConsumeReg(GenTree* tree);
-
 void genCopyRegIfNeeded(GenTree* tree, regNumber needReg);
 void genConsumeRegAndCopy(GenTree* tree, regNumber needReg);
 
@@ -139,13 +121,9 @@ void genConsumeIfReg(GenTreePtr tree)
 }
 
 void genRegCopy(GenTreePtr tree);
-
 void genTransferRegGCState(regNumber dst, regNumber src);
-
 void genConsumeAddress(GenTree* addr);
-
 void genConsumeAddrMode(GenTreeAddrMode* mode);
-
 void genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg);
 void genConsumeBlockSrc(GenTreeBlk* blkNode);
 void genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg);
@@ -156,13 +134,9 @@ void genConsumePutStructArgStk(GenTreePutArgStk* putArgStkNode, regNumber dstReg
 #endif // FEATURE_PUT_STRUCT_ARG_STK
 
 void genConsumeRegs(GenTree* tree);
-
 void genConsumeOperands(GenTreeOp* tree);
-
 void genEmitGSCookieCheck(bool pushReg);
-
 void genSetRegToIcon(regNumber reg, ssize_t val, var_types type = TYP_INT, insFlags flags = INS_FLAGS_DONT_CARE);
-
 void genCodeForShift(GenTreePtr tree);
 
 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
@@ -173,29 +147,24 @@ void genCodeForShiftLong(GenTreePtr tree);
 void genCodeForShiftRMW(GenTreeStoreInd* storeInd);
 #endif // _TARGET_XARCH_
 
+void genCodeForCast(GenTreeOp* tree);
+void genCodeForLclAddr(GenTree* tree);
+void genCodeForIndir(GenTreeIndir* tree);
 void genCodeForNegNot(GenTree* tree);
-
 void genCodeForLclVar(GenTreeLclVar* tree);
-
 void genCodeForLclFld(GenTreeLclFld* tree);
-
 void genCodeForStoreLclFld(GenTreeLclFld* tree);
-
 void genCodeForStoreLclVar(GenTreeLclVar* tree);
-
 void genCodeForReturnTrap(GenTreeOp* tree);
-
+void genCodeForJcc(GenTreeJumpCC* tree);
 void genCodeForStoreInd(GenTreeStoreInd* tree);
-
 void genCodeForSwap(GenTreeOp* tree);
-
 void genCodeForCpObj(GenTreeObj* cpObjNode);
-
 void genCodeForCpBlk(GenTreeBlk* cpBlkNode);
-
 void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
-
 void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
+void genCodeForPhysReg(GenTreePhysReg* tree);
+void genCodeForNullCheck(GenTreeOp* tree);
 
 void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
 void genAlignStackBeforeCall(GenTreeCall* call);
@@ -254,43 +223,27 @@ void genStoreRegToStackArg(var_types type, regNumber reg, int offset);
 #endif // FEATURE_PUT_STRUCT_ARG_STK
 
 void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
-
 void genCodeForStoreOffset(instruction ins, emitAttr size, regNumber src, GenTree* base, unsigned offset);
 
 #ifdef _TARGET_ARM64_
 void genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset);
-
 void genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset);
 #endif // _TARGET_ARM64_
 
 void genCodeForStoreBlk(GenTreeBlk* storeBlkNode);
-
 void genCodeForInitBlk(GenTreeBlk* initBlkNode);
-
 void genCodeForInitBlkRepStos(GenTreeBlk* initBlkNode);
-
 void genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode);
-
 void genJumpTable(GenTree* tree);
-
 void genTableBasedSwitch(GenTree* tree);
-
 void genCodeForArrIndex(GenTreeArrIndex* treeNode);
-
 void genCodeForArrOffset(GenTreeArrOffs* treeNode);
-
 instruction genGetInsForOper(genTreeOps oper, var_types type);
-
 void genStoreInd(GenTreePtr node);
-
 bool genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarrierForm, GenTree* addr, GenTree* data);
-
 void genCallInstruction(GenTreeCall* call);
-
 void genJmpMethod(GenTreePtr jmp);
-
 BasicBlock* genCallFinally(BasicBlock* block);
-
 void genCodeForJumpTrue(GenTreePtr tree);
 
 #if FEATURE_EH_FUNCLETS
@@ -305,7 +258,6 @@ void genMultiRegCallStoreToLocal(GenTreePtr treeNode);
 bool isStructReturn(GenTreePtr treeNode);
 void genStructReturn(GenTreePtr treeNode);
 
-// Codegen for GT_RETURN.
 void genReturn(GenTreePtr treeNode);
 
 void genLclHeap(GenTreePtr tree);
index d693ff9..42f041d 100644 (file)
@@ -1558,6 +1558,8 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
             GenTreePtr op1 = treeNode->gtGetOp1();
             genConsumeRegs(op1);
             emit->emitInsBinary(ins_Store(targetType), emitTypeSize(treeNode), treeNode, op1);
+
+            genUpdateLife(treeNode);
         }
         break;
 
index 9737c13..c2e2cfa 100644 (file)
@@ -3526,6 +3526,10 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
                                     gtNewIconNode(offsetof(CORINFO_String, stringLen), TYP_I_IMPL));
                 op1 = gtNewOperNode(GT_IND, TYP_INT, op1);
             }
+
+            // Getting the length of a null string should throw
+            op1->gtFlags |= GTF_EXCEPT;
+
             retNode = op1;
             break;
 
index 035f094..72dba4e 100644 (file)
@@ -2872,8 +2872,10 @@ void Lowering::InsertPInvokeMethodProlog()
     store->gtOp.gtOp1 = call;
     store->gtFlags |= GTF_VAR_DEF;
 
+    GenTree* const insertionPoint = firstBlockRange.FirstNonPhiOrCatchArgNode();
+
     comp->fgMorphTree(store);
-    firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, store));
+    firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, store));
     DISPTREERANGE(firstBlockRange, store);
 
 #if !defined(_TARGET_X86_) && !defined(_TARGET_ARM_)
@@ -2887,7 +2889,7 @@ void Lowering::InsertPInvokeMethodProlog()
         GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfCallSiteSP);
     storeSP->gtOp1 = PhysReg(REG_SPBASE);
 
-    firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, storeSP));
+    firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeSP));
     DISPTREERANGE(firstBlockRange, storeSP);
 
 #endif // !defined(_TARGET_X86_) && !defined(_TARGET_ARM_)
@@ -2903,7 +2905,7 @@ void Lowering::InsertPInvokeMethodProlog()
                                                    callFrameInfo.offsetOfCalleeSavedFP);
     storeFP->gtOp1 = PhysReg(REG_FPBASE);
 
-    firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, storeFP));
+    firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeFP));
     DISPTREERANGE(firstBlockRange, storeFP);
 #endif // !defined(_TARGET_ARM_)
 
@@ -2918,7 +2920,7 @@ void Lowering::InsertPInvokeMethodProlog()
         // Push a frame - if we are NOT in an IL stub, this is done right before the call
         // The init routine sets InlinedCallFrame's m_pNext, so we just set the thead's top-of-stack
         GenTree* frameUpd = CreateFrameLinkUpdate(PushFrame);
-        firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, frameUpd));
+        firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, frameUpd));
         DISPTREERANGE(firstBlockRange, frameUpd);
     }
 #endif // _TARGET_64BIT_
index 637fa45..5f6fa7c 100644 (file)
@@ -1573,7 +1573,7 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
 
   #define RBM_CALLEE_SAVED        (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
   #define RBM_CALLEE_TRASH        (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
-  #define RBM_CALLEE_TRASH_NOGC   (RBM_R12|RBM_R13|RBM_R14|RBM_R15)
+  #define RBM_CALLEE_TRASH_NOGC   (RBM_R12|RBM_R13|RBM_R14|RBM_R15|RBM_IP1)
   #define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
 
   #define RBM_ALLINT              (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
index 791d1ca..90409f7 100644 (file)
   <data name="ArgumentOutOfRange_ArrayLBAndLength" xml:space="preserve">
     <value>Higher indices will exceed Int32.MaxValue because of large lower bound and/or length.</value>
   </data>
-  <data name="ArgumentOutOfRange_ArrayListInsert" xml:space="preserve">
-    <value>Insertion index was out of range. Must be non-negative and less than or equal to size.</value>
-  </data>
   <data name="ArgumentOutOfRange_BadHourMinuteSecond" xml:space="preserve">
     <value>Hour, Minute, and Second parameters describe an un-representable DateTime.</value>
   </data>
index 3171491..e519199 100644 (file)
     <AssemblyInfoLines Include="[assembly: System.Security.AllowPartiallyTrustedCallers]" />
     <AssemblyInfoLines Include="[assembly: System.Runtime.InteropServices.ComVisible(false)]" />
     <AssemblyInfoLines Include="[assembly: System.Resources.NeutralResourcesLanguage(&quot;en-US&quot;)]" />
+    <AssemblyInfoLines Include="[assembly: System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute(System.Runtime.InteropServices.DllImportSearchPath.AssemblyDirectory | System.Runtime.InteropServices.DllImportSearchPath.System32)]" />
   </ItemGroup>
   <!--
     Helper Paths
     <Compile Include="$(BclSourcesRoot)\System\Runtime\GcSettings.cs" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="$(BclSourcesRoot)\System\Collections\ArrayList.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Collections\Comparer.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Collections\CompatibleComparer.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Collections\ListDictionaryInternal.cs" />
     <Compile Include="$(BclSourcesRoot)\System\MissingMemberException.cs" />
     <Compile Include="$(BclSourcesRoot)\System\NonSerializedAttribute.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Number.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\OperatingSystem.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\OperationCanceledException.cs" />
     <Compile Include="$(BclSourcesRoot)\System\ParseNumbers.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\PlatformID.cs" />
     <Compile Include="$(BclSourcesRoot)\System\ResId.cs" />
     <Compile Include="$(BclSourcesRoot)\System\RtType.cs" />
     <Compile Include="$(BclSourcesRoot)\System\RuntimeArgumentHandle.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\GregorianCalendar.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\GregorianCalendarHelper.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\IdnMapping.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\NumberFormatInfo.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\RegionInfo.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\SortKey.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\StringInfo.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\TextElementEnumerator.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\TextInfo.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\TimeSpanFormat.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\Monitor.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\Mutex.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\Overlapped.cs" />
+    <Compile Include="$(BclSourcesRoot)\System\Threading\PinnableBufferCache.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\Semaphore.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\Thread.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\ThreadInterruptedException.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\Directory.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\SearchOption.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\DriveNotFoundException.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\IO\EncodingCache.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\File.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\FileLoadException.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\FileNotFoundException.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\IOException.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\MemoryStream.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\IO\PinnedBufferMemoryStream.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\Stream.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryAccessor.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryStream.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryStreamWrapper.cs" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="$(BclSourcesRoot)\System\Security\DynamicSecurityMethodAttribute.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Runtime\Serialization\SerializationInfo.cs" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="$(BclSourcesRoot)\System\Runtime\Remoting\ObjectHandle.cs" />
-  </ItemGroup>
-  <ItemGroup>
     <Compile Include="$(BclSourcesRoot)\System\Text\DecoderNLS.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Text\DecoderBestFitFallback.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Text\DecoderExceptionFallback.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Numerics\Hashing\HashHelpers.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(TargetsUnix)' == 'true'">
-    <Compile Include="$(BclSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.Collation.cs" />
     <Compile Include="$(BclSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.ICU.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Debug.Unix.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\CalendarData.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\CompareInfo.Unix.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\CultureData.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\CultureInfo.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\EncodingTable.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\EncodingDataItem.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Unix.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\HijriCalendar.Unix.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\IdnMapping.Unix.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\JapaneseCalendar.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\TextInfo.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\FileSystemEnumerable.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IO\TextReader.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\CultureData.Windows.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\CultureInfo.Windows.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Windows.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\HijriCalendar.Win32.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\IdnMapping.Windows.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Globalization\JapaneseCalendar.Win32.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\TextInfo.Windows.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Text\Normalization.Windows.cs" />
     <Compile Include="$(BclSourcesRoot)\System\TimeZoneInfo.Win32.cs" />
     <Compile Include="$(CommonPath)\Preprocessed\AssemblyRefs.g.cs" />
     <!-- These files are shared with other framework components and don't live the same folder as the rest of them-->
     <Compile Include="$(CommonPath)\NotImplemented.cs" />
-    <Compile Include="$(CommonPath)\PinnableBufferCache.cs" />
     <Compile Include="$(CommonPath)\System\SR.cs" />
     <!-- Include Internals visible to file in the compilation -->
     <Compile Include="$(BclSourcesRoot)\mscorlib.Friends.cs" />
@@ -3,7 +3,6 @@
 // See the LICENSE file in the project root for more information.
 
 using System;
-using System.Diagnostics;
 using System.Globalization;
 using System.Runtime.InteropServices;
 using System.Security;
@@ -61,8 +60,6 @@ internal static partial class Interop
 
             protected override bool ReleaseHandle()
             {
-                Debug.Assert(!GlobalizationMode.Invariant);
-
                 CloseSortHandle(handle);
                 SetHandle(IntPtr.Zero);
                 return true;
index 2bb349d..7d3287f 100644 (file)
@@ -89,20 +89,20 @@ internal static partial class Interop
         internal static extern bool GetUserPreferredUILanguages(uint dwFlags, out uint pulNumLanguages, char [] pwszLanguagesBuffer, ref uint pcchLanguagesBuffer);
 
         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
-        internal static extern int GetLocaleInfoEx(string lpLocaleName, uint LCType, IntPtr lpLCData, int cchData);
+        internal static extern int GetLocaleInfoEx(string lpLocaleName, uint LCType, void* lpLCData, int cchData);
 
         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
-        internal extern static bool EnumSystemLocalesEx(EnumLocalesProcEx lpLocaleEnumProcEx, uint dwFlags, IntPtr lParam, IntPtr reserved);
+        internal extern static bool EnumSystemLocalesEx(EnumLocalesProcEx lpLocaleEnumProcEx, uint dwFlags, void* lParam, IntPtr reserved);
 
-        internal delegate BOOL EnumLocalesProcEx(IntPtr lpLocaleString, uint dwFlags, IntPtr lParam);
+        internal delegate BOOL EnumLocalesProcEx(char* lpLocaleString, uint dwFlags, void* lParam);
 
         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
         internal extern static int ResolveLocaleName(string lpNameToResolve, char* lpLocaleName, int cchLocaleName);
 
         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
-        internal extern static bool EnumTimeFormatsEx(EnumTimeFormatsProcEx lpTimeFmtEnumProcEx, string lpLocaleName, uint dwFlags, IntPtr lParam);
+        internal extern static bool EnumTimeFormatsEx(EnumTimeFormatsProcEx lpTimeFmtEnumProcEx, string lpLocaleName, uint dwFlags, void* lParam);
   
-        internal delegate BOOL EnumTimeFormatsProcEx(IntPtr lpTimeFormatString, IntPtr lParam);
+        internal delegate BOOL EnumTimeFormatsProcEx(char* lpTimeFormatString, void* lParam);
 
         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
         internal extern static int GetCalendarInfoEx(string lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, out int lpValue);
@@ -111,12 +111,12 @@ internal static partial class Interop
         internal extern static int GetCalendarInfoEx(string lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, IntPtr lpValue);
 
         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
-        internal extern static bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string lpReserved, uint CalType, IntPtr lParam);
+        internal extern static bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string lpReserved, uint CalType, void* lParam);
         
-        internal delegate BOOL EnumCalendarInfoProcExEx(IntPtr lpCalendarInfoString, uint Calendar, IntPtr lpReserved, IntPtr lParam);
+        internal delegate BOOL EnumCalendarInfoProcExEx(char* lpCalendarInfoString, uint Calendar, IntPtr lpReserved, void* lParam);
 
         [StructLayout(LayoutKind.Sequential)]
-        internal struct NlsVersionInfoEx 
+        internal struct NlsVersionInfoEx
         {
             internal int dwNLSVersionInfoSize;
             internal int dwNLSVersion;
index f09d827..3e00140 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JulianCalendar.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\KoreanCalendar.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\KoreanLunisolarCalendar.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberFormatInfo.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberStyles.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\PersianCalendar.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\SortKey.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\SortVersion.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\StringInfo.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TaiwanCalendar.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TaiwanLunisolarCalendar.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ThaiBuddhistCalendar.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\InvalidProgramException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\InvalidTimeZoneException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\DirectoryNotFoundException.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\IO\EncodingCache.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\EndOfStreamException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\Error.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileAccess.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\PathTooLongException.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\IO\PinnedBufferMemoryStream.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\SeekOrigin.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\StreamHelpers.CopyValidation.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\IO\UnmanagedMemoryStream.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\IO\UnmanagedMemoryStreamWrapper.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IObservable.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IObserver.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IProgress.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\NullReferenceException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\ObjectDisposedException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\ObsoleteAttribute.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\OperationCanceledException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\OverflowException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\ParamArrayAttribute.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\ParamsArray.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempFileNameW.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempPathW.cs"/>
-    <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Globalization.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Globalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LockFile.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.OutputDebugString.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysFreeString.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysStringLen.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" Condition="'$(IsProjectNLibrary)' != 'true' and '$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.WinRT.cs" Condition="'$(IsProjectNLibrary)' == 'true'"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Win32.cs" Condition="'$(IsProjectNLibrary)' != 'true' and '$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.WinRT.cs" Condition="'$(IsProjectNLibrary)' == 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" Condition="'$(IsProjectNLibrary)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.WinRT.cs" Condition="'$(IsProjectNLibrary)' == 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\Interop.Libraries.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Calendar.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Casing.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+    <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Collation.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Idna.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Locale.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Normalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Unlink.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Write.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Debug.Unix.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\LocaleData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.OSX.cs" Condition="'$(TargetsOSX)' == 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Linux.cs" Condition="'$(TargetsOSX)' != 'true'"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Unix.cs"/>
@@ -306,21 +306,30 @@ namespace System.Globalization
 
         private static void EnumCalendarInfoCallback(string calendarString, IntPtr context)
         {
-            CallbackContext callbackContext = (CallbackContext)((GCHandle)context).Target;
-
-            if (callbackContext.DisallowDuplicates)
+            try
             {
-                foreach (string existingResult in callbackContext.Results)
+                CallbackContext callbackContext = (CallbackContext)((GCHandle)context).Target;
+
+                if (callbackContext.DisallowDuplicates)
                 {
-                    if (string.Equals(calendarString, existingResult, StringComparison.Ordinal))
+                    foreach (string existingResult in callbackContext.Results)
                     {
-                        // the value is already in the results, so don't add it again
-                        return;
+                        if (string.Equals(calendarString, existingResult, StringComparison.Ordinal))
+                        {
+                            // the value is already in the results, so don't add it again
+                            return;
+                        }
                     }
                 }
-            }
 
-            callbackContext.Results.Add(calendarString);
+                callbackContext.Results.Add(calendarString);
+            }
+            catch (Exception e)
+            {
+                Debug.Assert(false, e.ToString());
+                // we ignore the managed exceptions here because EnumCalendarInfoCallback will get called from the native code.
+                // If we don't ignore the exception here that can cause the runtime to fail fast.
+            }
         }
 
         private class CallbackContext
@@ -39,7 +39,7 @@ namespace System.Globalization
             }
 
             char[] outputHeap = new char[actualLength];
-            fixed (char* pOutputHeap = outputHeap)
+            fixed (char* pOutputHeap = &outputHeap[0])
             {
                 actualLength = Interop.GlobalizationInterop.ToAscii(flags, unicode, count, pOutputHeap, actualLength);
                 if (actualLength == 0 || actualLength > outputHeap.Length)
@@ -66,7 +66,7 @@ namespace System.Globalization
             else
             {
                 char[] output = new char[count];
-                fixed (char* pOutput = output)
+                fixed (char* pOutput = &output[0])
                 {
                     return GetUnicodeCore(ascii, count, flags, pOutput, count, reattempt: true);
                 }
@@ -84,7 +84,7 @@ namespace System.Globalization
         internal int percentDecimalDigits = 2;
 
         [OptionalField(VersionAdded = 2)]
-        internal int digitSubstitution = (int) DigitShapes.None;
+        internal int digitSubstitution = (int)DigitShapes.None;
 
         internal bool isReadOnly = false;
 
@@ -131,7 +131,7 @@ namespace System.Globalization
             Contract.EndContractBlock();
         }
 
-        private static void VerifyNativeDigits(string [] nativeDig, string propertyName)
+        private static void VerifyNativeDigits(string[] nativeDig, string propertyName)
         {
             if (nativeDig == null)
             {
@@ -157,7 +157,7 @@ namespace System.Globalization
                     {
                         // Not 1 or 2 UTF-16 code points
                         throw new ArgumentException(SR.Argument_InvalidNativeDigitValue, propertyName);
-                    } 
+                    }
                     else if (!char.IsSurrogatePair(nativeDig[i][0], nativeDig[i][1]))
                     {
                         // 2 UTF-6 code points, but not a surrogate pair
@@ -175,8 +175,8 @@ namespace System.Globalization
             }
         }
 
-         private static void VerifyDigitSubstitution(DigitShapes digitSub, string propertyName)
-         {
+        private static void VerifyDigitSubstitution(DigitShapes digitSub, string propertyName)
+        {
             switch (digitSub)
             {
                 case DigitShapes.Context:
@@ -309,7 +309,7 @@ namespace System.Globalization
             set
             {
                 VerifyWritable();
-                VerifyDecimalSeparator(value, "CurrencyDecimalSeparator");
+                VerifyDecimalSeparator(value, nameof(CurrencyDecimalSeparator));
                 currencyDecimalSeparator = value;
             }
         }
@@ -404,13 +404,13 @@ namespace System.Globalization
             {
                 if (value == null)
                 {
-                    throw new ArgumentNullException("PercentGroupSizes",
+                    throw new ArgumentNullException(nameof(PercentGroupSizes),
                         SR.ArgumentNull_Obj);
                 }
                 Contract.EndContractBlock();
                 VerifyWritable();
                 Int32[] inputSizes = (Int32[])value.Clone();
-                CheckGroupSize("PercentGroupSizes", inputSizes);
+                CheckGroupSize(nameof(PercentGroupSizes), inputSizes);
                 percentGroupSizes = inputSizes;
             }
         }
@@ -807,9 +807,9 @@ namespace System.Globalization
             }
         }
 
-        public string [] NativeDigits
+        public string[] NativeDigits
         {
-            get { return (String[]) nativeDigits.Clone(); }
+            get { return (String[])nativeDigits.Clone(); }
             set
             {
                 VerifyWritable();
@@ -820,12 +820,12 @@ namespace System.Globalization
 
         public DigitShapes DigitSubstitution
         {
-            get { return (DigitShapes) digitSubstitution; } 
+            get { return (DigitShapes)digitSubstitution; }
             set
             {
                 VerifyWritable();
                 VerifyDigitSubstitution(value, nameof(DigitSubstitution));
-                digitSubstitution = (int) value;
+                digitSubstitution = (int)value;
             }
         }
 
 //
 ////////////////////////////////////////////////////////////////////////////
 
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+
 namespace System.Globalization
 {
-    using System;
-    using System.Runtime.CompilerServices;
-    using System.Runtime.Serialization;
-    using System.Diagnostics;
-    using System.Diagnostics.Contracts;
-
     [Serializable]
     public partial class SortKey
     {
@@ -30,8 +30,7 @@ namespace System.Globalization
         internal string _localeName;       // locale identifier
 
         [OptionalField(VersionAdded = 1)] // LCID field so serialization is Whidbey compatible though we don't officially support it
-        internal int _win32LCID;            
-                                          // Whidbey serialization 
+        internal int _win32LCID;
 
         internal CompareOptions _options;  // options
         internal string _string;         // original string
@@ -45,8 +44,8 @@ namespace System.Globalization
         {
             _keyData = keyData;
             _localeName = localeName;
-            _options    = options;
-            _string   = str;
+            _options = options;
+            _string = str;
         }
 
         [OnSerializing]
@@ -84,7 +83,7 @@ namespace System.Globalization
                 return (_string);
             }
         }
-    
+
         ////////////////////////////////////////////////////////////////////////
         //
         //  GetKeyData
@@ -100,7 +99,7 @@ namespace System.Globalization
                 return (byte[])(_keyData.Clone());
             }
         }
-    
+
         ////////////////////////////////////////////////////////////////////////
         //
         //  Compare
@@ -112,14 +111,15 @@ namespace System.Globalization
         ////////////////////////////////////////////////////////////////////////
         public static int Compare(SortKey sortkey1, SortKey sortkey2)
         {
-            if (sortkey1==null || sortkey2==null)
+            if (sortkey1 == null || sortkey2 == null)
             {
                 throw new ArgumentNullException((sortkey1 == null ? nameof(sortkey1) : nameof(sortkey2)));
             }
             Contract.EndContractBlock();
+
             byte[] key1Data = sortkey1._keyData;
             byte[] key2Data = sortkey2._keyData;
-    
+
             Debug.Assert(key1Data != null, "key1Data != null");
             Debug.Assert(key2Data != null, "key2Data != null");
 
@@ -138,13 +138,13 @@ namespace System.Globalization
 
             int compLen = (key1Data.Length < key2Data.Length) ? key1Data.Length : key2Data.Length;
 
-            for (int i=0; i<compLen; i++)
+            for (int i = 0; i < compLen; i++)
             {
-                if (key1Data[i]>key2Data[i])
+                if (key1Data[i] > key2Data[i])
                 {
                     return (1);
                 }
-                if (key1Data[i]<key2Data[i])
+                if (key1Data[i] < key2Data[i])
                 {
                     return (-1);
                 }
@@ -93,7 +93,7 @@ namespace System.Globalization
             {
                 if (null == value)
                 {
-                    throw new ArgumentNullException("String",
+                    throw new ArgumentNullException(nameof(String),
                         SR.ArgumentNull_String);
                 }
                 Contract.EndContractBlock();
@@ -117,13 +117,13 @@ namespace System.Globalization
             }
         }
 
-        public string SubstringByTextElements(int startingTextElement) 
+        public string SubstringByTextElements(int startingTextElement)
         {
             // If the string is empty, no sense going further. 
-            if (null == this.Indexes) 
+            if (null == this.Indexes)
             {
                 // Just decide which error to give depending on the param they gave us....
-                if (startingTextElement < 0) 
+                if (startingTextElement < 0)
                 {
                     throw new ArgumentOutOfRangeException(nameof(startingTextElement), SR.ArgumentOutOfRange_NeedPosNum);
                 }
@@ -135,7 +135,7 @@ namespace System.Globalization
             return (SubstringByTextElements(startingTextElement, Indexes.Length - startingTextElement));
         }
 
-        public string SubstringByTextElements(int startingTextElement, int lengthInTextElements) 
+        public string SubstringByTextElements(int startingTextElement, int lengthInTextElements)
         {
             if (startingTextElement < 0)
             {
index 7c09ae1..c036ee6 100644 (file)
@@ -1599,7 +1599,7 @@ namespace System.IO
             {
                 var awaitable = (AsyncCopyToAwaitable)ThreadPoolBoundHandle.GetNativeOverlappedState(pOVERLAP);
 
-                Debug.Assert(awaitable._continuation != s_sentinel, "Sentinel must not have already been set as the continuation");
+                Debug.Assert(!ReferenceEquals(awaitable._continuation, s_sentinel), "Sentinel must not have already been set as the continuation");
                 awaitable._errorCode = errorCode;
                 awaitable._numBytes = numBytes;
 
@@ -1617,15 +1617,15 @@ namespace System.IO
             }
 
             public AsyncCopyToAwaitable GetAwaiter() => this;
-            public bool IsCompleted => _continuation == s_sentinel;
+            public bool IsCompleted => ReferenceEquals(_continuation, s_sentinel);
             public void GetResult() { }
             public void OnCompleted(Action continuation) => UnsafeOnCompleted(continuation);
             public void UnsafeOnCompleted(Action continuation)
             {
-                if (_continuation == s_sentinel ||
+                if (ReferenceEquals(_continuation, s_sentinel) ||
                     Interlocked.CompareExchange(ref _continuation, continuation, null) != null)
                 {
-                    Debug.Assert(_continuation == s_sentinel, $"Expected continuation set to s_sentinel, got ${_continuation}");
+                    Debug.Assert(ReferenceEquals(_continuation, s_sentinel), $"Expected continuation set to s_sentinel, got ${_continuation}");
                     Task.Run(continuation);
                 }
             }
index b3a8783..9feb287 100644 (file)
@@ -76,19 +76,23 @@ namespace System.IO
         // "\\server\share").
         public static string GetDirectoryName(string path)
         {
-            if (path != null)
+            if (string.IsNullOrWhiteSpace(path))
             {
-                PathInternal.CheckInvalidPathChars(path);
-                path = PathInternal.NormalizeDirectorySeparators(path);
-                int root = PathInternal.GetRootLength(path);
+                if (path == null) return null;
+                throw new ArgumentException(SR.Arg_PathIllegal, nameof(path));
+            }
 
-                int i = path.Length;
-                if (i > root)
-                {
-                    while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) ;
-                    return path.Substring(0, i);
-                }
+            PathInternal.CheckInvalidPathChars(path);
+            path = PathInternal.NormalizeDirectorySeparators(path);
+            int root = PathInternal.GetRootLength(path);
+
+            int i = path.Length;
+            if (i > root)
+            {
+                while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) ;
+                return path.Substring(0, i);
             }
+            
             return null;
         }
 
@@ -26,9 +26,6 @@ namespace System.IO
         private byte[] _array;
         private GCHandle _pinningHandle;
 
-        // The new inheritance model requires a Critical default ctor since base (UnmanagedMemoryStream) has one
-        private PinnedBufferMemoryStream() : base() { }
-
         internal PinnedBufferMemoryStream(byte[] array)
         {
             Debug.Assert(array != null, "Array can't be null");
@@ -42,7 +39,7 @@ namespace System.IO
             }
 
             _array = array;
-            _pinningHandle = new GCHandle(array, GCHandleType.Pinned);
+            _pinningHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
             // Now the byte[] is pinned for the lifetime of this instance.
             // But I also need to get a pointer to that block of memory...
             fixed (byte* ptr = &_array[0])
@@ -56,20 +53,11 @@ namespace System.IO
 
         protected override void Dispose(bool disposing)
         {
-            if (_isOpen)
+            if (_pinningHandle.IsAllocated)
             {
                 _pinningHandle.Free();
-                _isOpen = false;
-            }
-#if _DEBUG
-            // To help track down lifetime issues on checked builds, force 
-            //a full GC here.
-            if (disposing)
-            {
-                GC.Collect();
-                GC.WaitForPendingFinalizers();
             }
-#endif
+
             base.Dispose(disposing);
         }
     }
@@ -2,28 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-/*============================================================
-**
-**
-** 
-**
-** Purpose: Create a stream over unmanaged memory, mostly
-**          useful for memory-mapped files.
-**
-**
-===========================================================*/
-
-using System;
-using System.Runtime;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
-using System.Security;
 using System.Threading;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
 using System.Threading.Tasks;
 
-
 namespace System.IO
 {
     /*
@@ -47,45 +32,14 @@ namespace System.IO
      * call free, run a user-provided delegate to free the memory, etc.  
      * We'll suggest user write a subclass of UnmanagedMemoryStream that uses
      * a SafeHandle subclass to hold onto the memory.
-     * Check for problems when using this in the negative parts of a 
-     * process's address space.  We may need to use unsigned longs internally
-     * and change the overflow detection logic.
-     * 
-     * -----SECURITY MODEL AND SILVERLIGHT-----
-     * A few key notes about exposing UMS in silverlight:
-     * 1. No ctors are exposed to transparent code. This version of UMS only
-     * supports byte* (not SafeBuffer). Therefore, framework code can create
-     * a UMS and hand it to transparent code. Transparent code can use most
-     * operations on a UMS, but not operations that directly expose a 
-     * pointer.
-     * 
-     * 2. Scope of "unsafe" and non-CLS compliant operations reduced: The
-     * Whidbey version of this class has CLSCompliant(false) at the class 
-     * level and unsafe modifiers at the method level. These were reduced to 
-     * only where the unsafe operation is performed -- i.e. immediately 
-     * around the pointer manipulation. Note that this brings UMS in line 
-     * with recent changes in pu/clr to support SafeBuffer.
      * 
-     * 3. Currently, the only caller that creates a UMS is ResourceManager, 
-     * which creates read-only UMSs, and therefore operations that can 
-     * change the length will throw because write isn't supported. A 
-     * conservative option would be to formalize the concept that _only_
-     * read-only UMSs can be creates, and enforce this by making WriteX and
-     * SetLength SecurityCritical. However, this is a violation of 
-     * security inheritance rules, so we must keep these safe. The 
-     * following notes make this acceptable for future use.
-     *    a. a race condition in WriteX that could have allowed a thread to 
-     *    read from unzeroed memory was fixed
-     *    b. memory region cannot be expanded beyond _capacity; in other 
-     *    words, a UMS creator is saying a writable UMS is safe to 
-     *    write to anywhere in the memory range up to _capacity, specified
-     *    in the ctor. Even if the caller doesn't specify a capacity, then
-     *    length is used as the capacity.
      */
+
+    /// <summary>
+    /// Stream over a memory pointer or over a SafeBuffer
+    /// </summary>
     public class UnmanagedMemoryStream : Stream
     {
-        private const long UnmanagedMemStreamMaxLength = Int64.MaxValue;
-
         private SafeBuffer _buffer;
         private unsafe byte* _mem;
         private long _length;
@@ -93,11 +47,12 @@ namespace System.IO
         private long _position;
         private long _offset;
         private FileAccess _access;
-        internal bool _isOpen;
-        [NonSerialized]
+        private bool _isOpen;
         private Task<Int32> _lastReadTask; // The last successful task returned from ReadAsync 
 
-
+        /// <summary>
+        /// Creates a closed stream.
+        /// </summary>
         // Needed for subclasses that need to map a file, etc.
         protected UnmanagedMemoryStream()
         {
@@ -108,16 +63,32 @@ namespace System.IO
             _isOpen = false;
         }
 
+        /// <summary>
+        /// Creates a stream over a SafeBuffer.
+        /// </summary>
+        /// <param name="buffer"></param>
+        /// <param name="offset"></param>
+        /// <param name="length"></param>
         public UnmanagedMemoryStream(SafeBuffer buffer, long offset, long length)
         {
             Initialize(buffer, offset, length, FileAccess.Read);
         }
 
+        /// <summary>
+        /// Creates a stream over a SafeBuffer.
+        /// </summary>
         public UnmanagedMemoryStream(SafeBuffer buffer, long offset, long length, FileAccess access)
         {
             Initialize(buffer, offset, length, access);
         }
 
+        /// <summary>
+        /// Subclasses must call this method (or the other overload) to properly initialize all instance fields.
+        /// </summary>
+        /// <param name="buffer"></param>
+        /// <param name="offset"></param>
+        /// <param name="length"></param>
+        /// <param name="access"></param>
         protected void Initialize(SafeBuffer buffer, long offset, long length, FileAccess access)
         {
             if (buffer == null)
@@ -177,18 +148,27 @@ namespace System.IO
             _isOpen = true;
         }
 
+        /// <summary>
+        /// Creates a stream over a byte*.
+        /// </summary>
         [CLSCompliant(false)]
         public unsafe UnmanagedMemoryStream(byte* pointer, long length)
         {
             Initialize(pointer, length, length, FileAccess.Read);
         }
 
+        /// <summary>
+        /// Creates a stream over a byte*.
+        /// </summary>
         [CLSCompliant(false)]
         public unsafe UnmanagedMemoryStream(byte* pointer, long length, long capacity, FileAccess access)
         {
             Initialize(pointer, length, capacity, access);
         }
 
+        /// <summary>
+        /// Subclasses must call this method (or the other overload) to properly initialize all instance fields.
+        /// </summary>
         [CLSCompliant(false)]
         protected unsafe void Initialize(byte* pointer, long length, long capacity, FileAccess access)
         {
@@ -215,24 +195,37 @@ namespace System.IO
             _isOpen = true;
         }
 
+        /// <summary>
+        /// Returns true if the stream can be read; otherwise returns false.
+        /// </summary>
         public override bool CanRead
         {
             [Pure]
             get { return _isOpen && (_access & FileAccess.Read) != 0; }
         }
 
+        /// <summary>
+        /// Returns true if the stream can seek; otherwise returns false.
+        /// </summary>
         public override bool CanSeek
         {
             [Pure]
             get { return _isOpen; }
         }
 
+        /// <summary>
+        /// Returns true if the stream can be written to; otherwise returns false.
+        /// </summary>
         public override bool CanWrite
         {
             [Pure]
             get { return _isOpen && (_access & FileAccess.Write) != 0; }
         }
 
+        /// <summary>
+        /// Closes the stream. The stream's memory needs to be dealt with separately.
+        /// </summary>
+        /// <param name="disposing"></param>
         protected override void Dispose(bool disposing)
         {
             _isOpen = false;
@@ -244,11 +237,19 @@ namespace System.IO
             base.Dispose(disposing);
         }
 
+        /// <summary>
+        /// Since it's a memory stream, this method does nothing.
+        /// </summary>
         public override void Flush()
         {
-            if (!_isOpen) __Error.StreamIsClosed();
+            if (!_isOpen) throw Error.GetStreamIsClosed();
         }
 
+        /// <summary>
+        /// Since it's a memory stream, this method does nothing specific.
+        /// </summary>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
         public override Task FlushAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -265,98 +266,92 @@ namespace System.IO
             }
         }
 
-
+        /// <summary>
+        /// Number of bytes in the stream.
+        /// </summary>
         public override long Length
         {
             get
             {
-                if (!_isOpen) __Error.StreamIsClosed();
+                if (!_isOpen) throw Error.GetStreamIsClosed();
                 return Interlocked.Read(ref _length);
             }
         }
 
+        /// <summary>
+        /// Number of bytes that can be written to the stream.
+        /// </summary>
         public long Capacity
         {
             get
             {
-                if (!_isOpen) __Error.StreamIsClosed();
+                if (!_isOpen) throw Error.GetStreamIsClosed();
                 return _capacity;
             }
         }
 
+        /// <summary>
+        /// ReadByte will read byte at the Position in the stream
+        /// </summary>
         public override long Position
         {
             get
             {
-                if (!CanSeek) __Error.StreamIsClosed();
+                if (!CanSeek) throw Error.GetStreamIsClosed();
                 Contract.EndContractBlock();
                 return Interlocked.Read(ref _position);
             }
             set
             {
-                if (value < 0)
-                    throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_NeedNonNegNum);
+                if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_NeedNonNegNum);
+                if (!CanSeek) throw Error.GetStreamIsClosed();
                 Contract.EndContractBlock();
-                if (!CanSeek) __Error.StreamIsClosed();
 
-#if !BIT64
-                unsafe {
-                    // On 32 bit machines, ensure we don't wrap around.
-                    if (value > (long) Int32.MaxValue || _mem + value < _mem)
-                        throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_StreamLength);
-                }
-#endif
                 Interlocked.Exchange(ref _position, value);
             }
         }
 
+        /// <summary>
+        /// Pointer to memory at the current Position in the stream. 
+        /// </summary>
         [CLSCompliant(false)]
         public unsafe byte* PositionPointer
         {
             get
             {
-                if (_buffer != null)
-                {
-                    throw new NotSupportedException(SR.NotSupported_UmsSafeBuffer);
-                }
+                if (_buffer != null) throw new NotSupportedException(SR.NotSupported_UmsSafeBuffer);
+                if (!_isOpen) throw Error.GetStreamIsClosed();
 
                 // Use a temp to avoid a race
                 long pos = Interlocked.Read(ref _position);
                 if (pos > _capacity)
                     throw new IndexOutOfRangeException(SR.IndexOutOfRange_UMSPosition);
                 byte* ptr = _mem + pos;
-                if (!_isOpen) __Error.StreamIsClosed();
                 return ptr;
             }
             set
             {
-                if (_buffer != null)
-                    throw new NotSupportedException(SR.NotSupported_UmsSafeBuffer);
-                if (!_isOpen) __Error.StreamIsClosed();
+                if (_buffer != null) throw new NotSupportedException(SR.NotSupported_UmsSafeBuffer);
+                if (!_isOpen) throw Error.GetStreamIsClosed();
 
-                // Note: subtracting pointers returns an Int64.  Working around
-                // to avoid hitting compiler warning CS0652 on this line. 
-                if (new IntPtr(value - _mem).ToInt64() > UnmanagedMemStreamMaxLength)
-                    throw new ArgumentOutOfRangeException("offset", SR.ArgumentOutOfRange_UnmanagedMemStreamLength);
                 if (value < _mem)
                     throw new IOException(SR.IO_SeekBeforeBegin);
+                long newPosition = (long)value - (long)_mem;
+                if (newPosition < 0)
+                    throw new ArgumentOutOfRangeException("offset", SR.ArgumentOutOfRange_UnmanagedMemStreamLength);
 
-                Interlocked.Exchange(ref _position, value - _mem);
-            }
-        }
-
-        internal unsafe byte* Pointer
-        {
-            get
-            {
-                if (_buffer != null)
-                    throw new NotSupportedException(SR.NotSupported_UmsSafeBuffer);
-
-                return _mem;
+                Interlocked.Exchange(ref _position, newPosition);
             }
         }
 
-        public override int Read([In, Out] byte[] buffer, int offset, int count)
+        /// <summary>
+        /// Reads bytes from stream and puts them into the buffer
+        /// </summary>
+        /// <param name="buffer">Buffer to read the bytes to.</param>
+        /// <param name="offset">Starting index in the buffer.</param>
+        /// <param name="count">Maximum number of bytes to read.</param>
+        /// <returns>Number of bytes actually read.</returns>
+        public override int Read(byte[] buffer, int offset, int count)
         {
             if (buffer == null)
                 throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer);
@@ -368,8 +363,8 @@ namespace System.IO
                 throw new ArgumentException(SR.Argument_InvalidOffLen);
             Contract.EndContractBlock();  // Keep this in sync with contract validation in ReadAsync
 
-            if (!_isOpen) __Error.StreamIsClosed();
-            if (!CanRead) __Error.ReadNotSupported();
+            if (!_isOpen) throw Error.GetStreamIsClosed();
+            if (!CanRead) throw Error.GetReadNotSupported();
 
             // Use a local variable to avoid a race where another thread 
             // changes our position after we decide we can read some bytes.
@@ -418,6 +413,14 @@ namespace System.IO
             return nInt;
         }
 
+        /// <summary>
+        /// Reads bytes from stream and puts them into the buffer
+        /// </summary>
+        /// <param name="buffer">Buffer to read the bytes to.</param>
+        /// <param name="offset">Starting index in the buffer.</param>
+        /// <param name="count">Maximum number of bytes to read.</param>       
+        /// <param name="cancellationToken">Token that can be used to cancel this operation.</param>
+        /// <returns>Task that can be used to access the number of bytes actually read.</returns>
         public override Task<Int32> ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
         {
             if (buffer == null)
@@ -446,10 +449,14 @@ namespace System.IO
             }
         }
 
+        /// <summary>
+        /// Returns the byte at the stream current Position and advances the Position.
+        /// </summary>
+        /// <returns></returns>
         public override int ReadByte()
         {
-            if (!_isOpen) __Error.StreamIsClosed();
-            if (!CanRead) __Error.ReadNotSupported();
+            if (!_isOpen) throw Error.GetStreamIsClosed();
+            if (!CanRead) throw Error.GetReadNotSupported();
 
             long pos = Interlocked.Read(ref _position);  // Use a local to avoid a race condition
             long len = Interlocked.Read(ref _length);
@@ -487,11 +494,15 @@ namespace System.IO
             return result;
         }
 
+        /// <summary>
+        /// Advanced the Position to specific location in the stream.
+        /// </summary>
+        /// <param name="offset">Offset from the loc parameter.</param>
+        /// <param name="loc">Origin for the offset parameter.</param>
+        /// <returns></returns>
         public override long Seek(long offset, SeekOrigin loc)
         {
-            if (!_isOpen) __Error.StreamIsClosed();
-            if (offset > UnmanagedMemStreamMaxLength)
-                throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_UnmanagedMemStreamLength);
+            if (!_isOpen) throw Error.GetStreamIsClosed();
             switch (loc)
             {
                 case SeekOrigin.Begin:
@@ -523,15 +534,19 @@ namespace System.IO
             return finalPos;
         }
 
+        /// <summary>
+        /// Sets the Length of the stream.
+        /// </summary>
+        /// <param name="value"></param>
         public override void SetLength(long value)
         {
             if (value < 0)
-                throw new ArgumentOutOfRangeException("length", SR.ArgumentOutOfRange_NeedNonNegNum);
+                throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_NeedNonNegNum);
             Contract.EndContractBlock();
             if (_buffer != null)
                 throw new NotSupportedException(SR.NotSupported_UmsSafeBuffer);
-            if (!_isOpen) __Error.StreamIsClosed();
-            if (!CanWrite) __Error.WriteNotSupported();
+            if (!_isOpen) throw Error.GetStreamIsClosed();
+            if (!CanWrite) throw Error.GetWriteNotSupported();
 
             if (value > _capacity)
                 throw new IOException(SR.IO_FixedCapacity);
@@ -552,6 +567,12 @@ namespace System.IO
             }
         }
 
+        /// <summary>
+        /// Writes buffer into the stream
+        /// </summary>
+        /// <param name="buffer">Buffer that will be written.</param>
+        /// <param name="offset">Starting index in the buffer.</param>
+        /// <param name="count">Number of bytes to write.</param>
         public override void Write(byte[] buffer, int offset, int count)
         {
             if (buffer == null)
@@ -564,8 +585,8 @@ namespace System.IO
                 throw new ArgumentException(SR.Argument_InvalidOffLen);
             Contract.EndContractBlock();  // Keep contract validation in sync with WriteAsync(..)
 
-            if (!_isOpen) __Error.StreamIsClosed();
-            if (!CanWrite) __Error.WriteNotSupported();
+            if (!_isOpen) throw Error.GetStreamIsClosed();
+            if (!CanWrite) throw Error.GetWriteNotSupported();
 
             long pos = Interlocked.Read(ref _position);  // Use a local to avoid a race condition
             long len = Interlocked.Read(ref _length);
@@ -635,6 +656,14 @@ namespace System.IO
             return;
         }
 
+        /// <summary>
+        /// Writes buffer into the stream. The operation completes synchronously.
+        /// </summary>
+        /// <param name="buffer">Buffer that will be written.</param>
+        /// <param name="offset">Starting index in the buffer.</param>
+        /// <param name="count">Number of bytes to write.</param>
+        /// <param name="cancellationToken">Token that can be used to cancel the operation.</param>
+        /// <returns>Task that can be awaited </returns>
         public override Task WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
         {
             if (buffer == null)
@@ -658,15 +687,18 @@ namespace System.IO
             catch (Exception ex)
             {
                 Debug.Assert(!(ex is OperationCanceledException));
-                return Task.FromException<Int32>(ex);
+                return Task.FromException(ex);
             }
         }
 
-
+        /// <summary>
+        /// Writes a byte to the stream and advances the current Position.
+        /// </summary>
+        /// <param name="value"></param>
         public override void WriteByte(byte value)
         {
-            if (!_isOpen) __Error.StreamIsClosed();
-            if (!CanWrite) __Error.WriteNotSupported();
+            if (!_isOpen) throw Error.GetStreamIsClosed();
+            if (!CanWrite) throw Error.GetWriteNotSupported();
 
             long pos = Interlocked.Read(ref _position);  // Use a local to avoid a race condition
             long len = Interlocked.Read(ref _length);
@@ -34,19 +34,16 @@ namespace System.IO
 
         public override bool CanRead
         {
-            [Pure]
             get { return _unmanagedStream.CanRead; }
         }
 
         public override bool CanSeek
         {
-            [Pure]
             get { return _unmanagedStream.CanSeek; }
         }
 
         public override bool CanWrite
         {
-            [Pure]
             get { return _unmanagedStream.CanWrite; }
         }
 
@@ -55,7 +52,7 @@ namespace System.IO
             try
             {
                 if (disposing)
-                    _unmanagedStream.Close();
+                    _unmanagedStream.Dispose();
             }
             finally
             {
@@ -112,7 +109,7 @@ namespace System.IO
             }
         }
 
-        public override int Read([In, Out] byte[] buffer, int offset, int count)
+        public override int Read(byte[] buffer, int offset, int count)
         {
             return _unmanagedStream.Read(buffer, offset, count);
         }
@@ -129,11 +126,8 @@ namespace System.IO
 
         public unsafe override byte[] ToArray()
         {
-            if (!_unmanagedStream._isOpen) __Error.StreamIsClosed();
-            if (!_unmanagedStream.CanRead) __Error.ReadNotSupported();
-
             byte[] buffer = new byte[_unmanagedStream.Length];
-            Buffer.Memcpy(buffer, 0, _unmanagedStream.Pointer, 0, (int)_unmanagedStream.Length);
+            _unmanagedStream.Read(buffer, 0, (int)_unmanagedStream.Length);
             return buffer;
         }
 
@@ -154,9 +148,6 @@ namespace System.IO
                 throw new ArgumentNullException(nameof(stream), SR.ArgumentNull_Stream);
             Contract.EndContractBlock();
 
-            if (!_unmanagedStream._isOpen) __Error.StreamIsClosed();
-            if (!CanRead) __Error.ReadNotSupported();
-
             byte[] buffer = ToArray();
 
             stream.Write(buffer, 0, buffer.Length);
@@ -217,4 +208,3 @@ namespace System.IO
     }  // class UnmanagedMemoryStreamWrapper
 }  // namespace
 
-
index a214050..41d7541 100644 (file)
@@ -161,7 +161,12 @@ namespace System.Resources
     // into smaller chunks, each of size sqrt(n), would be substantially better for
     // resource files containing thousands of resources.
     // 
-    internal sealed class RuntimeResourceSet : ResourceSet, IEnumerable
+#if CORECLR
+    internal
+#else
+    public  // On CoreRT, this must be public because of need to whitelist past the ReflectionBlock.
+#endif
+    sealed class RuntimeResourceSet : ResourceSet, IEnumerable
     {
         internal const int Version = 2;            // File format version number
 
index 8145a95..94e990a 100644 (file)
@@ -93,7 +93,6 @@ namespace Microsoft.Win32
     using System.Security;
     using System.Text;
     using System.Configuration.Assemblies;
-    using System.Runtime.Remoting;
     using System.Runtime.InteropServices;
     using System.Threading;
     using Microsoft.Win32.SafeHandles;
index 34c6ea5..d11739b 100644 (file)
@@ -16,7 +16,6 @@ namespace System
 {
     using System;
     using System.Reflection;
-    using System.Runtime.Remoting;
     using System.Security;
     using CultureInfo = System.Globalization.CultureInfo;
     using Evidence = System.Security.Policy.Evidence;
@@ -113,47 +112,6 @@ namespace System
             return Activator.CreateInstance(type, false);
         }
 
-        /*
-         * Create an instance using the name of type and the assembly where it exists. This allows
-         * types to be created remotely without having to load the type locally.
-         */
-
-        [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
-        static public ObjectHandle CreateInstance(String assemblyName,
-                                                  String typeName)
-        {
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-            return CreateInstance(assemblyName,
-                                  typeName,
-                                  false,
-                                  Activator.ConstructorDefault,
-                                  null,
-                                  null,
-                                  null,
-                                  null,
-                                  null,
-                                  ref stackMark);
-        }
-
-        [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod                                                  
-        static public ObjectHandle CreateInstance(String assemblyName,
-                                                  String typeName,
-                                                  Object[] activationAttributes)
-
-        {
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-            return CreateInstance(assemblyName,
-                                  typeName,
-                                  false,
-                                  Activator.ConstructorDefault,
-                                  null,
-                                  null,
-                                  null,
-                                  activationAttributes,
-                                  null,
-                                  ref stackMark);
-        }
-
         [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
         static public Object CreateInstance(Type type, bool nonPublic)
         {
@@ -185,221 +143,5 @@ namespace System
             // Skip the CreateInstanceCheckThis call to avoid perf cost and to maintain compatibility with V2 (throwing the same exceptions).
             return (T)rt.CreateInstanceDefaultCtor(true /*publicOnly*/, true /*skipCheckThis*/, true /*fillCache*/, ref stackMark);
         }
-
-        static public ObjectHandle CreateInstanceFrom(String assemblyFile,
-                                                      String typeName)
-
-        {
-            return CreateInstanceFrom(assemblyFile, typeName, null);
-        }
-
-        static public ObjectHandle CreateInstanceFrom(String assemblyFile,
-                                                      String typeName,
-                                                      Object[] activationAttributes)
-
-        {
-            return CreateInstanceFrom(assemblyFile,
-                                      typeName,
-                                      false,
-                                      Activator.ConstructorDefault,
-                                      null,
-                                      null,
-                                      null,
-                                      activationAttributes);
-        }
-
-        [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
-        public static ObjectHandle CreateInstance(string assemblyName,
-                                                  string typeName,
-                                                  bool ignoreCase,
-                                                  BindingFlags bindingAttr,
-                                                  Binder binder,
-                                                  object[] args,
-                                                  CultureInfo culture,
-                                                  object[] activationAttributes)
-        {
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-            return CreateInstance(assemblyName,
-                                  typeName,
-                                  ignoreCase,
-                                  bindingAttr,
-                                  binder,
-                                  args,
-                                  culture,
-                                  activationAttributes,
-                                  null,
-                                  ref stackMark);
-        }
-
-        static internal ObjectHandle CreateInstance(String assemblyString,
-                                                    String typeName,
-                                                    bool ignoreCase,
-                                                    BindingFlags bindingAttr,
-                                                    Binder binder,
-                                                    Object[] args,
-                                                    CultureInfo culture,
-                                                    Object[] activationAttributes,
-                                                    Evidence securityInfo,
-                                                    ref StackCrawlMark stackMark)
-        {
-            Type type = null;
-            Assembly assembly = null;
-            if (assemblyString == null)
-            {
-                assembly = RuntimeAssembly.GetExecutingAssembly(ref stackMark);
-            }
-            else
-            {
-                RuntimeAssembly assemblyFromResolveEvent;
-                AssemblyName assemblyName = RuntimeAssembly.CreateAssemblyName(assemblyString, false /*forIntrospection*/, out assemblyFromResolveEvent);
-                if (assemblyFromResolveEvent != null)
-                {
-                    // Assembly was resolved via AssemblyResolve event
-                    assembly = assemblyFromResolveEvent;
-                }
-                else if (assemblyName.ContentType == AssemblyContentType.WindowsRuntime)
-                {
-                    // WinRT type - we have to use Type.GetType
-                    type = Type.GetType(typeName + ", " + assemblyString, true /*throwOnError*/, ignoreCase);
-                }
-                else
-                {
-                    // Classic managed type
-                    assembly = RuntimeAssembly.InternalLoadAssemblyName(
-                        assemblyName, securityInfo, null, ref stackMark,
-                        true /*thrownOnFileNotFound*/, false /*forIntrospection*/);
-                }
-            }
-
-            if (type == null)
-            {
-                // It's classic managed type (not WinRT type)
-                Log(assembly != null, "CreateInstance:: ", "Loaded " + assembly.FullName, "Failed to Load: " + assemblyString);
-                if (assembly == null) return null;
-
-                type = assembly.GetType(typeName, true /*throwOnError*/, ignoreCase);
-            }
-
-            Object o = Activator.CreateInstance(type,
-                                                bindingAttr,
-                                                binder,
-                                                args,
-                                                culture,
-                                                activationAttributes);
-
-            Log(o != null, "CreateInstance:: ", "Created Instance of class " + typeName, "Failed to create instance of class " + typeName);
-            if (o == null)
-                return null;
-            else
-            {
-                ObjectHandle Handle = new ObjectHandle(o);
-                return Handle;
-            }
-        }
-
-        public static ObjectHandle CreateInstanceFrom(string assemblyFile,
-                                                      string typeName,
-                                                      bool ignoreCase,
-                                                      BindingFlags bindingAttr,
-                                                      Binder binder,
-                                                      object[] args,
-                                                      CultureInfo culture,
-                                                      object[] activationAttributes)
-        {
-            return CreateInstanceFromInternal(assemblyFile,
-                                              typeName,
-                                              ignoreCase,
-                                              bindingAttr,
-                                              binder,
-                                              args,
-                                              culture,
-                                              activationAttributes,
-                                              null);
-        }
-
-        private static ObjectHandle CreateInstanceFromInternal(String assemblyFile,
-                                                               String typeName,
-                                                               bool ignoreCase,
-                                                               BindingFlags bindingAttr,
-                                                               Binder binder,
-                                                               Object[] args,
-                                                               CultureInfo culture,
-                                                               Object[] activationAttributes,
-                                                               Evidence securityInfo)
-        {
-#pragma warning disable 618
-            Assembly assembly = Assembly.LoadFrom(assemblyFile, securityInfo);
-#pragma warning restore 618
-            Type t = assembly.GetType(typeName, true, ignoreCase);
-
-            Object o = Activator.CreateInstance(t,
-                                                bindingAttr,
-                                                binder,
-                                                args,
-                                                culture,
-                                                activationAttributes);
-
-            Log(o != null, "CreateInstanceFrom:: ", "Created Instance of class " + typeName, "Failed to create instance of class " + typeName);
-            if (o == null)
-                return null;
-            else
-            {
-                ObjectHandle Handle = new ObjectHandle(o);
-                return Handle;
-            }
-        }
-
-        public static ObjectHandle CreateComInstanceFrom(String assemblyName,
-                                                         String typeName)
-        {
-            return CreateComInstanceFrom(assemblyName,
-                                         typeName,
-                                         null,
-                                         AssemblyHashAlgorithm.None);
-        }
-
-        public static ObjectHandle CreateComInstanceFrom(String assemblyName,
-                                                         String typeName,
-                                                         byte[] hashValue,
-                                                         AssemblyHashAlgorithm hashAlgorithm)
-        {
-            Assembly assembly = Assembly.LoadFrom(assemblyName, hashValue, hashAlgorithm);
-
-            Type t = assembly.GetType(typeName, true, false);
-
-            Object[] Attr = t.GetCustomAttributes(typeof(ComVisibleAttribute), false);
-            if (Attr.Length > 0)
-            {
-                if (((ComVisibleAttribute)Attr[0]).Value == false)
-                    throw new TypeLoadException(SR.Argument_TypeMustBeVisibleFromCom);
-            }
-
-            Log(assembly != null, "CreateInstance:: ", "Loaded " + assembly.FullName, "Failed to Load: " + assemblyName);
-
-            if (assembly == null) return null;
-
-
-            Object o = Activator.CreateInstance(t,
-                                                Activator.ConstructorDefault,
-                                                null,
-                                                null,
-                                                null,
-                                                null);
-
-            Log(o != null, "CreateInstance:: ", "Created Instance of class " + typeName, "Failed to create instance of class " + typeName);
-            if (o == null)
-                return null;
-            else
-            {
-                ObjectHandle Handle = new ObjectHandle(o);
-                return Handle;
-            }
-        }
-
-        [System.Diagnostics.Conditional("_DEBUG")]
-        private static void Log(bool test, string title, string success, string failure)
-        {
-        }
     }
 }
-
index 02a473c..edd53b2 100644 (file)
@@ -25,7 +25,6 @@ namespace System
     using System.Collections.Generic;
     using System.Threading;
     using System.Runtime.InteropServices;
-    using System.Runtime.Remoting;
     using System.Reflection.Emit;
     using CultureInfo = System.Globalization.CultureInfo;
     using System.IO;
@@ -258,18 +257,6 @@ namespace System
         private static extern APPX_FLAGS nGetAppXFlags();
 #endif
 
-        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
-        [SuppressUnmanagedCodeSecurity]
-        private static extern void GetAppDomainManagerType(AppDomainHandle domain,
-                                                           StringHandleOnStack retAssembly,
-                                                           StringHandleOnStack retType);
-
-        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
-        [SuppressUnmanagedCodeSecurity]
-        private static extern void SetAppDomainManagerType(AppDomainHandle domain,
-                                                           string assembly,
-                                                           string type);
-
         [SuppressUnmanagedCodeSecurity]
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         private static extern void SetSecurityHomogeneousFlag(AppDomainHandle domain,
@@ -328,54 +315,6 @@ namespace System
                 SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths, appLocalWinMD);
             }
 
-            string domainManagerAssembly;
-            string domainManagerType;
-            GetAppDomainManagerType(out domainManagerAssembly, out domainManagerType);
-
-            if (domainManagerAssembly != null && domainManagerType != null)
-            {
-                try
-                {
-                    _domainManager = CreateInstanceAndUnwrap(domainManagerAssembly, domainManagerType) as AppDomainManager;
-                }
-                catch (FileNotFoundException e)
-                {
-                    throw new TypeLoadException(SR.Argument_NoDomainManager, e);
-                }
-                catch (SecurityException e)
-                {
-                    throw new TypeLoadException(SR.Argument_NoDomainManager, e);
-                }
-                catch (TypeLoadException e)
-                {
-                    throw new TypeLoadException(SR.Argument_NoDomainManager, e);
-                }
-
-                if (_domainManager == null)
-                {
-                    throw new TypeLoadException(SR.Argument_NoDomainManager);
-                }
-
-                // If this domain was not created by a managed call to CreateDomain, then the AppDomainSetup
-                // will not have the correct values for the AppDomainManager set.
-                FusionStore.AppDomainManagerAssembly = domainManagerAssembly;
-                FusionStore.AppDomainManagerType = domainManagerType;
-
-                bool notifyFusion = _domainManager.GetType() != typeof(System.AppDomainManager) && !DisableFusionUpdatesFromADManager();
-
-
-
-                AppDomainSetup FusionStoreOld = null;
-                if (notifyFusion)
-                    FusionStoreOld = new AppDomainSetup(FusionStore, true);
-
-                // Initialize the AppDomainMAnager and register the instance with the native host if requested
-                _domainManager.InitializeNewDomain(FusionStore);
-
-                if (notifyFusion)
-                    SetupFusionStore(_FusionStore, FusionStoreOld); // Notify Fusion about the changes the user implementation of InitializeNewDomain may have made to the FusionStore object.
-            }
-
             InitializeCompatibilityFlags();
         }
 
@@ -485,34 +424,6 @@ namespace System
         }
 
         /// <summary>
-        ///     Get the name of the assembly and type that act as the AppDomainManager for this domain
-        /// </summary>
-        internal void GetAppDomainManagerType(out string assembly, out string type)
-        {
-            // We can't just use our parameters because we need to ensure that the strings used for hte QCall
-            // are on the stack.
-            string localAssembly = null;
-            string localType = null;
-
-            GetAppDomainManagerType(GetNativeHandle(),
-                                    JitHelpers.GetStringHandleOnStack(ref localAssembly),
-                                    JitHelpers.GetStringHandleOnStack(ref localType));
-
-            assembly = localAssembly;
-            type = localType;
-        }
-
-        /// <summary>
-        ///     Set the assembly and type which act as the AppDomainManager for this domain
-        /// </summary>
-        private void SetAppDomainManagerType(string assembly, string type)
-        {
-            Debug.Assert(assembly != null, "assembly != null");
-            Debug.Assert(type != null, "type != null");
-            SetAppDomainManagerType(GetNativeHandle(), assembly, type);
-        }
-
-        /// <summary>
         ///     Called for every AppDomain (including the default domain) to initialize the security of the AppDomain)
         /// </summary>
         private void InitializeDomainSecurity(Evidence providedSecurityInfo,
@@ -584,23 +495,6 @@ namespace System
             }
         }
 
-
-        public ObjectHandle CreateInstance(String assemblyName,
-                                           String typeName)
-
-        {
-            // jit does not check for that, so we should do it ...
-            if (this == null)
-                throw new NullReferenceException();
-
-            if (assemblyName == null)
-                throw new ArgumentNullException(nameof(assemblyName));
-            Contract.EndContractBlock();
-
-            return Activator.CreateInstance(assemblyName,
-                                            typeName);
-        }
-
         public static AppDomain CurrentDomain
         {
             get
@@ -1158,12 +1052,6 @@ namespace System
             }
 #endif // FEATURE_COMINTEROP
 
-            // set up the AppDomainManager for this domain and initialize security.
-            if (adSetup.AppDomainManagerAssembly != null && adSetup.AppDomainManagerType != null)
-            {
-                ad.SetAppDomainManagerType(adSetup.AppDomainManagerAssembly, adSetup.AppDomainManagerType);
-            }
-
             ad.CreateAppDomainManager(); // could modify FusionStore's object
             ad.InitializeDomainSecurity(providedSecurityInfo,
                                         creatorsSecurityInfo,
@@ -1301,16 +1189,6 @@ namespace System
             }
         }
 
-        public Object CreateInstanceAndUnwrap(String assemblyName,
-                                              String typeName)
-        {
-            ObjectHandle oh = CreateInstance(assemblyName, typeName);
-            if (oh == null)
-                return null;
-
-            return oh.Unwrap();
-        } // CreateInstanceAndUnwrap
-
         public Int32 Id
         {
             get
index 67f7c9a..12a0d55 100644 (file)
@@ -15,7 +15,6 @@ namespace System
 {
     using System.IO;
     using System.Text;
-    using System.Runtime.Remoting;
     using System.Diagnostics;
     using Microsoft.Win32;
     using System.Runtime.CompilerServices;
diff --git a/src/mscorlib/src/System/Collections/ArrayList.cs b/src/mscorlib/src/System/Collections/ArrayList.cs
deleted file mode 100644 (file)
index cee7be7..0000000
+++ /dev/null
@@ -1,626 +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.
-
-/*============================================================
-**
-** 
-** 
-**
-**
-** Purpose: Implements a dynamically sized List as an array,
-**          and provides many convenience methods for treating
-**          an array as an IList.
-**
-** 
-===========================================================*/
-
-using System;
-using System.Runtime;
-using System.Security;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.Serialization;
-using System.Diagnostics.CodeAnalysis;
-using System.Diagnostics.Contracts;
-
-namespace System.Collections
-{
-    // Implements a variable-size List that uses an array of objects to store the
-    // elements. A ArrayList has a capacity, which is the allocated length
-    // of the internal array. As elements are added to a ArrayList, the capacity
-    // of the ArrayList is automatically increased as required by reallocating the
-    // internal array.
-    // 
-    [FriendAccessAllowed]
-    [DebuggerTypeProxy(typeof(System.Collections.ArrayList.ArrayListDebugView))]
-    [DebuggerDisplay("Count = {Count}")]
-    [Serializable]
-    internal class ArrayList : IList, ICloneable
-    {
-        private Object[] _items;
-        [ContractPublicPropertyName("Count")]
-        private int _size;
-        private int _version;
-        [NonSerialized]
-        private Object _syncRoot;
-
-        private const int _defaultCapacity = 4;
-        private static readonly Object[] emptyArray = Array.Empty<Object>();
-
-        // Constructs a ArrayList. The list is initially empty and has a capacity
-        // of zero. Upon adding the first element to the list the capacity is
-        // increased to _defaultCapacity, and then increased in multiples of two as required.
-        public ArrayList()
-        {
-            _items = emptyArray;
-        }
-
-        // Constructs a ArrayList with a given initial capacity. The list is
-        // initially empty, but will have room for the given number of elements
-        // before any reallocations are required.
-        // 
-        public ArrayList(int capacity)
-        {
-            if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), SR.Format(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(capacity)));
-            Contract.EndContractBlock();
-
-            if (capacity == 0)
-                _items = emptyArray;
-            else
-                _items = new Object[capacity];
-        }
-
-        // Constructs a ArrayList, copying the contents of the given collection. The
-        // size and capacity of the new list will both be equal to the size of the
-        // given collection.
-        // 
-        public ArrayList(ICollection c)
-        {
-            if (c == null)
-                throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection);
-            Contract.EndContractBlock();
-
-            int count = c.Count;
-            if (count == 0)
-            {
-                _items = emptyArray;
-            }
-            else
-            {
-                _items = new Object[count];
-                AddRange(c);
-            }
-        }
-
-        // Gets and sets the capacity of this list.  The capacity is the size of
-        // the internal array used to hold items.  When set, the internal 
-        // array of the list is reallocated to the given capacity.
-        // 
-        public virtual int Capacity
-        {
-            get
-            {
-                Contract.Ensures(Contract.Result<int>() >= Count);
-                return _items.Length;
-            }
-            set
-            {
-                if (value < _size)
-                {
-                    throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity);
-                }
-                Contract.Ensures(Capacity >= 0);
-                Contract.EndContractBlock();
-                // We don't want to update the version number when we change the capacity.
-                // Some existing applications have dependency on this.
-                if (value != _items.Length)
-                {
-                    if (value > 0)
-                    {
-                        Object[] newItems = new Object[value];
-                        if (_size > 0)
-                        {
-                            Array.Copy(_items, 0, newItems, 0, _size);
-                        }
-                        _items = newItems;
-                    }
-                    else
-                    {
-                        _items = new Object[_defaultCapacity];
-                    }
-                }
-            }
-        }
-
-        // Read-only property describing how many elements are in the List.
-        public virtual int Count
-        {
-            get
-            {
-                Contract.Ensures(Contract.Result<int>() >= 0);
-                return _size;
-            }
-        }
-
-        public virtual bool IsFixedSize
-        {
-            get { return false; }
-        }
-
-
-        // Is this ArrayList read-only?
-        public virtual bool IsReadOnly
-        {
-            get { return false; }
-        }
-
-        // Is this ArrayList synchronized (thread-safe)?
-        public virtual bool IsSynchronized
-        {
-            get { return false; }
-        }
-
-        // Synchronization root for this object.
-        public virtual Object SyncRoot
-        {
-            get
-            {
-                if (_syncRoot == null)
-                {
-                    System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);
-                }
-                return _syncRoot;
-            }
-        }
-
-        // Sets or Gets the element at the given index.
-        // 
-        public virtual Object this[int index]
-        {
-            get
-            {
-                if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
-                Contract.EndContractBlock();
-                return _items[index];
-            }
-            set
-            {
-                if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
-                Contract.EndContractBlock();
-                _items[index] = value;
-                _version++;
-            }
-        }
-
-        // Adds the given object to the end of this list. The size of the list is
-        // increased by one. If required, the capacity of the list is doubled
-        // before adding the new element.
-        //
-        public virtual int Add(Object value)
-        {
-            Contract.Ensures(Contract.Result<int>() >= 0);
-            if (_size == _items.Length) EnsureCapacity(_size + 1);
-            _items[_size] = value;
-            _version++;
-            return _size++;
-        }
-
-        // Adds the elements of the given collection to the end of this list. If
-        // required, the capacity of the list is increased to twice the previous
-        // capacity or the new size, whichever is larger.
-        //
-        public virtual void AddRange(ICollection c)
-        {
-            InsertRange(_size, c);
-        }
-
-
-        // Clears the contents of ArrayList.
-        public virtual void Clear()
-        {
-            if (_size > 0)
-            {
-                Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
-                _size = 0;
-            }
-            _version++;
-        }
-
-        // Clones this ArrayList, doing a shallow copy.  (A copy is made of all
-        // Object references in the ArrayList, but the Objects pointed to 
-        // are not cloned).
-        public virtual Object Clone()
-        {
-            Contract.Ensures(Contract.Result<Object>() != null);
-            ArrayList la = new ArrayList(_size);
-            la._size = _size;
-            la._version = _version;
-            Array.Copy(_items, 0, la._items, 0, _size);
-            return la;
-        }
-
-
-        // Contains returns true if the specified element is in the ArrayList.
-        // It does a linear, O(n) search.  Equality is determined by calling
-        // item.Equals().
-        //
-        public virtual bool Contains(Object item)
-        {
-            if (item == null)
-            {
-                for (int i = 0; i < _size; i++)
-                    if (_items[i] == null)
-                        return true;
-                return false;
-            }
-            else
-            {
-                for (int i = 0; i < _size; i++)
-                    if ((_items[i] != null) && (_items[i].Equals(item)))
-                        return true;
-                return false;
-            }
-        }
-
-        // Copies this ArrayList into array, which must be of a 
-        // compatible array type.  
-        //
-        public virtual void CopyTo(Array array, int arrayIndex)
-        {
-            if ((array != null) && (array.Rank != 1))
-                throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
-            Contract.EndContractBlock();
-            // Delegate rest of error checking to Array.Copy.
-            Array.Copy(_items, 0, array, arrayIndex, _size);
-        }
-
-        // Ensures that the capacity of this list is at least the given minimum
-        // value. If the currect capacity of the list is less than min, the
-        // capacity is increased to twice the current capacity or to min,
-        // whichever is larger.
-        private void EnsureCapacity(int min)
-        {
-            if (_items.Length < min)
-            {
-                int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2;
-                // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
-                // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
-                if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
-                if (newCapacity < min) newCapacity = min;
-                Capacity = newCapacity;
-            }
-        }
-
-        // Returns an enumerator for this list with the given
-        // permission for removal of elements. If modifications made to the list 
-        // while an enumeration is in progress, the MoveNext and 
-        // GetObject methods of the enumerator will throw an exception.
-        //
-        public virtual IEnumerator GetEnumerator()
-        {
-            Contract.Ensures(Contract.Result<IEnumerator>() != null);
-            return new ArrayListEnumeratorSimple(this);
-        }
-
-        // Returns the index of the first occurrence of a given value in a range of
-        // this list. The list is searched forwards from beginning to end.
-        // The elements of the list are compared to the given value using the
-        // Object.Equals method.
-        // 
-        // This method uses the Array.IndexOf method to perform the
-        // search.
-        // 
-        public virtual int IndexOf(Object value)
-        {
-            Contract.Ensures(Contract.Result<int>() < Count);
-            return Array.IndexOf((Array)_items, value, 0, _size);
-        }
-
-        // Inserts an element into this list at a given index. The size of the list
-        // is increased by one. If required, the capacity of the list is doubled
-        // before inserting the new element.
-        // 
-        public virtual void Insert(int index, Object value)
-        {
-            // Note that insertions at the end are legal.
-            if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_ArrayListInsert);
-            //Contract.Ensures(Count == Contract.OldValue(Count) + 1);
-            Contract.EndContractBlock();
-
-            if (_size == _items.Length) EnsureCapacity(_size + 1);
-            if (index < _size)
-            {
-                Array.Copy(_items, index, _items, index + 1, _size - index);
-            }
-            _items[index] = value;
-            _size++;
-            _version++;
-        }
-
-        // Inserts the elements of the given collection at a given index. If
-        // required, the capacity of the list is increased to twice the previous
-        // capacity or the new size, whichever is larger.  Ranges may be added
-        // to the end of the list by setting index to the ArrayList's size.
-        //
-        public virtual void InsertRange(int index, ICollection c)
-        {
-            if (c == null)
-                throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection);
-            if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
-            //Contract.Ensures(Count == Contract.OldValue(Count) + c.Count);
-            Contract.EndContractBlock();
-
-            int count = c.Count;
-            if (count > 0)
-            {
-                EnsureCapacity(_size + count);
-                // shift existing items
-                if (index < _size)
-                {
-                    Array.Copy(_items, index, _items, index + count, _size - index);
-                }
-
-                Object[] itemsToInsert = new Object[count];
-                c.CopyTo(itemsToInsert, 0);
-                itemsToInsert.CopyTo(_items, index);
-                _size += count;
-                _version++;
-            }
-        }
-
-        // Returns a read-only IList wrapper for the given IList.
-        //
-        [FriendAccessAllowed]
-        public static IList ReadOnly(IList list)
-        {
-            if (list == null)
-                throw new ArgumentNullException(nameof(list));
-            Contract.Ensures(Contract.Result<IList>() != null);
-            Contract.EndContractBlock();
-            return new ReadOnlyList(list);
-        }
-
-        // Removes the element at the given index. The size of the list is
-        // decreased by one.
-        // 
-        public virtual void Remove(Object obj)
-        {
-            Contract.Ensures(Count >= 0);
-
-            int index = IndexOf(obj);
-            BCLDebug.Correctness(index >= 0 || !(obj is Int32), "You passed an Int32 to Remove that wasn't in the ArrayList." + Environment.NewLine + "Did you mean RemoveAt?  int: " + obj + "  Count: " + Count);
-            if (index >= 0)
-                RemoveAt(index);
-        }
-
-        // Removes the element at the given index. The size of the list is
-        // decreased by one.
-        // 
-        public virtual void RemoveAt(int index)
-        {
-            if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
-            Contract.Ensures(Count >= 0);
-            //Contract.Ensures(Count == Contract.OldValue(Count) - 1);
-            Contract.EndContractBlock();
-
-            _size--;
-            if (index < _size)
-            {
-                Array.Copy(_items, index + 1, _items, index, _size - index);
-            }
-            _items[_size] = null;
-            _version++;
-        }
-
-        // ToArray returns a new array of a particular type containing the contents 
-        // of the ArrayList.  This requires copying the ArrayList and potentially
-        // downcasting all elements.  This copy may fail and is an O(n) operation.
-        // Internally, this implementation calls Array.Copy.
-        //
-        public virtual Array ToArray(Type type)
-        {
-            if (type == null)
-                throw new ArgumentNullException(nameof(type));
-            Contract.Ensures(Contract.Result<Array>() != null);
-            Contract.EndContractBlock();
-            Array array = Array.UnsafeCreateInstance(type, _size);
-            Array.Copy(_items, 0, array, 0, _size);
-            return array;
-        }
-
-        [Serializable]
-        private class ReadOnlyList : IList
-        {
-            private IList _list;
-
-            internal ReadOnlyList(IList l)
-            {
-                _list = l;
-            }
-
-            public virtual int Count
-            {
-                get { return _list.Count; }
-            }
-
-            public virtual bool IsReadOnly
-            {
-                get { return true; }
-            }
-
-            public virtual bool IsFixedSize
-            {
-                get { return true; }
-            }
-
-            public virtual bool IsSynchronized
-            {
-                get { return _list.IsSynchronized; }
-            }
-
-            public virtual Object this[int index]
-            {
-                get
-                {
-                    return _list[index];
-                }
-                set
-                {
-                    throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection);
-                }
-            }
-
-            public virtual Object SyncRoot
-            {
-                get { return _list.SyncRoot; }
-            }
-
-            public virtual int Add(Object obj)
-            {
-                throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection);
-            }
-
-            public virtual void Clear()
-            {
-                throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection);
-            }
-
-            public virtual bool Contains(Object obj)
-            {
-                return _list.Contains(obj);
-            }
-
-            public virtual void CopyTo(Array array, int index)
-            {
-                _list.CopyTo(array, index);
-            }
-
-            public virtual IEnumerator GetEnumerator()
-            {
-                return _list.GetEnumerator();
-            }
-
-            public virtual int IndexOf(Object value)
-            {
-                return _list.IndexOf(value);
-            }
-
-            public virtual void Insert(int index, Object obj)
-            {
-                throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection);
-            }
-
-            public virtual void Remove(Object value)
-            {
-                throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection);
-            }
-
-            public virtual void RemoveAt(int index)
-            {
-                throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection);
-            }
-        }
-
-        [Serializable]
-        private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable
-        {
-            private ArrayList list;
-            private int index;
-            private int version;
-            private Object currentElement;
-            [NonSerialized]
-            private bool isArrayList;
-            // this object is used to indicate enumeration has not started or has terminated
-            private static Object dummyObject = new Object();
-
-            internal ArrayListEnumeratorSimple(ArrayList list)
-            {
-                this.list = list;
-                index = -1;
-                version = list._version;
-                isArrayList = (list.GetType() == typeof(ArrayList));
-                currentElement = dummyObject;
-            }
-
-            public Object Clone()
-            {
-                return MemberwiseClone();
-            }
-
-            public bool MoveNext()
-            {
-                if (version != list._version)
-                {
-                    throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumFailedVersion));
-                }
-
-                if (isArrayList)
-                {  // avoid calling virtual methods if we are operating on ArrayList to improve performance
-                    if (index < list._size - 1)
-                    {
-                        currentElement = list._items[++index];
-                        return true;
-                    }
-                    else
-                    {
-                        currentElement = dummyObject;
-                        index = list._size;
-                        return false;
-                    }
-                }
-                else
-                {
-                    if (index < list.Count - 1)
-                    {
-                        currentElement = list[++index];
-                        return true;
-                    }
-                    else
-                    {
-                        index = list.Count;
-                        currentElement = dummyObject;
-                        return false;
-                    }
-                }
-            }
-
-            public Object Current
-            {
-                get
-                {
-                    object temp = currentElement;
-                    if (dummyObject == temp)
-                    { // check if enumeration has not started or has terminated
-                        if (index == -1)
-                        {
-                            throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumNotStarted));
-                        }
-                        else
-                        {
-                            throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumEnded));
-                        }
-                    }
-
-                    return temp;
-                }
-            }
-
-            public void Reset()
-            {
-                if (version != list._version)
-                {
-                    throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumFailedVersion));
-                }
-
-                currentElement = dummyObject;
-                index = -1;
-            }
-        }
-
-        internal class ArrayListDebugView
-        {
-            private ArrayList arrayList;
-        }
-    }
-}
index e360eef..c08e287 100644 (file)
 ** thread safety. If a reader writer lock is available, then that may be used
 ** with a Dictionary to get the same thread safety guarantee. 
 ** 
-** Reader writer locks don't exist in silverlight, so we do the following as a
-** result of removing non-generic collections from silverlight: 
-** 1. If the Hashtable was fully synchronized, then we replace it with a 
-**    Dictionary with full locks around reads/writes (same thread safety
-**    guarantee).
-** 2. Otherwise, the Hashtable has the default MR/SW thread safety behavior, 
-**    so we do one of the following on a case-by-case basis:
-**    a. If the race condition can be addressed by rearranging the code and using a temp
-**       variable (for example, it's only populated immediately after created)
-**       then we address the race condition this way and use Dictionary.
-**    b. If there's concern about degrading performance with the increased 
-**       locking, we ifdef with FEATURE_NONGENERIC_COLLECTIONS so we can at 
-**       least use Hashtable in the desktop build, but Dictionary with full 
-**       locks in silverlight builds. Note that this is heavier locking than 
-**       MR/SW, but this is the only option without rewriting (or adding back)
-**       the reader writer lock. 
-**    c. If there's no performance concern (e.g. debug-only code) we 
-**       consistently replace Hashtable with Dictionary plus full locks to 
-**       reduce complexity.
-**    d. Most of serialization is dead code in silverlight. Instead of updating
-**       those Hashtable occurences in serialization, we carved out references 
-**       to serialization such that this code doesn't need to build in 
-**       silverlight. 
 ===========================================================*/
 
 namespace System.Collections.Generic
@@ -706,22 +683,6 @@ namespace System.Collections.Generic
             value = default(TValue);
             return false;
         }
-
-        // Method similar to TryGetValue that returns the value instead of putting it in an out param.
-        public TValue GetValueOrDefault(TKey key) => GetValueOrDefault(key, default(TValue));
-
-        // Method similar to TryGetValue that returns the value instead of putting it in an out param. If the entry
-        // doesn't exist, returns the defaultValue instead.
-        public TValue GetValueOrDefault(TKey key, TValue defaultValue)
-        {
-            int i = FindEntry(key);
-            if (i >= 0)
-            {
-                return entries[i].value;
-            }
-            return defaultValue;
-        }
-
         public bool TryAdd(TKey key, TValue value) => TryInsert(key, value, InsertionBehavior.None);
 
         bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
index d7ad827..17e2dd9 100644 (file)
@@ -5,7 +5,6 @@
 
 using System;
 using System.Reflection;
-using System.Runtime.Remoting;
 using System.Runtime.Serialization;
 using System.Globalization;
 using System.Diagnostics.Contracts;
index 92df7e7..cda3c4e 100644 (file)
 // The Debugger class is a part of the System.Diagnostics package
 // and is used for communicating with a debugger.
 
-using System;
-using System.IO;
-using System.Collections;
-using System.Reflection;
 using System.Runtime.CompilerServices;
-using System.Security;
-using System.Runtime.Versioning;
 
 namespace System.Diagnostics
 {
-    // No data, does not need to be marked with the serializable attribute
-    public sealed class Debugger
+    public static class Debugger
     {
-        // This should have been a static class, but wasn't as of v3.5.  Clearly, this is
-        // broken.  We'll keep this in V4 for binary compat, but marked obsolete as error
-        // so migrated source code gets fixed.
-        [Obsolete("Do not create instances of the Debugger class.  Call the static methods directly on this type instead", true)]
-        public Debugger()
-        {
-            // Should not have been instantiable - here for binary compatibility in V4.
-        }
-
         // Break causes a breakpoint to be signalled to an attached debugger.  If no debugger
-        // is attached, the user is asked if he wants to attach a debugger. If yes, then the 
+        // is attached, the user is asked if he wants to attach a debugger. If yes, then the
         // debugger is launched.
-        [MethodImplAttribute(MethodImplOptions.NoInlining)]
-        public static void Break()
-        {
-            // Causing a break is now allowed.
-            BreakInternal();
-        }
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        public static void Break() => BreakInternal();
 
-        private static void BreakCanThrow()
-        {
-            BreakInternal();
-        }
+        // The VM depends on this private method.
+        private static void BreakCanThrow() => BreakInternal();
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void BreakInternal();
 
         // Launch launches & attaches a debugger to the process. If a debugger is already attached,
-        // nothing happens.  
+        // nothing happens.
         //
-        public static bool Launch()
-        {
-            if (Debugger.IsAttached)
-                return (true);
-
-            // Causing the debugger to launch is now allowed.
-            return (LaunchInternal());
-        }
+        public static bool Launch() => IsAttached ? true : LaunchInternal();
 
         // This class implements code:ICustomDebuggerNotification and provides a type to be used to notify
-        // the debugger that execution is about to enter a path that involves a cross-thread dependency. 
-        // See code:NotifyOfCrossThreadDependency for more details. 
-        private class CrossThreadDependencyNotification : ICustomDebuggerNotification
-        {
-            // constructor
-            public CrossThreadDependencyNotification()
-            {
-            }
-        }
-
-        // Do not inline the slow path 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)]
-        private static void NotifyOfCrossThreadDependencySlow()
-        {
-            CrossThreadDependencyNotification notification = new CrossThreadDependencyNotification();
-            CustomNotification(notification);
-        }
-
-        // Sends a notification to the debugger to indicate that execution is about to enter a path 
-        // involving a cross thread dependency. A debugger that has opted into this type of notification 
-        // can take appropriate action on receipt. For example, performing a funceval normally requires 
-        // freezing all threads but the one performing the funceval. If the funceval requires execution on 
-        // more than one thread, as might occur in remoting scenarios, the funceval will block. This 
-        // notification will apprise the debugger that it will need  to slip a thread or abort the funceval 
-        // in such a situation. The notification is subject to collection after this function returns. 
-        // 
+        // the debugger that execution is about to enter a path that involves a cross-thread dependency.
+        // See code:NotifyOfCrossThreadDependency for more details.
+        private class CrossThreadDependencyNotification : ICustomDebuggerNotification { }
+
+        // Do not inline the slow path
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private static void NotifyOfCrossThreadDependencySlow() =>
+            CustomNotification(new CrossThreadDependencyNotification());
+
+        // Sends a notification to the debugger to indicate that execution is about to enter a path
+        // involving a cross thread dependency. A debugger that has opted into this type of notification
+        // can take appropriate action on receipt. For example, performing a funceval normally requires
+        // freezing all threads but the one performing the funceval. If the funceval requires execution on
+        // more than one thread, as might occur in remoting scenarios, the funceval will block. This
+        // notification will apprise the debugger that it will need  to slip a thread or abort the funceval
+        // in such a situation. The notification is subject to collection after this function returns.
+        //
         public static void NotifyOfCrossThreadDependency()
         {
-            if (Debugger.IsAttached)
+            if (IsAttached)
             {
                 NotifyOfCrossThreadDependencySlow();
             }
         }
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern bool LaunchInternal();
 
         // Returns whether or not a debugger is attached to the process.
         //
         public static extern bool IsAttached
         {
-            [MethodImplAttribute(MethodImplOptions.InternalCall)]
+            [MethodImpl(MethodImplOptions.InternalCall)]
             get;
         }
 
@@ -108,26 +70,26 @@ namespace System.Diagnostics
         // An attached debugger can enable or disable which messages will
         // actually be reported to the user through the COM+ debugger
         // services API.  This info is communicated to the runtime so only
-        // desired events are actually reported to the debugger.  
+        // desired events are actually reported to the debugger.
         //
         // Constant representing the default category
-        public static readonly String DefaultCategory = null;
+        public static readonly string DefaultCategory = null;
 
         // Posts a message for the attached debugger.  If there is no
         // debugger attached, has no effect.  The debugger may or may not
-        // report the message depending on its settings. 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern void Log(int level, String category, String message);
+        // report the message depending on its settings.
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern void Log(int level, string category, string message);
 
         // Checks to see if an attached debugger has logging enabled
-        //  
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        //
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern bool IsLogging();
 
         // Posts a custom notification for the attached debugger.  If there is no
         // debugger attached, has no effect.  The debugger may or may not
-        // report the notification depending on its settings. 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        // report the notification depending on its settings.
+        [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void CustomNotification(ICustomDebuggerNotification data);
     }
 }
index b62ea49..9ec0cfc 100644 (file)
@@ -4,7 +4,6 @@
 
 namespace System.Diagnostics
 {
-    using System.Runtime.Remoting;
     using System;
     using System.IO;
     using System.Collections;
index 502e8df..7c4503e 100644 (file)
@@ -9,7 +9,6 @@
 using System.Diagnostics.Contracts;
 
 using System;
-using System.Runtime.Remoting;
 using System.Runtime.Serialization;
 
 namespace System
index dddbdc2..257deb2 100644 (file)
@@ -77,9 +77,6 @@ namespace System
             }
         }
 
-
-        private static volatile OperatingSystem m_os;  // Cached OperatingSystem value
-
         /*==================================TickCount===================================
         **Action: Gets the number of ticks since the system was started.
         **Returns: The number of ticks since the system was started.
index 51a2727..89de24d 100644 (file)
@@ -157,20 +157,9 @@ namespace System.Globalization
                 }
             }
 
-            GCHandle contextHandle = GCHandle.Alloc(data);
-            try
-            {
-                // Now call the enumeration API. Work is done by our callback function
-#if CORECLR
-                Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarsCallback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, (IntPtr)contextHandle);
-#else
-                IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, IntPtr, Interop.BOOL>>(EnumCalendarsCallback);
-                Interop.Kernel32.EnumCalendarInfoExEx(callback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, (IntPtr)contextHandle);
-#endif
-            }
-            finally
+            unsafe
             {
-                contextHandle.Free();
+                Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarsCallback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, Unsafe.AsPointer(ref data));
             }
 
             // Copy to the output array
@@ -300,15 +289,13 @@ namespace System.Globalization
         }
 
         // EnumCalendarInfoExEx callback itself.
-#if !CORECLR
-        [NativeCallable(CallingConvention = CallingConvention.StdCall)]
-#endif
-        private static unsafe Interop.BOOL EnumCalendarInfoCallback(IntPtr lpCalendarInfoString, uint calendar, IntPtr pReserved, IntPtr lParam)
+        // [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+        private static unsafe Interop.BOOL EnumCalendarInfoCallback(char* lpCalendarInfoString, uint calendar, IntPtr pReserved, void* lParam)
         {
-            EnumData context = (EnumData)((GCHandle)lParam).Target;
+            ref EnumData context = ref Unsafe.As<byte, EnumData>(ref *(byte*)lParam);
             try
             {
-                string calendarInfo = new string((char*)lpCalendarInfoString);
+                string calendarInfo = new string(lpCalendarInfoString);
 
                 // If we had a user override, check to make sure this differs
                 if (context.userOverride != calendarInfo)
@@ -343,7 +330,7 @@ namespace System.Globalization
                     string res = CultureData.GetLocaleInfoEx(localeName, lcType);
 
                     // if it succeeded remember the override for the later callers
-                    if (res != "")
+                    if (res != null)
                     {
                         // Remember this was the override (so we can look for duplicates later in the enum function)
                         context.userOverride = res;
@@ -354,20 +341,10 @@ namespace System.Globalization
                 }
             }
 
-            GCHandle contextHandle = GCHandle.Alloc(context);
-            try
+            unsafe
             {
-#if CORECLR
-                Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarInfoCallback, localeName, (uint)calendar, null, calType, (IntPtr)contextHandle);
-#else
                 // Now call the enumeration API. Work is done by our callback function
-                IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, IntPtr, Interop.BOOL>>(EnumCalendarInfoCallback);
-                Interop.Kernel32.EnumCalendarInfoExEx(callback, localeName, (uint)calendar, null, calType, (IntPtr)contextHandle);
-#endif // CORECLR
-            }
-            finally
-            {
-                contextHandle.Free();
+                Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarInfoCallback, localeName, (uint)calendar, null, calType, Unsafe.AsPointer(ref context));
             }
 
             // Now we have a list of data, fail if we didn't find anything.
@@ -464,12 +441,10 @@ namespace System.Globalization
             public IntList calendars;      // list of calendars found so far
         }
 
-#if !CORECLR
-        [NativeCallable(CallingConvention = CallingConvention.StdCall)]
-#endif
-        private static Interop.BOOL EnumCalendarsCallback(IntPtr lpCalendarInfoString, uint calendar, IntPtr reserved, IntPtr lParam)
+        // [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+        private static unsafe Interop.BOOL EnumCalendarsCallback(char* lpCalendarInfoString, uint calendar, IntPtr reserved, void* lParam)
         {
-            EnumCalendarsData context = (EnumCalendarsData)((GCHandle)lParam).Target;
+            ref EnumCalendarsData context = ref Unsafe.As<byte, EnumCalendarsData>(ref *(byte*)lParam);
             try
             {
                 // If we had a user override, check to make sure this differs
index 6d2678b..c39327e 100644 (file)
@@ -4,6 +4,7 @@
 
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Text;
 
@@ -179,7 +180,7 @@ namespace System.Globalization
                 return new String(pBuffer);
             }
 
-            return "";
+            return null;
         }
 
         internal static unsafe int GetLocaleInfoExInt(String localeName, uint field)
@@ -195,7 +196,7 @@ namespace System.Globalization
         {
             Debug.Assert(!GlobalizationMode.Invariant);
 
-            return Interop.Kernel32.GetLocaleInfoEx(lpLocaleName, lcType, (IntPtr)lpLCData, cchData);
+            return Interop.Kernel32.GetLocaleInfoEx(lpLocaleName, lcType, lpLCData, cchData);
         }
 
         private string GetLocaleInfo(LocaleStringData type)
@@ -284,19 +285,9 @@ namespace System.Globalization
             context.cultureName = null;
             context.regionName = regionName;
 
-            GCHandle contextHandle = GCHandle.Alloc(context);
-            try
+            unsafe
             {
-#if CORECLR
-                Interop.Kernel32.EnumSystemLocalesEx(EnumSystemLocalesProc, LOCALE_SPECIFICDATA | LOCALE_SUPPLEMENTAL, (IntPtr)contextHandle, IntPtr.Zero);
-#else
-                IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, Interop.BOOL>>(EnumSystemLocalesProc);
-                Interop.Kernel32.EnumSystemLocalesEx(callback, LOCALE_SPECIFICDATA | LOCALE_SUPPLEMENTAL, (IntPtr)contextHandle, IntPtr.Zero);
-#endif
-            }
-            finally
-            {
-                contextHandle.Free();
+                Interop.Kernel32.EnumSystemLocalesEx(EnumSystemLocalesProc, LOCALE_SPECIFICDATA | LOCALE_SUPPLEMENTAL, Unsafe.AsPointer(ref context), IntPtr.Zero);
             }
 
             if (context.cultureName != null)
@@ -543,15 +534,13 @@ namespace System.Globalization
         }
 
         // EnumSystemLocaleEx callback.
-#if !CORECLR
-        [NativeCallable(CallingConvention = CallingConvention.StdCall)]
-#endif
-        private static unsafe Interop.BOOL EnumSystemLocalesProc(IntPtr lpLocaleString, uint flags, IntPtr contextHandle)
+        // [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+        private static unsafe Interop.BOOL EnumSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle)
         {
-            EnumLocaleData context = (EnumLocaleData)((GCHandle)contextHandle).Target;
+            ref EnumLocaleData context = ref Unsafe.As<byte, EnumLocaleData>(ref *(byte*)contextHandle);
             try
             {
-                string cultureName = new string((char*)lpLocaleString);
+                string cultureName = new string(lpLocaleString);
                 string regionName = GetLocaleInfoEx(cultureName, LOCALE_SISO3166CTRYNAME);
                 if (regionName != null && regionName.Equals(context.regionName, StringComparison.OrdinalIgnoreCase))
                 {
@@ -568,15 +557,13 @@ namespace System.Globalization
         }
 
         // EnumSystemLocaleEx callback.
-#if !CORECLR
-        [NativeCallable(CallingConvention = CallingConvention.StdCall)]
-#endif
-        private static unsafe Interop.BOOL EnumAllSystemLocalesProc(IntPtr lpLocaleString, uint flags, IntPtr contextHandle)
+        // [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+        private static unsafe Interop.BOOL EnumAllSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle)
         {
-            EnumData context = (EnumData)((GCHandle)contextHandle).Target;
+            ref EnumData context = ref Unsafe.As<byte, EnumData>(ref *(byte*)contextHandle);
             try
             {
-                context.strings.Add(new string((char*)lpLocaleString));
+                context.strings.Add(new string(lpLocaleString));
                 return Interop.BOOL.TRUE;
             }
             catch (Exception)
@@ -592,16 +579,13 @@ namespace System.Globalization
         }
 
         // EnumTimeFormatsEx callback itself.
-#if !CORECLR
-        [NativeCallable(CallingConvention = CallingConvention.StdCall)]
-#endif
-        private static unsafe Interop.BOOL EnumTimeCallback(IntPtr lpTimeFormatString, IntPtr lParam)
+        // [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+        private static unsafe Interop.BOOL EnumTimeCallback(char* lpTimeFormatString, void* lParam)
         {
-            EnumData context = (EnumData)((GCHandle)lParam).Target;
-
+            ref EnumData context = ref Unsafe.As<byte, EnumData>(ref *(byte*)lParam);
             try
             {
-                context.strings.Add(new string((char*)lpTimeFormatString));
+                context.strings.Add(new string(lpTimeFormatString));
                 return Interop.BOOL.TRUE;
             }
             catch (Exception)
@@ -617,21 +601,9 @@ namespace System.Globalization
 
             EnumData data = new EnumData();
             data.strings = new StringList();
-            GCHandle dataHandle = GCHandle.Alloc(data);
-            try
-            {
-#if CORECLR
-                Interop.Kernel32.EnumTimeFormatsEx(EnumTimeCallback, localeName, (uint)dwFlags, (IntPtr)dataHandle);
-#else
-                // Now call the enumeration API. Work is done by our callback function
-                IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, IntPtr, Interop.BOOL>>(EnumTimeCallback);
-                Interop.Kernel32.EnumTimeFormatsEx(callback, localeName, (uint)dwFlags, (IntPtr)dataHandle);
-#endif
-            }
-            finally
-            {
-                dataHandle.Free();
-            }
+
+            // Now call the enumeration API. Work is done by our callback function
+            Interop.Kernel32.EnumTimeFormatsEx(EnumTimeCallback, localeName, (uint)dwFlags, Unsafe.AsPointer(ref data));
 
             if (data.strings.Count > 0)
             {
@@ -757,19 +729,10 @@ namespace System.Globalization
 
             EnumData context = new EnumData();
             context.strings = new StringList();
-            GCHandle contextHandle = GCHandle.Alloc(context);
-            try
-            {
-#if CORECLR
-                Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, flags, (IntPtr)contextHandle, IntPtr.Zero);
-#else
-                IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, Interop.BOOL>>(EnumAllSystemLocalesProc);
-                Interop.Kernel32.EnumSystemLocalesEx(callback, flags, (IntPtr)contextHandle, IntPtr.Zero);
-#endif
-            }
-            finally
+
+            unsafe
             {
-                contextHandle.Free();
+                Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, flags, Unsafe.AsPointer(ref context), IntPtr.Zero);
             }
 
             CultureInfo [] cultures = new CultureInfo[context.strings.Count];
@@ -802,19 +765,10 @@ namespace System.Globalization
             {
                 EnumData context = new EnumData();
                 context.strings = new StringList();
-                GCHandle contextHandle = GCHandle.Alloc(context);
-                try
-                {
-#if CORECLR
-                    Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, (IntPtr)contextHandle, IntPtr.Zero);
-#else
-                    IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, Interop.BOOL>>(EnumAllSystemLocalesProc);
-                    Interop.Kernel32.EnumSystemLocalesEx(callback, Interop.Kernel32.LOCALE_REPLACEMENT, (IntPtr)contextHandle, IntPtr.Zero);
-#endif
-                }
-                finally
+
+                unsafe
                 {
-                    contextHandle.Free();
+                    Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, Unsafe.AsPointer(ref context), IntPtr.Zero);
                 }
 
                 for (int i=0; i<context.strings.Count; i++)
index b049eaf..dedcab5 100644 (file)
@@ -3,7 +3,6 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Text;
-using System.Runtime.Remoting;
 using System;
 using System.Security;
 
index 70f8326..1af195e 100644 (file)
@@ -206,11 +206,5 @@ namespace System.IO
         {
             throw new NotSupportedException(SR.NotSupported_UnwritableStream);
         }
-
-        // From WinError.h
-        internal const int ERROR_FILE_NOT_FOUND = Win32Native.ERROR_FILE_NOT_FOUND;
-        internal const int ERROR_PATH_NOT_FOUND = Win32Native.ERROR_PATH_NOT_FOUND;
-        internal const int ERROR_ACCESS_DENIED = Win32Native.ERROR_ACCESS_DENIED;
-        internal const int ERROR_INVALID_PARAMETER = Win32Native.ERROR_INVALID_PARAMETER;
     }
 }
index 5668f9e..39f66a2 100644 (file)
@@ -11,7 +11,6 @@
 
 
 using System;
-using System.Runtime.Remoting;
 using System.Runtime.Serialization;
 using System.Runtime.CompilerServices;
 using System.Globalization;
index 51150e1..0b8342f 100644 (file)
@@ -13,7 +13,6 @@
 
 
 using System;
-using System.Runtime.Remoting;
 using System.Runtime.Serialization;
 using System.Runtime.CompilerServices;
 using System.Globalization;
diff --git a/src/mscorlib/src/System/OperatingSystem.cs b/src/mscorlib/src/System/OperatingSystem.cs
deleted file mode 100644 (file)
index 5eb1253..0000000
+++ /dev/null
@@ -1,154 +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.
-
-/*============================================================
-**
-**
-**
-** Purpose: 
-**
-**
-===========================================================*/
-
-using System.Runtime.Serialization;
-using System.Globalization;
-using System.Runtime.InteropServices;
-using System.Diagnostics.Contracts;
-
-namespace System
-{
-    [Serializable]
-    internal sealed class OperatingSystem : ICloneable, ISerializable
-    {
-        private Version _version;
-        private PlatformID _platform;
-        private string _servicePack;
-        private string _versionString;
-
-        private OperatingSystem()
-        {
-        }
-
-        internal OperatingSystem(PlatformID platform, Version version, string servicePack)
-        {
-            if (platform < PlatformID.Win32S || platform > PlatformID.MacOSX)
-            {
-                throw new ArgumentException(
-                    SR.Format(SR.Arg_EnumIllegalVal, (int)platform),
-                    nameof(platform));
-            }
-
-            if ((Object)version == null)
-                throw new ArgumentNullException(nameof(version));
-            Contract.EndContractBlock();
-
-            _platform = platform;
-            _version = (Version)version.Clone();
-            _servicePack = servicePack;
-        }
-
-        private OperatingSystem(SerializationInfo info, StreamingContext context)
-        {
-            SerializationInfoEnumerator enumerator = info.GetEnumerator();
-            while (enumerator.MoveNext())
-            {
-                switch (enumerator.Name)
-                {
-                    case "_version":
-                        _version = (Version)info.GetValue("_version", typeof(Version));
-                        break;
-                    case "_platform":
-                        _platform = (PlatformID)info.GetValue("_platform", typeof(PlatformID));
-                        break;
-                    case "_servicePack":
-                        _servicePack = info.GetString("_servicePack");
-                        break;
-                }
-            }
-
-            if (_version == null)
-            {
-                throw new SerializationException(SR.Format(SR.Serialization_MissField, "_version"));
-            }
-        }
-
-        public void GetObjectData(SerializationInfo info, StreamingContext context)
-        {
-            if (info == null)
-            {
-                throw new ArgumentNullException(nameof(info));
-            }
-            Contract.EndContractBlock();
-
-            info.AddValue("_version", _version);
-            info.AddValue("_platform", _platform);
-            info.AddValue("_servicePack", _servicePack);
-        }
-
-        public Version Version
-        {
-            get { return _version; }
-        }
-
-        public Object Clone()
-        {
-            return new OperatingSystem(_platform,
-                                       _version, _servicePack);
-        }
-
-        public override String ToString()
-        {
-            return VersionString;
-        }
-
-        public String VersionString
-        {
-            get
-            {
-                if (_versionString != null)
-                {
-                    return _versionString;
-                }
-
-                String os;
-                switch (_platform)
-                {
-                    case PlatformID.Win32NT:
-                        os = "Microsoft Windows NT ";
-                        break;
-                    case PlatformID.Win32Windows:
-                        if ((_version.Major > 4) ||
-                            ((_version.Major == 4) && (_version.Minor > 0)))
-                            os = "Microsoft Windows 98 ";
-                        else
-                            os = "Microsoft Windows 95 ";
-                        break;
-                    case PlatformID.Win32S:
-                        os = "Microsoft Win32S ";
-                        break;
-                    case PlatformID.WinCE:
-                        os = "Microsoft Windows CE ";
-                        break;
-                    case PlatformID.MacOSX:
-                        os = "Mac OS X ";
-                        break;
-                    default:
-                        os = "<unknown> ";
-                        break;
-                }
-
-                if (String.IsNullOrEmpty(_servicePack))
-                {
-                    _versionString = os + _version.ToString();
-                }
-                else
-                {
-                    _versionString = os + _version.ToString(3) + " " + _servicePack;
-                }
-
-                return _versionString;
-            }
-        }
-    }
-}
diff --git a/src/mscorlib/src/System/PlatformID.cs b/src/mscorlib/src/System/PlatformID.cs
deleted file mode 100644 (file)
index dfab217..0000000
+++ /dev/null
@@ -1,27 +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.
-
-/*============================================================
-**
-**
-**
-** Purpose: Defines IDs for supported platforms
-**
-**
-===========================================================*/
-
-namespace System
-{
-    [Serializable]
-    internal enum PlatformID
-    {
-        Win32S = 0,
-        Win32Windows = 1,
-        Win32NT = 2,
-        WinCE = 3,
-        Unix = 4,
-        Xbox = 5,
-        MacOSX = 6
-    }
-}
index cfb36e7..9d34b48 100644 (file)
@@ -87,26 +87,6 @@ namespace System.Reflection
             return AssemblyLoadContext.Default.LoadFromAssemblyPath(fullPath);
         }
 
-        // Evidence is protected in Assembly.Load()
-        [Obsolete("This method is obsolete and will be removed in a future release of the .NET Framework. Please use an overload of LoadFrom which does not take an Evidence parameter. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
-        [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
-        internal static Assembly LoadFrom(String assemblyFile,
-                                        Evidence securityEvidence)
-        {
-            Contract.Ensures(Contract.Result<Assembly>() != null);
-
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-
-            return RuntimeAssembly.InternalLoadFrom(
-                assemblyFile,
-                securityEvidence,
-                null, // hashValue
-                AssemblyHashAlgorithm.None,
-                false,// forIntrospection);
-                ref stackMark);
-        }
-
-        [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
         public static Assembly LoadFrom(String assemblyFile,
                                         byte[] hashValue,
                                         AssemblyHashAlgorithm hashAlgorithm)
index 96eb45f..0f0c052 100644 (file)
@@ -2040,7 +2040,7 @@ namespace System.Reflection
             count = 0;
 
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
-            if (!all && s_pca.GetValueOrDefault(caType) == null && !IsSecurityAttribute(caType))
+            if (!all && !s_pca.ContainsKey(caType) && !IsSecurityAttribute(caType))
                 return Array.Empty<Attribute>();
 
             List<Attribute> pcas = new List<Attribute>();
@@ -2078,7 +2078,7 @@ namespace System.Reflection
         internal static bool IsDefined(RuntimeType type, RuntimeType caType)
         {
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
-            if (!all && s_pca.GetValueOrDefault(caType) == null && !IsSecurityAttribute(caType))
+            if (!all && !s_pca.ContainsKey(caType) && !IsSecurityAttribute(caType))
                 return false;
 
             if (all || caType == (RuntimeType)typeof(SerializableAttribute))
@@ -2107,7 +2107,7 @@ namespace System.Reflection
             count = 0;
 
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
-            if (!all && s_pca.GetValueOrDefault(caType) == null && !IsSecurityAttribute(caType))
+            if (!all && !s_pca.ContainsKey(caType) && !IsSecurityAttribute(caType))
                 return Array.Empty<Attribute>();
 
             List<Attribute> pcas = new List<Attribute>();
@@ -2140,7 +2140,7 @@ namespace System.Reflection
         internal static bool IsDefined(RuntimeMethodInfo method, RuntimeType caType)
         {
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
-            if (!all && s_pca.GetValueOrDefault(caType) == null)
+            if (!all && !s_pca.ContainsKey(caType))
                 return false;
 
             if (all || caType == (RuntimeType)typeof(DllImportAttribute))
@@ -2170,7 +2170,7 @@ namespace System.Reflection
             count = 0;
 
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
-            if (!all && s_pca.GetValueOrDefault(caType) == null)
+            if (!all && !s_pca.ContainsKey(caType))
                 return null;
 
             Attribute[] pcas = new Attribute[s_pcasCount];
@@ -2201,7 +2201,7 @@ namespace System.Reflection
         internal static bool IsDefined(RuntimeParameterInfo parameter, RuntimeType caType)
         {
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
-            if (!all && s_pca.GetValueOrDefault(caType) == null)
+            if (!all && !s_pca.ContainsKey(caType))
                 return false;
 
 
@@ -2231,7 +2231,7 @@ namespace System.Reflection
 
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
 
-            if (!all && s_pca.GetValueOrDefault(caType) == null && !IsSecurityAttribute(caType))
+            if (!all && !s_pca.ContainsKey(caType) && !IsSecurityAttribute(caType))
                 return Array.Empty<Attribute>();
 
             List<Attribute> pcas = new List<Attribute>();
@@ -2283,7 +2283,7 @@ namespace System.Reflection
             count = 0;
 
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
-            if (!all && s_pca.GetValueOrDefault(caType) == null)
+            if (!all && !s_pca.ContainsKey(caType))
                 return null;
 
             Attribute[] pcas = new Attribute[s_pcasCount];
@@ -2309,7 +2309,7 @@ namespace System.Reflection
         internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType caType)
         {
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
-            if (!all && s_pca.GetValueOrDefault(caType) == null)
+            if (!all && !s_pca.ContainsKey(caType))
                 return false;
 
             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
@@ -2334,7 +2334,7 @@ namespace System.Reflection
 
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
 
-            if (!all && s_pca.GetValueOrDefault(caType) == null && !IsSecurityAttribute(caType))
+            if (!all && !s_pca.ContainsKey(caType) && !IsSecurityAttribute(caType))
                 return Array.Empty<Attribute>();
 
             List<Attribute> pcas = new List<Attribute>();
@@ -2357,7 +2357,7 @@ namespace System.Reflection
         {
             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
 
-            if (!all && s_pca.GetValueOrDefault(caType) == null)
+            if (!all && !s_pca.ContainsKey(caType))
                 return false;
 
             if (all || IsSecurityAttribute(caType))
index 4632525..cb2d156 100644 (file)
@@ -320,26 +320,6 @@ namespace System.Reflection
             return CustomAttributeData.GetCustomAttributesInternal(this);
         }
 
-        [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
-        internal static RuntimeAssembly InternalLoadFrom(String assemblyFile,
-                                                         Evidence securityEvidence,
-                                                         byte[] hashValue,
-                                                         AssemblyHashAlgorithm hashAlgorithm,
-                                                         bool forIntrospection,
-                                                         ref StackCrawlMark stackMark)
-        {
-            if (assemblyFile == null)
-                throw new ArgumentNullException(nameof(assemblyFile));
-
-            Contract.EndContractBlock();
-
-            AssemblyName an = new AssemblyName();
-            an.CodeBase = assemblyFile;
-            an.SetHashControl(hashValue, hashAlgorithm);
-            // The stack mark is used for MDA filtering
-            return InternalLoadAssemblyName(an, securityEvidence, null, ref stackMark, true /*thrownOnFileNotFound*/, forIntrospection);
-        }
-
         // Wrapper function to wrap the typical use of InternalLoad.
         internal static RuntimeAssembly InternalLoad(String assemblyString,
                                                      Evidence assemblySecurity,
index 6d0aa6f..b64f95b 100644 (file)
@@ -23,7 +23,6 @@ using System.Runtime.Serialization;
 using System.Runtime.CompilerServices;
 using System.Security;
 using System.Text;
-using System.Runtime.Remoting;
 using MdSigCallingConvention = System.Signature.MdSigCallingConvention;
 using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache;
 using System.Runtime.InteropServices;
@@ -1200,7 +1199,7 @@ namespace System
                         {
                             string name = eventInfo.Name;
 
-                            if (csEventInfos.GetValueOrDefault(name) != null)
+                            if (csEventInfos.ContainsKey(name))
                                 continue;
 
                             csEventInfos[name] = eventInfo;
@@ -1355,10 +1354,8 @@ namespace System
                             if (csPropertyInfos != null)
                             {
                                 string name = propertyInfo.Name;
-
-                                List<RuntimePropertyInfo> cache = csPropertyInfos.GetValueOrDefault(name);
-
-                                if (cache == null)
+                                List<RuntimePropertyInfo> cache;
+                                if (!csPropertyInfos.TryGetValue(name, out cache))
                                 {
                                     cache = new List<RuntimePropertyInfo>(1);
                                     csPropertyInfos[name] = cache;
index c050000..97365b0 100644 (file)
@@ -13,7 +13,6 @@
 
 using System;
 using System.Runtime.Serialization;
-using System.Runtime.Remoting;
 using System.Diagnostics.Contracts;
 
 namespace System.Runtime.CompilerServices
index 8198d9f..fe69f61 100644 (file)
@@ -99,7 +99,6 @@
 // code:ComEventsMethod.Invoke
 
 using System;
-using System.Runtime.Remoting;
 
 namespace System.Runtime.InteropServices
 {
index 97f1bc5..13eb953 100644 (file)
@@ -22,7 +22,6 @@ namespace System.Runtime.InteropServices
     using System.Security;
     using System.Text;
     using System.Threading;
-    using System.Runtime.Remoting;
     using System.Runtime.CompilerServices;
     using System.Globalization;
     using System.Runtime.ConstrainedExecution;
diff --git a/src/mscorlib/src/System/Runtime/Remoting/ObjectHandle.cs b/src/mscorlib/src/System/Runtime/Remoting/ObjectHandle.cs
deleted file mode 100644 (file)
index e76882d..0000000
+++ /dev/null
@@ -1,40 +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.
-
-/*============================================================
-**
-**
-**
-** ObjectHandle wraps object references. A Handle allows a 
-** marshal by value object to be returned through an 
-** indirection allowing the caller to control when the
-** object is loaded into their domain.
-**
-** 
-===========================================================*/
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace System.Runtime.Remoting
-{
-    public class ObjectHandle
-    {
-        private Object WrappedObject;
-
-        private ObjectHandle()
-        {
-        }
-
-        internal ObjectHandle(Object o)
-        {
-            WrappedObject = o;
-        }
-
-        internal Object Unwrap()
-        {
-            return WrappedObject;
-        }
-    }
-}
index 1813932..b49b372 100644 (file)
@@ -17,7 +17,6 @@ using System.Reflection;
 using System.Collections;
 using System.Collections.Generic;
 using System.Security;
-using System.Runtime.Remoting;
 using System.Runtime.CompilerServices;
 using System.Runtime.Versioning;
 using System.Threading;
index 7fc3ce2..8fb54c7 100644 (file)
@@ -15,7 +15,6 @@
 using System;
 using System.Collections.Generic;
 using System.Reflection;
-using System.Runtime.Remoting;
 using System.Globalization;
 using System.Diagnostics;
 using System.Diagnostics.Contracts;
index a6a04d9..5c37f25 100644 (file)
@@ -12,7 +12,6 @@
 =============================================================================*/
 
 using System.Threading;
-using System.Runtime.Remoting;
 using System.Security;
 using System.Runtime.CompilerServices;
 using System.Runtime.ConstrainedExecution;
index 1591234..5788051 100644 (file)
@@ -8,7 +8,6 @@ namespace System.Text
     using System.Collections;
     using System.Collections.Generic;
     using System.Runtime;
-    using System.Runtime.Remoting;
     using System.Runtime.Serialization;
     using System.Globalization;
     using System.Security;
index 3ace333..0df64a5 100644 (file)
@@ -17,7 +17,6 @@
 
 using System;
 using System.Runtime;
-using System.Runtime.Remoting;
 using System.Threading;
 using System.Runtime.CompilerServices;
 using System.Runtime.ConstrainedExecution;
index f3412d2..da4856e 100644 (file)
@@ -15,7 +15,6 @@
 namespace System.Threading
 {
     using System.Threading;
-    using System.Runtime.Remoting;
     using System;
     using System.Runtime.CompilerServices;
     using System.Runtime.InteropServices;
index 85e1da5..339ba08 100644 (file)
@@ -13,7 +13,6 @@
 
 using System;
 using System.Globalization;
-using System.Runtime.Remoting;
 using System.Runtime.Serialization;
 using System.Runtime.InteropServices;
 using System.Runtime.CompilerServices;
index 35c9a51..0f470d9 100644 (file)
@@ -2853,6 +2853,14 @@ PAL_GetSymbolModuleBase(void *symbol);
 PALIMPORT
 LPVOID
 PALAPI
+PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange(
+    IN LPCVOID lpBeginAddress,
+    IN LPCVOID lpEndAddress,
+    IN SIZE_T dwSize);
+
+PALIMPORT
+LPVOID
+PALAPI
 VirtualAlloc(
          IN LPVOID lpAddress,
          IN SIZE_T dwSize,
index 145c2c9..b8a9fe9 100644 (file)
@@ -93,10 +93,10 @@ elseif(PAL_CMAKE_PLATFORM_ARCH_I386)
   set(PAL_ARCH_SOURCES_DIR i386)
 endif()
 
-if(CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT CLR_CMAKE_PLATFORM_ALPINE_LINUX)
+if(PAL_CMAKE_PLATFORM_ARCH_AMD64 AND CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT CLR_CMAKE_PLATFORM_ALPINE_LINUX)
   # Currently the _xstate is not available on Alpine Linux
   add_definitions(-DXSTATE_SUPPORTED)
-endif(CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT CLR_CMAKE_PLATFORM_ALPINE_LINUX)
+endif(PAL_CMAKE_PLATFORM_ARCH_AMD64 AND CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT CLR_CMAKE_PLATFORM_ALPINE_LINUX)
 
 if(CLR_CMAKE_PLATFORM_ALPINE_LINUX)
   # Setting RLIMIT_NOFILE breaks debugging of coreclr on Alpine Linux for some reason
index 7f37f42..48677df 100644 (file)
@@ -66,6 +66,8 @@
 #cmakedefine HAVE_UNW_GET_ACCESSORS
 #cmakedefine01 HAVE_XSWDEV
 #cmakedefine01 HAVE_XSW_USAGE
+#cmakedefine01 HAVE_PUBLIC_XSTATE_STRUCT
+#cmakedefine01 HAVE_PR_SET_PTRACER
 
 #cmakedefine01 HAVE_STAT_TIMESPEC
 #cmakedefine01 HAVE_STAT_NSEC
index b5b98d5..d5c6577 100644 (file)
@@ -1022,6 +1022,25 @@ int main(int argc, char **argv)
     return 0;
 }" HAVE_XSW_USAGE)
 
+check_cxx_source_compiles("
+#include <signal.h>
+
+int main(int argc, char **argv)
+{
+    struct _xstate xstate;
+    struct _fpx_sw_bytes bytes;
+    return 0;
+}" HAVE_PUBLIC_XSTATE_STRUCT)
+
+check_cxx_source_compiles("
+#include <sys/prctl.h>
+
+int main(int argc, char **argv)
+{
+    int flag = (int)PR_SET_PTRACER;
+    return 0;
+}" HAVE_PR_SET_PTRACER)
+
 set(CMAKE_REQUIRED_LIBRARIES pthread)
 check_cxx_source_compiles("
 #include <errno.h>
index db6d695..2c86a03 100644 (file)
@@ -39,6 +39,16 @@ typedef ucontext_t native_context_t;
 #else   // HAVE_UCONTEXT_T
 #error Native context type is not known on this platform!
 #endif  // HAVE_UCONTEXT_T
+
+#if defined(XSTATE_SUPPORTED) && !HAVE_PUBLIC_XSTATE_STRUCT
+namespace asm_sigcontext
+{
+#include <asm/sigcontext.h>
+};
+using asm_sigcontext::_fpx_sw_bytes;
+using asm_sigcontext::_xstate;
+#endif // defined(XSTATE_SUPPORTED) && !HAVE_PUBLIC_XSTATE_STRUCT
+
 #else // !HAVE_MACH_EXCEPTIONS
 #include <mach/kern_return.h>
 #include <mach/mach_port.h>
index 31d225f..36eaf81 100644 (file)
@@ -60,7 +60,7 @@ enum VIRTUAL_CONSTANTS
     
     VIRTUAL_PAGE_SIZE       = 0x1000,
     VIRTUAL_PAGE_MASK       = VIRTUAL_PAGE_SIZE - 1,
-    BOUNDARY_64K    = 0xffff
+    VIRTUAL_64KB            = 0x10000
 };
 
 /*++
@@ -130,11 +130,22 @@ public:
         AllocateMemory
 
         This function attempts to allocate the requested amount of memory from its reserved virtual
-        address space. The function will return NULL if the allocation request cannot
+        address space. The function will return null if the allocation request cannot
         be satisfied by the memory that is currently available in the allocator.
     --*/
     void* AllocateMemory(SIZE_T allocationSize);
 
+    /*++
+    Function:
+        AllocateMemory
+
+        This function attempts to allocate the requested amount of memory from its reserved virtual
+        address space, if memory is available within the specified range. The function will return
+        null if the allocation request cannot satisfied by the memory that is currently available in
+        the allocator.
+    --*/
+    void *AllocateMemoryWithinRange(const void *beginAddress, const void *endAddress, SIZE_T allocationSize);
+
 private:
     /*++
     Function:
@@ -160,12 +171,13 @@ private:
     // that can be used to calculate an approximate location of the memory that
     // is in 2GB range from the coreclr library. In addition, having precise size of libcoreclr
     // is not necessary for the calculations.
-    const int32_t CoreClrLibrarySize = 100 * 1024 * 1024;
+    static const int32_t CoreClrLibrarySize = 100 * 1024 * 1024;
 
     // This constant represent the max size of the virtual memory that this allocator
     // will try to reserve during initialization. We want all JIT-ed code and the
     // entire libcoreclr to be located in a 2GB range.
-    const int32_t MaxExecutableMemorySize = 0x7FFF0000 - CoreClrLibrarySize;
+    static const int32_t MaxExecutableMemorySize = 0x7FFF0000;
+    static const int32_t MaxExecutableMemorySizeNearCoreClr = MaxExecutableMemorySize - CoreClrLibrarySize;
 
     // Start address of the reserved virtual address space
     void* m_startAddress;
index 5fdb6fd..f26293b 100644 (file)
@@ -2440,20 +2440,21 @@ void * MAPMapPEFile(HANDLE hFile)
     // We're going to start adding mappings to the mapping list, so take the critical section
     InternalEnterCriticalSection(pThread, &mapping_critsec);
 
-#if !defined(_AMD64_)
-    loadedBase = mmap((void*)preferredBase, virtualSize, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-#else // defined(_AMD64_)    
+#ifdef BIT64
     // First try to reserve virtual memory using ExecutableAllcator. This allows all PE images to be
     // near each other and close to the coreclr library which also allows the runtime to generate
-    // more efficient code (by avoiding usage of jump stubs).
-    loadedBase = ReserveMemoryFromExecutableAllocator(pThread, ALIGN_UP(virtualSize, GetVirtualPageSize()));
+    // more efficient code (by avoiding usage of jump stubs). Alignment to a 64 KB granularity should
+    // not be necessary (alignment to page size should be sufficient), but see
+    // ExecutableMemoryAllocator::AllocateMemory() for the reason why it is done.
+    loadedBase = ReserveMemoryFromExecutableAllocator(pThread, ALIGN_UP(virtualSize, VIRTUAL_64KB));
+#endif // BIT64
+
     if (loadedBase == NULL)
     {
         // MAC64 requires we pass MAP_SHARED (or MAP_PRIVATE) flags - otherwise, the call is failed.
         // Refer to mmap documentation at http://www.manpagez.com/man/2/mmap/ for details.
-        loadedBase = mmap((void*)preferredBase, virtualSize, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+        loadedBase = mmap(NULL, virtualSize, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
     }
-#endif // !defined(_AMD64_)
 
     if (MAP_FAILED == loadedBase)
     {
index 7e00843..41bd37c 100644 (file)
@@ -18,15 +18,19 @@ Abstract:
 
 --*/
 
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(VIRTUAL); // some headers have code with asserts, so do this first
+
 #include "pal/thread.hpp"
 #include "pal/cs.hpp"
 #include "pal/malloc.hpp"
 #include "pal/file.hpp"
 #include "pal/seh.hpp"
-#include "pal/dbgmsg.h"
 #include "pal/virtual.h"
 #include "pal/map.h"
 #include "pal/init.h"
+#include "pal/utils.h"
 #include "common.h"
 
 #include <sys/types.h>
@@ -43,8 +47,6 @@ Abstract:
 
 using namespace CorUnix;
 
-SET_DEFAULT_DEBUG_CHANNEL(VIRTUAL);
-
 CRITICAL_SECTION virtual_critsec;
 
 // The first node in our list of allocated blocks.
@@ -93,6 +95,7 @@ namespace VirtualMemoryLogging
         Decommit = 0x40,
         Release = 0x50,
         Reset = 0x60,
+        ReserveFromExecutableMemoryAllocatorWithinRange = 0x70
     };
 
     // Indicates that the attempted operation has failed
@@ -884,8 +887,13 @@ static LPVOID VIRTUALReserveMemory(
 
     // First, figure out where we're trying to reserve the memory and
     // how much we need. On most systems, requests to mmap must be
-    // page-aligned and at multiples of the page size.
-    StartBoundary = (UINT_PTR)lpAddress & ~BOUNDARY_64K;
+    // page-aligned and at multiples of the page size. Unlike on Windows, on
+    // Unix, the allocation granularity is the page size, so the memory size to
+    // reserve is not aligned to 64 KB. Nor should the start boundary need to
+    // to be aligned down to 64 KB, but it is expected that there are other
+    // components that rely on this alignment when providing a specific address
+    // (note that mmap itself does not make any such guarantees).
+    StartBoundary = (UINT_PTR)ALIGN_DOWN(lpAddress, VIRTUAL_64KB);
     /* Add the sizes, and round down to the nearest page boundary. */
     MemSize = ( ((UINT_PTR)lpAddress + dwSize + VIRTUAL_PAGE_MASK) & ~VIRTUAL_PAGE_MASK ) - 
                StartBoundary;
@@ -894,7 +902,14 @@ static LPVOID VIRTUALReserveMemory(
     // try to get memory from the executable memory allocator to satisfy the request.
     if (((flAllocationType & MEM_RESERVE_EXECUTABLE) != 0) && (lpAddress == NULL))
     {
-        pRetVal = g_executableMemoryAllocator.AllocateMemory(MemSize);
+        // Alignment to a 64 KB granularity should not be necessary (alignment to page size should be sufficient), but see
+        // ExecutableMemoryAllocator::AllocateMemory() for the reason why it is done
+        SIZE_T reservationSize = ALIGN_UP(MemSize, VIRTUAL_64KB);
+        pRetVal = g_executableMemoryAllocator.AllocateMemory(reservationSize);
+        if (pRetVal != nullptr)
+        {
+            MemSize = reservationSize;
+        }
     }
 
     if (pRetVal == NULL)
@@ -1227,6 +1242,72 @@ done:
 
 /*++
 Function:
+  PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange
+
+  This function attempts to allocate the requested amount of memory in the specified address range, from the executable memory
+  allocator. If unable to do so, the function returns nullptr and does not set the last error.
+
+  lpBeginAddress - Inclusive beginning of range
+  lpEndAddress - Exclusive end of range
+  dwSize - Number of bytes to allocate
+--*/
+LPVOID
+PALAPI
+PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange(
+    IN LPCVOID lpBeginAddress,
+    IN LPCVOID lpEndAddress,
+    IN SIZE_T dwSize)
+{
+#ifdef BIT64
+    PERF_ENTRY(PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange);
+    ENTRY(
+        "PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange(lpBeginAddress = %p, lpEndAddress = %p, dwSize = %Iu)\n",
+        lpBeginAddress,
+        lpEndAddress,
+        dwSize);
+
+    _ASSERTE(lpBeginAddress <= lpEndAddress);
+
+    // Alignment to a 64 KB granularity should not be necessary (alignment to page size should be sufficient), but see
+    // ExecutableMemoryAllocator::AllocateMemory() for the reason why it is done
+    SIZE_T reservationSize = ALIGN_UP(dwSize, VIRTUAL_64KB);
+
+    CPalThread *currentThread = InternalGetCurrentThread();
+    InternalEnterCriticalSection(currentThread, &virtual_critsec);
+
+    void *address = g_executableMemoryAllocator.AllocateMemoryWithinRange(lpBeginAddress, lpEndAddress, reservationSize);
+    if (address != nullptr)
+    {
+        _ASSERTE(IS_ALIGNED(address, VIRTUAL_PAGE_SIZE));
+        if (!VIRTUALStoreAllocationInfo((UINT_PTR)address, reservationSize, MEM_RESERVE | MEM_RESERVE_EXECUTABLE, PAGE_NOACCESS))
+        {
+            ASSERT("Unable to store the structure in the list.\n");
+            munmap(address, reservationSize);
+            address = nullptr;
+        }
+    }
+
+    LogVaOperation(
+        VirtualMemoryLogging::VirtualOperation::ReserveFromExecutableMemoryAllocatorWithinRange,
+        nullptr,
+        dwSize,
+        MEM_RESERVE | MEM_RESERVE_EXECUTABLE,
+        PAGE_NOACCESS,
+        address,
+        TRUE);
+
+    InternalLeaveCriticalSection(currentThread, &virtual_critsec);
+
+    LOGEXIT("PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange returning %p\n", address);
+    PERF_EXIT(PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange);
+    return address;
+#else // !BIT64
+    return nullptr;
+#endif // BIT64
+}
+
+/*++
+Function:
   VirtualAlloc
 
 Note:
@@ -1982,11 +2063,15 @@ Function :
 --*/
 void* ReserveMemoryFromExecutableAllocator(CPalThread* pThread, SIZE_T allocationSize)
 {
+#ifdef BIT64
     InternalEnterCriticalSection(pThread, &virtual_critsec);
     void* mem = g_executableMemoryAllocator.AllocateMemory(allocationSize);
     InternalLeaveCriticalSection(pThread, &virtual_critsec);
 
     return mem;
+#else // !BIT64
+    return nullptr;
+#endif // BIT64
 }
 
 /*++
@@ -2024,14 +2109,14 @@ Function:
 void ExecutableMemoryAllocator::TryReserveInitialMemory()
 {
     CPalThread* pthrCurrent = InternalGetCurrentThread();
-    int32_t sizeOfAllocation = MaxExecutableMemorySize;
-    int32_t startAddressIncrement;
-    UINT_PTR startAddress;
+    int32_t sizeOfAllocation = MaxExecutableMemorySizeNearCoreClr;
+    int32_t preferredStartAddressIncrement;
+    UINT_PTR preferredStartAddress;
     UINT_PTR coreclrLoadAddress;
     const int32_t MemoryProbingIncrement = 128 * 1024 * 1024;
 
     // Try to find and reserve an available region of virtual memory that is located
-    // within 2GB range (defined by the MaxExecutableMemorySize constant) from the
+    // within 2GB range (defined by the MaxExecutableMemorySizeNearCoreClr constant) from the
     // location of the coreclr library.
     // Potentially, as a possible future improvement, we can get precise information
     // about available memory ranges by parsing data from '/proc/self/maps'.
@@ -2045,40 +2130,69 @@ void ExecutableMemoryAllocator::TryReserveInitialMemory()
     // (thus avoiding reserving memory below 4GB; besides some operating systems do not allow that).
     // If libcoreclr is loaded at high addresses then try to reserve memory below its location.
     coreclrLoadAddress = (UINT_PTR)PAL_GetSymbolModuleBase((void*)VirtualAlloc);
-    if ((coreclrLoadAddress < 0xFFFFFFFF) || ((coreclrLoadAddress - MaxExecutableMemorySize) < 0xFFFFFFFF))
+    if ((coreclrLoadAddress < 0xFFFFFFFF) || ((coreclrLoadAddress - MaxExecutableMemorySizeNearCoreClr) < 0xFFFFFFFF))
     {
         // Try to allocate above the location of libcoreclr
-        startAddress = coreclrLoadAddress + CoreClrLibrarySize;
-        startAddressIncrement = MemoryProbingIncrement;
+        preferredStartAddress = coreclrLoadAddress + CoreClrLibrarySize;
+        preferredStartAddressIncrement = MemoryProbingIncrement;
     }
     else
     {
         // Try to allocate below the location of libcoreclr
-        startAddress = coreclrLoadAddress - MaxExecutableMemorySize;
-        startAddressIncrement = 0;
+        preferredStartAddress = coreclrLoadAddress - MaxExecutableMemorySizeNearCoreClr;
+        preferredStartAddressIncrement = 0;
     }
 
     // Do actual memory reservation.
     do
     {
-        m_startAddress = ReserveVirtualMemory(pthrCurrent, (void*)startAddress, sizeOfAllocation);
-        if (m_startAddress != NULL)
+        m_startAddress = ReserveVirtualMemory(pthrCurrent, (void*)preferredStartAddress, sizeOfAllocation);
+        if (m_startAddress != nullptr)
         {
-            // Memory has been successfully reserved.
-            m_totalSizeOfReservedMemory = sizeOfAllocation;
-
-            // Randomize the location at which we start allocating from the reserved memory range.
-            int32_t randomOffset = GenerateRandomStartOffset();
-            m_nextFreeAddress = (void*)(((UINT_PTR)m_startAddress) + randomOffset);
-            m_remainingReservedMemory = sizeOfAllocation - randomOffset;
             break;
         }
 
         // Try to allocate a smaller region
         sizeOfAllocation -= MemoryProbingIncrement;
-        startAddress += startAddressIncrement;
+        preferredStartAddress += preferredStartAddressIncrement;
 
     } while (sizeOfAllocation >= MemoryProbingIncrement);
+
+    if (m_startAddress == nullptr)
+    {
+        // We were not able to reserve any memory near libcoreclr. Try to reserve approximately 2 GB of address space somewhere
+        // anyway:
+        //   - This sets aside address space that can be used for executable code, such that jumps/calls between such code may
+        //     continue to use short relative addresses instead of long absolute addresses that would currently require jump
+        //     stubs.
+        //   - The inability to allocate memory in a specific range for jump stubs is an unrecoverable problem. This reservation
+        //     would mitigate such issues that can become prevalent depending on which security features are enabled and to what
+        //     extent, such as in particular, PaX's RANDMMAP:
+        //       - https://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options
+        //   - Jump stubs for executable code residing in this region can request memory from this allocator
+        //   - Native images can be loaded into this address space, including any jump stubs that are required for its helper
+        //     table. This satisfies the vast majority of practical cases where the total amount of loaded native image memory
+        //     does not exceed approximately 2 GB.
+        //   - The code heap allocator for the JIT can allocate from this address space. Beyond this reservation, one can use
+        //     the COMPlus_CodeHeapReserveForJumpStubs environment variable to reserve space for jump stubs.
+        sizeOfAllocation = MaxExecutableMemorySize;
+        m_startAddress = ReserveVirtualMemory(pthrCurrent, nullptr, sizeOfAllocation);
+        if (m_startAddress == nullptr)
+        {
+            return;
+        }
+    }
+
+    // Memory has been successfully reserved.
+    m_totalSizeOfReservedMemory = sizeOfAllocation;
+
+    // Randomize the location at which we start allocating from the reserved memory range. Alignment to a 64 KB granularity
+    // should not be necessary, but see AllocateMemory() for the reason why it is done.
+    int32_t randomOffset = GenerateRandomStartOffset();
+    m_nextFreeAddress = ALIGN_UP((void*)(((UINT_PTR)m_startAddress) + randomOffset), VIRTUAL_64KB);
+    _ASSERTE(sizeOfAllocation >= (UINT_PTR)m_nextFreeAddress - (UINT_PTR)m_startAddress);
+    m_remainingReservedMemory =
+        ALIGN_DOWN(sizeOfAllocation - ((UINT_PTR)m_nextFreeAddress - (UINT_PTR)m_startAddress), VIRTUAL_64KB);
 }
 
 /*++
@@ -2086,7 +2200,7 @@ Function:
     ExecutableMemoryAllocator::AllocateMemory
 
     This function attempts to allocate the requested amount of memory from its reserved virtual
-    address space. The function will return NULL if the allocation request cannot
+    address space. The function will return null if the allocation request cannot
     be satisfied by the memory that is currently available in the allocator.
 
     Note: This function MUST be called with the virtual_critsec lock held.
@@ -2094,10 +2208,15 @@ Function:
 --*/
 void* ExecutableMemoryAllocator::AllocateMemory(SIZE_T allocationSize)
 {
-    void* allocatedMemory = NULL;
+#ifdef BIT64
+    void* allocatedMemory = nullptr;
 
-    // Allocation size must be in multiples of the virtual page size.
-    _ASSERTE((allocationSize & VIRTUAL_PAGE_MASK) == 0);
+    // Alignment to a 64 KB granularity should not be necessary (alignment to page size should be sufficient), but
+    // VIRTUALReserveMemory() aligns down the specified address to a 64 KB granularity, and as long as that is necessary, the
+    // reservation size here must be aligned to a 64 KB granularity to guarantee that all returned addresses are also aligned to
+    // a 64 KB granularity. Otherwise, attempting to reserve memory starting from an unaligned address returned by this function
+    // would fail in VIRTUALReserveMemory.
+    _ASSERTE(IS_ALIGNED(allocationSize, VIRTUAL_64KB));
 
     // The code below assumes that the caller owns the virtual_critsec lock.
     // So the calculations are not done in thread-safe manner.
@@ -2106,10 +2225,60 @@ void* ExecutableMemoryAllocator::AllocateMemory(SIZE_T allocationSize)
         allocatedMemory = m_nextFreeAddress;
         m_nextFreeAddress = (void*)(((UINT_PTR)m_nextFreeAddress) + allocationSize);
         m_remainingReservedMemory -= allocationSize;
-
     }
 
     return allocatedMemory;
+#else // !BIT64
+    return nullptr;
+#endif // BIT64
+}
+
+/*++
+Function:
+    AllocateMemory
+
+    This function attempts to allocate the requested amount of memory from its reserved virtual
+    address space, if memory is available within the specified range. The function will return
+    null if the allocation request cannot satisfied by the memory that is currently available in
+    the allocator.
+
+    Note: This function MUST be called with the virtual_critsec lock held.
+--*/
+void *ExecutableMemoryAllocator::AllocateMemoryWithinRange(const void *beginAddress, const void *endAddress, SIZE_T allocationSize)
+{
+#ifdef BIT64
+    _ASSERTE(beginAddress <= endAddress);
+
+    // Alignment to a 64 KB granularity should not be necessary (alignment to page size should be sufficient), but see
+    // AllocateMemory() for the reason why it is necessary
+    _ASSERTE(IS_ALIGNED(allocationSize, VIRTUAL_64KB));
+
+    // The code below assumes that the caller owns the virtual_critsec lock.
+    // So the calculations are not done in thread-safe manner.
+
+    if (allocationSize == 0 || allocationSize > m_remainingReservedMemory)
+    {
+        return nullptr;
+    }
+
+    void *address = m_nextFreeAddress;
+    if (address < beginAddress)
+    {
+        return nullptr;
+    }
+
+    void *nextFreeAddress = (void *)((UINT_PTR)address + allocationSize);
+    if (nextFreeAddress > endAddress)
+    {
+        return nullptr;
+    }
+
+    m_nextFreeAddress = nextFreeAddress;
+    m_remainingReservedMemory -= allocationSize;
+    return address;
+#else // !BIT64
+    return nullptr;
+#endif // BIT64
 }
 
 /*++
index 2a93d3c..6db9bf6 100644 (file)
@@ -2981,7 +2981,7 @@ PROCAbort()
     // Do any shutdown cleanup before aborting or creating a core dump
     PROCNotifyProcessShutdown();
 
-#if HAVE_PRCTL_H
+#if HAVE_PRCTL_H && HAVE_PR_SET_PTRACER
     // If enabled, launch the create minidump utility and wait until it completes
     if (g_argvCreateDump[0] != nullptr)
     {
@@ -3018,7 +3018,7 @@ PROCAbort()
             }
         }
     }
-#endif // HAVE_PRCTL_H
+#endif // HAVE_PRCTL_H && HAVE_PR_SET_PTRACER
     // Abort the process after waiting for the core dump to complete
     abort();
 }
diff --git a/src/scripts/genEventPipe.py b/src/scripts/genEventPipe.py
new file mode 100644 (file)
index 0000000..3a818ce
--- /dev/null
@@ -0,0 +1,500 @@
+from __future__ import print_function
+from genXplatEventing import *
+from genXplatLttng import *
+import os
+import xml.dom.minidom as DOM
+
+stdprolog = """// 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.
+
+/******************************************************************
+
+DO NOT MODIFY. AUTOGENERATED FILE.
+This file is generated using the logic from <root>/src/scripts/genEventPipe.py
+
+******************************************************************/
+"""
+
+stdprolog_cmake = """#
+#
+#******************************************************************
+
+#DO NOT MODIFY. AUTOGENERATED FILE.
+#This file is generated using the logic from <root>/src/scripts/genEventPipe.py
+
+#******************************************************************
+"""
+
+
+def generateClrEventPipeWriteEventsImpl(
+        providerName, eventNodes, allTemplates, exclusionListFile):
+    providerPrettyName = providerName.replace("Windows-", '')
+    providerPrettyName = providerPrettyName.replace("Microsoft-", '')
+    providerPrettyName = providerPrettyName.replace('-', '_')
+    WriteEventImpl = []
+
+    # EventPipeEvent declaration
+    for eventNode in eventNodes:
+        eventName = eventNode.getAttribute('symbol')
+        WriteEventImpl.append(
+            "EventPipeEvent *EventPipeEvent" +
+            eventName +
+            " = nullptr;\n")
+
+    for eventNode in eventNodes:
+        eventName = eventNode.getAttribute('symbol')
+        templateName = eventNode.getAttribute('template')
+
+        # generate EventPipeEventEnabled function
+        eventEnabledImpl = """bool EventPipeEventEnabled%s()
+{
+    return EventPipeEvent%s->IsEnabled();
+}
+
+""" % (eventName, eventName)
+        WriteEventImpl.append(eventEnabledImpl)
+
+        # generate EventPipeWriteEvent function
+        fnptype = []
+        linefnptype = []
+        fnptype.append("extern \"C\" ULONG EventPipeWriteEvent")
+        fnptype.append(eventName)
+        fnptype.append("(\n")
+
+        if templateName:
+            template = allTemplates[templateName]
+        else:
+            template = None
+
+        if template:
+            fnSig = template.signature
+            for paramName in fnSig.paramlist:
+                fnparam = fnSig.getParam(paramName)
+                wintypeName = fnparam.winType
+                typewName = palDataTypeMapping[wintypeName]
+                winCount = fnparam.count
+                countw = palDataTypeMapping[winCount]
+
+                if paramName in template.structs:
+                    linefnptype.append(
+                        "%sint %s_ElementSize,\n" %
+                        (lindent, paramName))
+
+                linefnptype.append(lindent)
+                linefnptype.append(typewName)
+                if countw != " ":
+                    linefnptype.append(countw)
+
+                linefnptype.append(" ")
+                linefnptype.append(fnparam.name)
+                linefnptype.append(",\n")
+
+            if len(linefnptype) > 0:
+                del linefnptype[-1]
+
+        fnptype.extend(linefnptype)
+        fnptype.append(")\n{\n")
+        checking = """    if (!EventPipeEventEnabled%s())
+        return ERROR_SUCCESS;
+""" % (eventName)
+
+        fnptype.append(checking)
+
+        WriteEventImpl.extend(fnptype)
+
+        if template:
+            body = generateWriteEventBody(template, providerName, eventName)
+            WriteEventImpl.append(body)
+        else:
+            WriteEventImpl.append(
+                "    EventPipe::WriteEvent(*EventPipeEvent" +
+                eventName +
+                ", nullptr, 0);\n")
+
+        WriteEventImpl.append("\n    return ERROR_SUCCESS;\n}\n\n")
+
+    # EventPipeProvider and EventPipeEvent initialization
+    WriteEventImpl.append(
+        "extern \"C\" void Init" +
+        providerPrettyName +
+        "()\n{\n")
+    WriteEventImpl.append(
+        "    EventPipeProvider" +
+        providerPrettyName +
+        " = new EventPipeProvider(" +
+        providerPrettyName +
+        "GUID);\n")
+    for eventNode in eventNodes:
+        eventName = eventNode.getAttribute('symbol')
+        templateName = eventNode.getAttribute('template')
+        eventKeywords = eventNode.getAttribute('keywords')
+        eventKeywordsMask = generateEventKeywords(eventKeywords)
+        eventValue = eventNode.getAttribute('value')
+        eventVersion = eventNode.getAttribute('version')
+        eventLevel = eventNode.getAttribute('level')
+        eventLevel = eventLevel.replace("win:", "EventPipeEventLevel::")
+        exclusionInfo = parseExclusionList(exclusionListFile)
+        taskName = eventNode.getAttribute('task')
+        noStack = getStackWalkBit(
+            providerName,
+            taskName,
+            eventName,
+            exclusionInfo.nostack)
+
+        initEvent = """    EventPipeEvent%s = EventPipeProvider%s->AddEvent(%s,%s,%s,%s,%d);
+""" % (eventName, providerPrettyName, eventKeywordsMask, eventValue, eventVersion, eventLevel, int(noStack))
+
+        WriteEventImpl.append(initEvent)
+    WriteEventImpl.append("}")
+
+    return ''.join(WriteEventImpl)
+
+
+def generateWriteEventBody(template, providerName, eventName):
+    header = """
+    char stackBuffer[%s];
+    char *buffer = stackBuffer;
+    unsigned int offset = 0;
+    unsigned int size = %s;
+    bool fixedBuffer = true;
+
+    bool success = true;
+""" % (template.estimated_size, template.estimated_size)
+
+    fnSig = template.signature
+    pack_list = []
+    for paramName in fnSig.paramlist:
+        parameter = fnSig.getParam(paramName)
+
+        if paramName in template.structs:
+            size = "(int)%s_ElementSize * (int)%s" % (
+                paramName, parameter.prop)
+            if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]:
+                size = "(int)(%s)" % specialCaseSizes[template.name][paramName]
+            pack_list.append(
+                "    success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" %
+                (paramName, size))
+        elif paramName in template.arrays:
+            size = "sizeof(%s) * (int)%s" % (
+                lttngDataTypeMapping[parameter.winType],
+                parameter.prop)
+            if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]:
+                size = "(int)(%s)" % specialCaseSizes[template.name][paramName]
+            pack_list.append(
+                "    success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" %
+                (paramName, size))
+        elif parameter.winType == "win:GUID":
+            pack_list.append(
+                "    success &= WriteToBuffer(*%s, buffer, offset, size, fixedBuffer);" %
+                (parameter.name,))
+        else:
+            pack_list.append(
+                "    success &= WriteToBuffer(%s, buffer, offset, size, fixedBuffer);" %
+                (parameter.name,))
+
+    code = "\n".join(pack_list) + "\n\n"
+
+    checking = """    if (!success)
+    {
+        if (!fixedBuffer)
+            delete[] buffer;
+        return ERROR_WRITE_FAULT;
+    }\n\n"""
+
+    body = "    EventPipe::WriteEvent(*EventPipeEvent" + \
+        eventName + ", (BYTE *)buffer, size);\n"
+
+    footer = """
+    if (!fixedBuffer)
+        delete[] buffer;
+"""
+
+    return header + code + checking + body + footer
+
+providerGUIDMap = {}
+providerGUIDMap[
+    "{e13c0d23-ccbc-4e12-931b-d9cc2eee27e4}"] = "{0xe13c0d23,0xccbc,0x4e12,{0x93,0x1b,0xd9,0xcc,0x2e,0xee,0x27,0xe4}}"
+providerGUIDMap[
+    "{A669021C-C450-4609-A035-5AF59AF4DF18}"] = "{0xA669021C,0xC450,0x4609,{0xA0,0x35,0x5A,0xF5,0x9A,0xF4,0xDF,0x18}}"
+providerGUIDMap[
+    "{CC2BCBBA-16B6-4cf3-8990-D74C2E8AF500}"] = "{0xCC2BCBBA,0x16B6,0x4cf3,{0x89,0x90,0xD7,0x4C,0x2E,0x8A,0xF5,0x00}}"
+providerGUIDMap[
+    "{763FD754-7086-4dfe-95EB-C01A46FAF4CA}"] = "{0x763FD754,0x7086,0x4dfe,{0x95,0xEB,0xC0,0x1A,0x46,0xFA,0xF4,0xCA}}"
+
+
+def generateGUID(tmpGUID):
+    return providerGUIDMap[tmpGUID]
+
+keywordMap = {}
+
+
+def generateEventKeywords(eventKeywords):
+    mask = 0
+    # split keywords if there are multiple
+    allKeywords = eventKeywords.split()
+
+    for singleKeyword in allKeywords:
+        mask = mask | keywordMap[singleKeyword]
+
+    return mask
+
+
+def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory):
+    tree = DOM.parse(etwmanifest)
+
+    with open(eventpipe_directory + "CMakeLists.txt", 'w') as topCmake:
+        topCmake.write(stdprolog_cmake + "\n")
+        topCmake.write("""cmake_minimum_required(VERSION 2.8.12.2)
+
+        project(eventpipe)
+
+        set(CMAKE_INCLUDE_CURRENT_DIR ON)
+        include_directories(${CLR_DIR}/src/vm)
+
+        add_library(eventpipe
+            STATIC\n""")
+
+        for providerNode in tree.getElementsByTagName('provider'):
+            providerName = providerNode.getAttribute('name')
+            providerName = providerName.replace("Windows-", '')
+            providerName = providerName.replace("Microsoft-", '')
+
+            providerName_File = providerName.replace('-', '')
+            providerName_File = providerName_File.lower()
+
+            topCmake.write('            "%s.cpp"\n' % (providerName_File))
+        topCmake.write('            "eventpipehelpers.cpp"\n')
+        topCmake.write("""        )
+
+        # Install the static eventpipe library
+        install(TARGETS eventpipe DESTINATION lib)
+        """)
+
+    topCmake.close()
+
+
+def generateEventPipeHelperFile(etwmanifest, eventpipe_directory):
+    with open(eventpipe_directory + "eventpipehelpers.cpp", 'w') as helper:
+        helper.write(stdprolog)
+        helper.write("""
+#include "stdlib.h"
+
+bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned int newSize, bool &fixedBuffer)
+{
+    newSize *= 1.5;
+    _ASSERTE(newSize > size); // check for overflow
+
+    if (newSize < 32)
+        newSize = 32;
+
+    char *newBuffer = new char[newSize];
+
+    memcpy(newBuffer, buffer, currLen);
+
+    if (!fixedBuffer)
+        delete[] buffer;
+
+    buffer = newBuffer;
+    size = newSize;
+    fixedBuffer = false;
+
+    return true;
+}
+
+bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer)
+{
+    if(!src) return true;
+    if (offset + len > size)
+    {
+        if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer))
+            return false;
+    }
+
+    memcpy(buffer + offset, src, len);
+    offset += len;
+    return true;
+}
+
+bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer)
+{
+    if(!str) return true;
+    unsigned int byteCount = (PAL_wcslen(str) + 1) * sizeof(*str);
+
+    if (offset + byteCount > size)
+    {
+        if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer))
+            return false;
+    }
+
+    memcpy(buffer + offset, str, byteCount);
+    offset += byteCount;
+    return true;
+}
+
+bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer)
+{
+    if(!str) return true;
+    unsigned int len = strlen(str) + 1;
+    if (offset + len > size)
+    {
+        if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer))
+            return false;
+    }
+
+    memcpy(buffer + offset, str, len);
+    offset += len;
+    return true;
+}
+
+""")
+
+        tree = DOM.parse(etwmanifest)
+
+        for providerNode in tree.getElementsByTagName('provider'):
+            providerName = providerNode.getAttribute('name')
+            providerPrettyName = providerName.replace("Windows-", '')
+            providerPrettyName = providerPrettyName.replace("Microsoft-", '')
+            providerPrettyName = providerPrettyName.replace('-', '_')
+            helper.write(
+                "extern \"C\" void Init" +
+                providerPrettyName +
+                "();\n\n")
+
+        helper.write("extern \"C\" void InitProvidersAndEvents()\n{\n")
+        for providerNode in tree.getElementsByTagName('provider'):
+            providerName = providerNode.getAttribute('name')
+            providerPrettyName = providerName.replace("Windows-", '')
+            providerPrettyName = providerPrettyName.replace("Microsoft-", '')
+            providerPrettyName = providerPrettyName.replace('-', '_')
+            helper.write("    Init" + providerPrettyName + "();\n")
+        helper.write("}")
+
+    helper.close()
+
+
+def generateEventPipeImplFiles(
+        etwmanifest, eventpipe_directory, exclusionListFile):
+    tree = DOM.parse(etwmanifest)
+    coreclrRoot = os.getcwd()
+    for providerNode in tree.getElementsByTagName('provider'):
+        providerGUID = providerNode.getAttribute('guid')
+        providerGUID = generateGUID(providerGUID)
+        providerName = providerNode.getAttribute('name')
+
+        providerPrettyName = providerName.replace("Windows-", '')
+        providerPrettyName = providerPrettyName.replace("Microsoft-", '')
+        providerName_File = providerPrettyName.replace('-', '')
+        providerName_File = providerName_File.lower()
+        providerPrettyName = providerPrettyName.replace('-', '_')
+        eventpipefile = eventpipe_directory + providerName_File + ".cpp"
+        eventpipeImpl = open(eventpipefile, 'w')
+        eventpipeImpl.write(stdprolog)
+
+        header = """
+#include \"%s/src/vm/common.h\"
+#include \"%s/src/vm/eventpipeprovider.h\"
+#include \"%s/src/vm/eventpipeevent.h\"
+#include \"%s/src/vm/eventpipe.h\"
+
+bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned int newSize, bool &fixedBuffer);
+bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer);
+bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer);
+bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer);
+
+template <typename T>
+bool WriteToBuffer(const T &value, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer)
+{
+    if (sizeof(T) + offset > size)
+    {
+           if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer))
+                   return false;
+    }
+
+    *(T *)(buffer + offset) = value;
+    offset += sizeof(T);
+    return true;
+}
+
+""" % (coreclrRoot, coreclrRoot, coreclrRoot, coreclrRoot)
+
+        eventpipeImpl.write(header)
+        eventpipeImpl.write(
+            "GUID const " +
+            providerPrettyName +
+            "GUID = " +
+            providerGUID +
+            ";\n")
+        eventpipeImpl.write(
+            "EventPipeProvider *EventPipeProvider" +
+            providerPrettyName +
+            " = nullptr;\n")
+        templateNodes = providerNode.getElementsByTagName('template')
+        allTemplates = parseTemplateNodes(templateNodes)
+        eventNodes = providerNode.getElementsByTagName('event')
+        eventpipeImpl.write(
+            generateClrEventPipeWriteEventsImpl(
+                providerName,
+                eventNodes,
+                allTemplates,
+                exclusionListFile) + "\n")
+        eventpipeImpl.close()
+
+
+def generateEventPipeFiles(
+        etwmanifest, eventpipe_directory, exclusionListFile):
+    eventpipe_directory = eventpipe_directory + "/"
+    tree = DOM.parse(etwmanifest)
+
+    if not os.path.exists(eventpipe_directory):
+        os.makedirs(eventpipe_directory)
+
+    # generate Cmake file
+    generateEventPipeCmakeFile(etwmanifest, eventpipe_directory)
+
+    # generate helper file
+    generateEventPipeHelperFile(etwmanifest, eventpipe_directory)
+
+    # generate all keywords
+    for keywordNode in tree.getElementsByTagName('keyword'):
+        keywordName = keywordNode.getAttribute('name')
+        keywordMask = keywordNode.getAttribute('mask')
+        keywordMap[keywordName] = int(keywordMask, 0)
+
+    # generate .cpp file for each provider
+    generateEventPipeImplFiles(
+        etwmanifest,
+        eventpipe_directory,
+        exclusionListFile)
+
+import argparse
+import sys
+
+
+def main(argv):
+
+    # parse the command line
+    parser = argparse.ArgumentParser(
+        description="Generates the Code required to instrument eventpipe logging mechanism")
+
+    required = parser.add_argument_group('required arguments')
+    required.add_argument('--man', type=str, required=True,
+                          help='full path to manifest containig the description of events')
+    required.add_argument('--intermediate', type=str, required=True,
+                          help='full path to eventprovider  intermediate directory')
+    required.add_argument('--exc', type=str, required=True,
+                          help='full path to exclusion list')
+    args, unknown = parser.parse_known_args(argv)
+    if unknown:
+        print('Unknown argument(s): ', ', '.join(unknown))
+        return const.UnknownArguments
+
+    sClrEtwAllMan = args.man
+    intermediate = args.intermediate
+    exclusionListFile = args.exc
+
+    generateEventPipeFiles(sClrEtwAllMan, intermediate, exclusionListFile)
+
+if __name__ == '__main__':
+    return_code = main(sys.argv[1:])
+    sys.exit(return_code)
index 6c6498d..6968d29 100644 (file)
@@ -39,7 +39,7 @@ stdprolog_cmake="""
 #******************************************************************
 """
 
-lindent = "                  ";
+lindent = "    ";
 palDataTypeMapping ={
         #constructed types
         "win:null"          :" ",
@@ -282,18 +282,17 @@ def generateClrallEvents(eventNodes,allTemplates):
         #generate EventEnabled
         clrallEvents.append("inline BOOL EventEnabled")
         clrallEvents.append(eventName)
-        clrallEvents.append("() {return XplatEventLogger::IsEventLoggingEnabled() && EventXplatEnabled")
-        clrallEvents.append(eventName+"();}\n\n")
+        clrallEvents.append("() {return ")
+        clrallEvents.append("EventPipeEventEnabled" + eventName + "() || ")
+        clrallEvents.append("(XplatEventLogger::IsEventLoggingEnabled() && EventXplatEnabled")
+        clrallEvents.append(eventName+"());}\n\n")
         #generate FireEtw functions
         fnptype     = []
         fnbody      = []
         fnptype.append("inline ULONG FireEtw")
         fnptype.append(eventName)
         fnptype.append("(\n")
-        fnbody.append(lindent)
-        fnbody.append("if (!EventEnabled")
-        fnbody.append(eventName)
-        fnbody.append("()) {return ERROR_SUCCESS;}\n")
+
         line        = []
         fnptypeline = []
 
@@ -339,11 +338,22 @@ def generateClrallEvents(eventNodes,allTemplates):
         fnptype.extend(fnptypeline)
         fnptype.append("\n)\n{\n")
         fnbody.append(lindent)
-        fnbody.append("return FireEtXplat")
+        fnbody.append("ULONG status = EventPipeWriteEvent" + eventName + "(" + ''.join(line) + ");\n")
+        fnbody.append(lindent)
+        fnbody.append("if(XplatEventLogger::IsEventLoggingEnabled())\n")
+        fnbody.append(lindent)
+        fnbody.append("{\n")
+        fnbody.append(lindent)
+        fnbody.append(lindent)
+        fnbody.append("status &= FireEtXplat")
         fnbody.append(eventName)
         fnbody.append("(")
         fnbody.extend(line)
         fnbody.append(");\n")
+        fnbody.append(lindent)
+        fnbody.append("}\n")
+        fnbody.append(lindent)
+        fnbody.append("return status;\n")
         fnbody.append("}\n\n")
 
         clrallEvents.extend(fnptype)
@@ -400,6 +410,57 @@ def generateClrXplatEvents(eventNodes, allTemplates):
 
     return ''.join(clrallEvents)
 
+def generateClrEventPipeWriteEvents(eventNodes, allTemplates):
+    clrallEvents = []
+    for eventNode in eventNodes:
+        eventName    = eventNode.getAttribute('symbol')
+        templateName = eventNode.getAttribute('template')
+
+        #generate EventPipeEventEnabled and EventPipeWriteEvent functions
+        eventenabled = []
+        writeevent   = []
+        fnptypeline  = []
+
+        eventenabled.append("extern \"C\" bool EventPipeEventEnabled")
+        eventenabled.append(eventName)
+        eventenabled.append("();\n")
+
+        writeevent.append("extern \"C\" ULONG EventPipeWriteEvent")
+        writeevent.append(eventName)
+        writeevent.append("(\n")
+
+        if templateName:
+            template = allTemplates[templateName]
+            fnSig    = template.signature
+
+            for params in fnSig.paramlist:
+                fnparam     = fnSig.getParam(params)
+                wintypeName = fnparam.winType
+                typewName   = palDataTypeMapping[wintypeName]
+                winCount    = fnparam.count
+                countw      = palDataTypeMapping[winCount]
+
+                if params in template.structs:
+                    fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params))
+
+                fnptypeline.append(lindent)
+                fnptypeline.append(typewName)
+                fnptypeline.append(countw)
+                fnptypeline.append(" ")
+                fnptypeline.append(fnparam.name)
+                fnptypeline.append(",\n")
+
+            #remove trailing commas
+            if len(fnptypeline) > 0:
+                del fnptypeline[-1]
+
+        writeevent.extend(fnptypeline)
+        writeevent.append("\n);\n")
+        clrallEvents.extend(eventenabled)
+        clrallEvents.extend(writeevent)
+
+    return ''.join(clrallEvents)
+
 #generates the dummy header file which is used by the VM as entry point to the logging Functions
 def generateclrEtwDummy(eventNodes,allTemplates):
     clretmEvents = []
@@ -670,15 +731,19 @@ def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile):
 
     clrallevents   = incDir + "/clretwallmain.h"
     clrxplatevents = incDir + "/clrxplatevents.h"
+    clreventpipewriteevents = incDir + "/clreventpipewriteevents.h"
 
     Clrallevents   = open(clrallevents,'w')
     Clrxplatevents = open(clrxplatevents,'w')
+    Clreventpipewriteevents = open(clreventpipewriteevents,'w')
 
     Clrallevents.write(stdprolog + "\n")
     Clrxplatevents.write(stdprolog + "\n")
+    Clreventpipewriteevents.write(stdprolog + "\n")
 
-    Clrallevents.write("\n#include \"clrxplatevents.h\"\n\n")
-
+    Clrallevents.write("\n#include \"clrxplatevents.h\"\n")
+    Clrallevents.write("#include \"clreventpipewriteevents.h\"\n\n")
+    
     for providerNode in tree.getElementsByTagName('provider'):
         templateNodes = providerNode.getElementsByTagName('template')
         allTemplates  = parseTemplateNodes(templateNodes)
@@ -689,8 +754,12 @@ def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile):
         #pal: create clrallevents.h
         Clrxplatevents.write(generateClrXplatEvents(eventNodes, allTemplates) + "\n")
 
+        #eventpipe: create clreventpipewriteevents.h
+        Clreventpipewriteevents.write(generateClrEventPipeWriteEvents(eventNodes, allTemplates) + "\n")
+
     Clrxplatevents.close()
     Clrallevents.close()
+    Clreventpipewriteevents.close()
 
 class EventExclusions:
     def __init__(self):
index bacf034..fae0e12 100644 (file)
@@ -593,7 +593,8 @@ bool ResizeBuffer(char *&buffer, int& size, int currLen, int newSize, bool &fixe
 
 bool WriteToBuffer(const BYTE *src, int len, char *&buffer, int& offset, int& size, bool &fixedBuffer)
 {
-       if (offset + len)
+    if (!src) return true;
+       if (offset + len > size)
        {
                if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer))
                        return false;
@@ -606,9 +607,10 @@ bool WriteToBuffer(const BYTE *src, int len, char *&buffer, int& offset, int& si
 
 bool WriteToBuffer(PCWSTR str, char *&buffer, int& offset, int& size, bool &fixedBuffer)
 {
+    if (!str) return true;
        int byteCount = (PAL_wcslen(str) + 1) * sizeof(*str);
 
-       if (offset + byteCount)
+       if (offset + byteCount > size)
        {
                if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer))
                        return false;
@@ -621,8 +623,9 @@ bool WriteToBuffer(PCWSTR str, char *&buffer, int& offset, int& size, bool &fixe
 
 bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool &fixedBuffer)
 {
+    if (!str) return true;
        int len = strlen(str) + 1;
-       if (offset + len)
+       if (offset + len > size)
        {
                if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer))
                        return false;
@@ -762,4 +765,4 @@ def main(argv):
 
 if __name__ == '__main__':
     return_code = main(sys.argv[1:])
-    sys.exit(return_code)
\ No newline at end of file
+    sys.exit(return_code)
index a8786de..b7fca3e 100644 (file)
@@ -573,7 +573,9 @@ static DWORD ShouldInjectFaultInRange()
 // Reserves free memory within the range [pMinAddr..pMaxAddr] using
 // ClrVirtualQuery to find free memory and ClrVirtualAlloc to reserve it.
 //
-// This method only supports the flAllocationType of MEM_RESERVE
+// This method only supports the flAllocationType of MEM_RESERVE, and expects that the memory
+// is being reserved for the purpose of eventually storing executable code.
+//
 // Callers also should set dwSize to a multiple of sysInfo.dwAllocationGranularity (64k).
 // That way they can reserve a large region and commit smaller sized pages
 // from that region until it fills up.  
@@ -603,6 +605,11 @@ BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr,
     static unsigned countOfCalls = 0;  // We log the number of tims we call this method
     countOfCalls++;                    // increment the call counter
 
+    if (dwSize == 0)
+    {
+        return nullptr;
+    }
+
     //
     // First lets normalize the pMinAddr and pMaxAddr values
     //
@@ -618,18 +625,26 @@ BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr,
         pMaxAddr = (BYTE *) TOP_MEMORY;
     }
 
+    // If pMaxAddr is not greater than pMinAddr we can not make an allocation
+    if (pMaxAddr <= pMinAddr)
+    {
+        return nullptr;
+    }
+
     // If pMinAddr is BOT_MEMORY and pMaxAddr is TOP_MEMORY
     // then we can call ClrVirtualAlloc instead 
     if ((pMinAddr == (BYTE *) BOT_MEMORY) && (pMaxAddr == (BYTE *) TOP_MEMORY))
     {
-        return (BYTE*) ClrVirtualAlloc(NULL, dwSize, flAllocationType, flProtect);
+        return (BYTE*) ClrVirtualAlloc(nullptr, dwSize, flAllocationType, flProtect);
     }
 
-    // If pMaxAddr is not greater than pMinAddr we can not make an allocation
-    if (dwSize == 0 || pMaxAddr <= pMinAddr)
+#ifdef FEATURE_PAL
+    pResult = (BYTE *)PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange(pMinAddr, pMaxAddr, dwSize);
+    if (pResult != nullptr)
     {
-        return NULL;
+        return pResult;
     }
+#endif // FEATURE_PAL
 
     // We will do one scan from [pMinAddr .. pMaxAddr]
     // First align the tryAddr up to next 64k base address. 
index ec4ff42..556eb0e 100644 (file)
@@ -164,8 +164,14 @@ set(VM_SOURCES_WKS
     eepolicy.cpp
     eetoprofinterfaceimpl.cpp
     eventpipe.cpp
+    eventpipeconfiguration.cpp
+    eventpipeevent.cpp
+    eventpipeeventinstance.cpp
+    eventpipefile.cpp
     eventpipejsonfile.cpp
+    eventpipeprovider.cpp
     eventstore.cpp
+    fastserializer.cpp
     fcall.cpp
     fieldmarshaler.cpp
     finalizerthread.cpp
@@ -481,3 +487,7 @@ convert_to_absolute_path(VM_SOURCES_DAC ${VM_SOURCES_DAC})
 
 add_subdirectory(dac)
 add_subdirectory(wks)
+
+if(CLR_CMAKE_PLATFORM_LINUX)
+    add_subdirectory($ENV{__IntermediatesDir}/Generated/eventpipe ${CMAKE_CURRENT_BINARY_DIR}/eventpipe)
+endif(CLR_CMAKE_PLATFORM_LINUX)
index 04d7527..36933f5 100644 (file)
@@ -509,6 +509,24 @@ LOCAL_LABEL(UM2MThunk_WrapperHelper_ArgumentsSetup):
         NESTED_END ThePreStub, _TEXT
 
 // ------------------------------------------------------------------
+        NESTED_ENTRY ThePreStubCompactARM, _TEXT, NoHandler
+
+        // r12 - address of compact entry point + PC_REG_RELATIVE_OFFSET
+
+        PROLOG_WITH_TRANSITION_BLOCK
+
+        mov         r0, r12
+
+        bl          C_FUNC(PreStubGetMethodDescForCompactEntryPoint)
+
+        mov         r12, r0                                          // pMethodDesc
+
+        EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
+
+        b           C_FUNC(ThePreStub)
+
+        NESTED_END ThePreStubCompactARM, _TEXT
+// ------------------------------------------------------------------
 // This method does nothing. It's just a fixed function for the debugger to put a breakpoint on.
         LEAF_ENTRY ThePreStubPatch, _TEXT
         nop
index 542bdc6..e5fd41a 100644 (file)
@@ -24,6 +24,7 @@
     IMPORT UMThunkStubRareDisableWorker
     IMPORT UM2MDoADCallBack
     IMPORT PreStubWorker
+    IMPORT PreStubGetMethodDescForCompactEntryPoint
     IMPORT NDirectImportWorker
     IMPORT ObjIsInstanceOfNoGC
     IMPORT ArrayStoreCheck
@@ -571,6 +572,26 @@ UM2MThunk_WrapperHelper_ArgumentsSetup
         NESTED_END
 
 ; ------------------------------------------------------------------
+
+        NESTED_ENTRY ThePreStubCompactARM
+
+        ; r12 - address of compact entry point + PC_REG_RELATIVE_OFFSET
+
+        PROLOG_WITH_TRANSITION_BLOCK
+
+        mov         r0, r12
+
+        bl          PreStubGetMethodDescForCompactEntryPoint
+
+        mov         r12, r0                                  ; pMethodDesc
+
+        EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
+
+        b          ThePreStub
+
+        NESTED_END
+
+; ------------------------------------------------------------------
 ; This method does nothing. It's just a fixed function for the debugger to put a breakpoint on.
         LEAF_ENTRY ThePreStubPatch
         nop
index 34af818..181d5f1 100644 (file)
@@ -57,7 +57,7 @@ EXTERN_C void checkStack(void);
 #define JUMP_ALLOCATE_SIZE                      8   // # bytes to allocate for a jump instruction
 #define BACK_TO_BACK_JUMP_ALLOCATE_SIZE         8   // # bytes to allocate for a back to back jump instruction
 
-//#define HAS_COMPACT_ENTRYPOINTS                 1
+#define HAS_COMPACT_ENTRYPOINTS                 1
 
 #define HAS_NDIRECT_IMPORT_PRECODE              1
 
@@ -90,6 +90,12 @@ EXTERN_C void setFPReturn(int fpSize, INT64 retVal);
 // this is the offset by which it should be decremented to arrive at the callsite.
 #define STACKWALK_CONTROLPC_ADJUST_OFFSET 2
 
+// Max offset for unconditional thumb branch
+#define MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB 2048
+
+// Offset of pc register
+#define PC_REG_RELATIVE_OFFSET 4
+
 //=======================================================================
 // IMPORTANT: This value is used to figure out how much to allocate
 // for a fixed array of FieldMarshaler's. That means it must be at least
@@ -236,6 +242,53 @@ void emitCOMStubCall (ComCallMethodDesc *pCOMMethod, PCODE target);
 #endif // FEATURE_COMINTEROP
 
 //------------------------------------------------------------------------
+inline void emitUnconditionalBranchThumb(LPBYTE pBuffer, int16_t offset)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    uint16_t *pInstr = (uint16_t *) pBuffer;
+
+    // offset from -2KB to +2KB
+    _ASSERTE (offset >= - MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB && offset < MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB);
+
+    if (offset >= 0)
+    {
+        offset = offset >> 1;
+    }
+    else
+    {
+        offset = ((MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB + offset) >> 1) | 0x400;
+    }
+
+    *pInstr = 0xE000 | offset;
+}
+
+//------------------------------------------------------------------------
+inline int16_t decodeUnconditionalBranchThumb(LPBYTE pBuffer)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    uint16_t *pInstr = (uint16_t *) pBuffer;
+
+    int16_t offset = (~0xE000) & (*pInstr);
+
+    if ((offset & 0x400) == 0)
+    {
+        offset = offset << 1;
+    }
+    else
+    {
+        offset = (~0x400) & offset;
+        offset = (offset << 1) - MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB;
+    }
+
+    // offset from -2KB to +2KB
+    _ASSERTE (offset >= - MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB && offset < MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB);
+
+    return offset;
+}
+
+//------------------------------------------------------------------------
 inline void emitJump(LPBYTE pBuffer, LPVOID target)
 {
     LIMITED_METHOD_CONTRACT;
index f1ba278..3088761 100644 (file)
@@ -1333,6 +1333,13 @@ BOOL DoesSlotCallPrestub(PCODE pCode)
 {
     PTR_WORD pInstr = dac_cast<PTR_WORD>(PCODEToPINSTR(pCode));
 
+#ifdef HAS_COMPACT_ENTRYPOINTS
+    if (MethodDescChunk::GetMethodDescFromCompactEntryPoint(pCode, TRUE) != NULL)
+    {
+        return TRUE;
+    }
+#endif // HAS_COMPACT_ENTRYPOINTS
+
     // FixupPrecode
     if (pInstr[0] == 0x46fc && // // mov r12, pc
         pInstr[1] == 0xf8df &&
index 15b8057..79e3989 100644 (file)
@@ -217,6 +217,7 @@ LEAF_END ThePreStubPatch, _TEXT
 //   x13  : incremented by 8
 //   x14  : incremented by 8
 //   x15  : trashed
+//   x17  : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
 //
 WRITE_BARRIER_ENTRY JIT_ByRefWriteBarrier
 
@@ -236,6 +237,7 @@ WRITE_BARRIER_END JIT_ByRefWriteBarrier
 //   x12  : trashed
 //   x14  : incremented by 8
 //   x15  : trashed
+//   x17  : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
 //
 WRITE_BARRIER_ENTRY JIT_CheckedWriteBarrier
     PREPARE_EXTERNAL_VAR g_lowest_address, x12
@@ -262,6 +264,7 @@ WRITE_BARRIER_END JIT_CheckedWriteBarrier
 //   x12  : trashed
 //   x14  : incremented by 8
 //   x15  : trashed
+//   x17  : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
 //
 WRITE_BARRIER_ENTRY JIT_WriteBarrier
     dmb  ST
@@ -310,6 +313,21 @@ LOCAL_LABEL(shadowupdateend):
     ldp  x12, x13, [sp],#16
 #endif
 
+#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+    // Update the write watch table if necessary
+    PREPARE_EXTERNAL_VAR g_sw_ww_enabled_for_gc_heap, x12
+    ldrb w12, [x12]
+    cbz  x12, LOCAL_LABEL(CheckCardTable)
+    PREPARE_EXTERNAL_VAR g_sw_ww_table, x12
+    ldr  x12, [x12]
+    add  x12, x12, x14, lsr #0xc  // SoftwareWriteWatch::AddressToTableByteIndexShift
+    ldrb w17, [x12]
+    cbnz x17, LOCAL_LABEL(CheckCardTable)
+    mov  w17, #0xFF
+    strb w17, [x12]
+#endif
+
+LOCAL_LABEL(CheckCardTable):
     // Branch to Exit if the reference is not in the Gen0 heap
     //
     PREPARE_EXTERNAL_VAR g_ephemeral_low, x12
@@ -333,6 +351,21 @@ LOCAL_LABEL(shadowupdateend):
 LOCAL_LABEL(UpdateCardTable):
     mov  x12, 0xFF 
     strb w12, [x15]
+
+#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
+    // Check if we need to update the card table
+    PREPARE_EXTERNAL_VAR g_card_bundle_table, x12
+    ldr  x12, [x12]
+    add  x15,  x12, x14, lsr #21
+    ldrb w12, [x15]
+    cmp  x12, 0xFF
+    beq  LOCAL_LABEL(Exit)
+
+LOCAL_LABEL(UpdateCardBundle):
+    mov  x12, 0xFF
+    strb w12, [x15]
+#endif
+
 LOCAL_LABEL(Exit):
     add  x14, x14, 8
     ret  lr  
index 0c7eb4d..40d2749 100644 (file)
@@ -1317,6 +1317,19 @@ void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
     return;
 }
 
+#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+void SwitchToWriteWatchBarrier(bool isRuntimeSuspended)
+{
+    return;
+}
+
+void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended)
+{
+    return;
+}
+#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+
+
 #ifdef DACCESS_COMPILE
 BOOL GetAnyThunkTarget (T_CONTEXT *pctx, TADDR *pTarget, TADDR *pTargetMethodDesc)
 {
index 702c255..e9bcc23 100644 (file)
@@ -326,110 +326,6 @@ Assembly* AssemblyNative::LoadFromBuffer(BOOL fForIntrospection, const BYTE* pAs
     return pAssembly;
 }
 
-FCIMPL6(Object*, AssemblyNative::LoadImage, U1Array* PEByteArrayUNSAFE,
-        U1Array* SymByteArrayUNSAFE, Object* securityUNSAFE,
-        StackCrawlMark* stackMark, CLR_BOOL fForIntrospection, SecurityContextSource securityContextSource)
-{
-    FCALL_CONTRACT;
-
-    struct _gc
-    {
-        U1ARRAYREF PEByteArray;
-        U1ARRAYREF SymByteArray;
-        OBJECTREF  security;
-        OBJECTREF Throwable;
-        OBJECTREF refRetVal;
-    } gc;
-
-    gc.PEByteArray  = (U1ARRAYREF) PEByteArrayUNSAFE;
-    gc.SymByteArray = (U1ARRAYREF) SymByteArrayUNSAFE;
-    gc.security     = (OBJECTREF)  securityUNSAFE;
-    gc.Throwable = NULL;
-    gc.refRetVal = NULL;
-
-    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
-
-
-    if (gc.PEByteArray == NULL)
-        COMPlusThrow(kArgumentNullException, W("ArgumentNull_Array"));
-
-    NewArrayHolder<BYTE> pbSyms;
-    DWORD cbSyms = 0;
-
-#ifdef DEBUGGING_SUPPORTED
-    // If we were given symbols, save a copy of them.
-            // the debugger, load them now).
-    if (gc.SymByteArray != NULL)
-    {
-        Security::CopyByteArrayToEncoding(&gc.SymByteArray,
-                                                    &pbSyms, &cbSyms);
-
-    }
-#endif // DEBUGGING_SUPPORTED
-
-    Assembly* pAssembly = NULL;
-    // Pin byte array for loading
-    {
-        Wrapper<OBJECTHANDLE, DoNothing, DestroyPinningHandle> handle(
-            GetAppDomain()->CreatePinningHandle(gc.PEByteArray));
-
-        const BYTE *pbImage = gc.PEByteArray->GetDirectConstPointerToNonObjectElements();
-        DWORD cbImage = gc.PEByteArray->GetNumComponents();
-        pAssembly = LoadFromBuffer(fForIntrospection, pbImage, cbImage, pbSyms, cbSyms, stackMark, OBJECTREFToObject(gc.security), securityContextSource);
-    }
-
-
-    if (pAssembly != NULL)
-        gc.refRetVal = pAssembly->GetExposedObject();
-
-    HELPER_METHOD_FRAME_END();
-
-    return OBJECTREFToObject(gc.refRetVal);
-}
-FCIMPLEND
-
-FCIMPL2(Object*, AssemblyNative::LoadFile, StringObject* pathUNSAFE, Object* securityUNSAFE)
-{
-    FCALL_CONTRACT;
-
-    struct _gc {
-        OBJECTREF refRetVal;
-        OBJECTREF refSecurity;
-        STRINGREF strPath;
-    } gc;
-    
-    gc.refRetVal = NULL;
-    gc.refSecurity = ObjectToOBJECTREF(securityUNSAFE);
-    gc.strPath = ObjectToSTRINGREF(pathUNSAFE);
-
-    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
-
-    if(CorHost2::IsLoadFromBlocked())
-        COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);
-
-    if (pathUNSAFE == NULL)
-        COMPlusThrow(kArgumentNullException, W("ArgumentNull_Path"));
-
-    StackSString path;
-    gc.strPath->GetSString(path);
-
-    Assembly *pAssembly = AssemblySpec::LoadAssembly(path);
-
-    LOG((LF_CLASSLOADER, 
-         LL_INFO100, 
-         "\tLoaded assembly from a file\n"));
-
-
-    if (pAssembly != NULL)
-        gc.refRetVal = (ASSEMBLYREF) pAssembly->GetExposedObject();
-
-    HELPER_METHOD_FRAME_END();
-
-    return OBJECTREFToObject(gc.refRetVal);
-}
-FCIMPLEND
-
-
 /* static */
 Assembly* AssemblyNative::LoadFromPEImage(ICLRPrivBinder* pBinderContext, PEImage *pILImage, PEImage *pNIImage)
 {
index 514589f..71e8b51 100644 (file)
@@ -46,10 +46,6 @@ public:
     static
     void QCALLTYPE GetExecutingAssembly(QCall::StackCrawlMarkHandle stackMark, QCall::ObjectHandleOnStack retAssembly);
 
-    static FCDECL2(Object*,         LoadFile,                   StringObject* pathUNSAFE,
-                                                                Object* securityUNSAFE);
-    static FCDECL6(Object*,         LoadImage,                  U1Array* PEByteArrayUNSAFE, U1Array* SymByteArrayUNSAFE, Object* securityUNSAFE, StackCrawlMark* stackMark, CLR_BOOL fForIntrospection, SecurityContextSource securityContextSource);
-
     static FCDECL10(Object*,         Load,                       AssemblyNameBaseObject* assemblyNameUNSAFE, 
                                                                 StringObject* codeBaseUNSAFE, 
                                                                 Object* securityUNSAFE, 
@@ -61,9 +57,6 @@ public:
                                                                 CLR_BOOL fSuppressSecurityChecks,
                                                                 INT_PTR ptrLoadContextBinder);
 
-    static FCDECL1(FC_BOOL_RET, IsFrameworkAssembly, AssemblyNameBaseObject* refAssemblyNameUNSAFE);
-    static FCDECL1(FC_BOOL_RET, IsNewPortableAssembly, AssemblyNameBaseObject* refAssemblyNameUNSAFE);
-
     //
     // instance FCALLs
     //
index 9cce46d..c82f7d4 100644 (file)
@@ -693,6 +693,11 @@ void EEStartupHelper(COINITIEE fFlags)
         InitThreadManager();
         STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "Returned successfully from InitThreadManager");
 
+#ifdef FEATURE_PERFTRACING
+        // Initialize the event pipe.
+        EventPipe::Initialize();
+#endif // FEATURE_PERFTRACING
+
 #ifdef FEATURE_EVENT_TRACE        
         // Initialize event tracing early so we can trace CLR startup time events.
         InitializeEventTracing();
@@ -1036,8 +1041,7 @@ void EEStartupHelper(COINITIEE fFlags)
 #endif
 
 #ifdef FEATURE_PERFTRACING
-        // Initialize the event pipe and start it if requested.
-        EventPipe::Initialize();
+        // Start the event pipe if requested.
         EventPipe::EnableOnStartup();
 #endif // FEATURE_PERFTRACING
 
index 6c74377..e3ec0ba 100644 (file)
@@ -2502,6 +2502,17 @@ inline PCODE GetPreStubEntryPoint()
     return GetEEFuncEntryPoint(ThePreStub);
 }
 
+#if defined(HAS_COMPACT_ENTRYPOINTS) && defined(_TARGET_ARM_)
+
+EXTERN_C void STDCALL ThePreStubCompactARM();
+
+inline PCODE GetPreStubCompactARMEntryPoint()
+{
+    return GetEEFuncEntryPoint(ThePreStubCompactARM);
+}
+
+#endif // defined(HAS_COMPACT_ENTRYPOINTS) && defined(_TARGET_ARM_)
+
 PCODE TheUMThunkPreStub();
 
 PCODE TheVarargNDirectStub(BOOL hasRetBuffArg);
index 81bc656..cc6966e 100644 (file)
@@ -594,7 +594,6 @@ FCFuncStart(gAssemblyFuncs)
     QCFuncElement("GetVersion", AssemblyNative::GetVersion)
     FCFuncElement("FCallIsDynamic", AssemblyNative::IsDynamic)
     FCFuncElement("_nLoad", AssemblyNative::Load)
-    FCFuncElement("nLoadImage", AssemblyNative::LoadImage)
     QCFuncElement("GetType", AssemblyNative::GetType)
     QCFuncElement("GetManifestResourceInfo", AssemblyNative::GetManifestResourceInfo)
     QCFuncElement("GetModules", AssemblyNative::GetModules)
index be5fa00..6bd389f 100644 (file)
@@ -1105,6 +1105,98 @@ void EEPolicy::HandleExitProcess(ShutdownCompleteAction sca)
     HandleExitProcessHelper(action, 0, sca);
 }
 
+StackWalkAction LogCallstackForLogCallback(
+    CrawlFrame       *pCF,      //
+    VOID*             pData     // Caller's private data
+)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        SO_INTOLERANT;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    SmallStackSString *pWordAt = ((SmallStackSString*)pData);
+
+    MethodDesc *pMD = pCF->GetFunction();
+    _ASSERTE(pMD != NULL);
+
+    StackSString str;
+    str = *pWordAt;
+
+    TypeString::AppendMethodInternal(str, pMD, TypeString::FormatNamespace|TypeString::FormatFullInst|TypeString::FormatSignature); 
+    PrintToStdErrW(str.GetUnicode());
+    PrintToStdErrA("\n");
+
+    return SWA_CONTINUE;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// A worker to save managed stack trace.
+//
+// Arguments:
+//    reporter - EventReporter object for EventLog
+//
+// Return Value:
+//    None
+//
+inline void LogCallstackForLogWorker()
+{
+    Thread* pThread = GetThread();
+    _ASSERTE (pThread);
+
+    SmallStackSString WordAt;
+
+    if (!WordAt.LoadResource(CCompRC::Optional, IDS_ER_WORDAT))
+    {
+        WordAt.Set(W("   at"));
+    }
+    else
+    {
+        WordAt.Insert(WordAt.Begin(), W("   "));
+    }
+    WordAt += W(" ");
+
+    pThread->StackWalkFrames(&LogCallstackForLogCallback, &WordAt, QUICKUNWIND | FUNCTIONSONLY);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Generate an EventLog entry for unhandled exception.
+//
+// Arguments:
+//    pExceptionInfo - Exception information
+//
+// Return Value:
+//    None
+//
+inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo)
+{
+    WRAPPER_NO_CONTRACT;
+
+    Thread *pThread = GetThread();
+    EX_TRY
+    {
+        PrintToStdErrA("FailFast: ");
+        PrintToStdErrW((WCHAR*)pszMessage);
+        PrintToStdErrA("\n");
+
+        if (pThread)
+        {
+            PrintToStdErrA("\n");
+            LogCallstackForLogWorker();
+        }
+    }
+    EX_CATCH
+    {
+    }
+    EX_END_CATCH(SwallowAllExceptions)
+}
+
 //
 // Log an error to the event log if possible, then throw up a dialog box.
 //
@@ -1117,6 +1209,12 @@ void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage
 
     _ASSERTE(pExceptionInfo != NULL);
 
+    // Log FailFast exception to StdErr
+    if (exitCode == (UINT)COR_E_FAILFAST)
+    {
+        DoLogForFailFastException(pszMessage, pExceptionInfo);
+    }
+
     if(ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, FailFast))
     {
         // Fire an ETW FailFast event
index 98d382e..8ea3f08 100644 (file)
@@ -4,21 +4,46 @@
 
 #include "common.h"
 #include "eventpipe.h"
+#include "eventpipeconfiguration.h"
+#include "eventpipeevent.h"
+#include "eventpipefile.h"
+#include "eventpipeprovider.h"
 #include "eventpipejsonfile.h"
 #include "sampleprofiler.h"
 
-CrstStatic EventPipe::s_initCrst;
+#ifdef FEATURE_PAL
+#include "pal.h"
+#endif // FEATURE_PAL
+
+#ifdef FEATURE_PERFTRACING
+
+CrstStatic EventPipe::s_configCrst;
 bool EventPipe::s_tracingInitialized = false;
-bool EventPipe::s_tracingEnabled = false;
+EventPipeConfiguration* EventPipe::s_pConfig = NULL;
+EventPipeFile* EventPipe::s_pFile = NULL;
 EventPipeJsonFile* EventPipe::s_pJsonFile = NULL;
 
+#ifdef FEATURE_PAL
+// This function is auto-generated from /src/scripts/genEventPipe.py
+extern "C" void InitProvidersAndEvents();
+#endif
+
 void EventPipe::Initialize()
 {
     STANDARD_VM_CONTRACT;
 
-    s_tracingInitialized = s_initCrst.InitNoThrow(
+    s_tracingInitialized = s_configCrst.InitNoThrow(
         CrstEventPipe,
-        (CrstFlags)(CRST_TAKEN_DURING_SHUTDOWN));
+        (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
+
+    s_pConfig = new EventPipeConfiguration();
+    s_pConfig->Initialize();
+
+#ifdef FEATURE_PAL
+    // This calls into auto-generated code to initialize the runtime providers
+    // and events so that the EventPipe configuration lock isn't taken at runtime
+    InitProvidersAndEvents();
+#endif
 }
 
 void EventPipe::EnableOnStartup()
@@ -66,9 +91,14 @@ void EventPipe::Enable()
         return;
     }
 
-    // Take the lock and enable tracing.
-    CrstHolder _crst(&s_initCrst);
-    s_tracingEnabled = true;
+    // Take the lock before enabling tracing.
+    CrstHolder _crst(GetLock());
+
+    // Create the event pipe file.
+    SString eventPipeFileOutputPath;
+    eventPipeFileOutputPath.Printf("Process-%d.netperf", GetCurrentProcessId());
+    s_pFile = new EventPipeFile(eventPipeFileOutputPath);
+
     if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) == 2)
     {
         // File placed in current working directory.
@@ -77,7 +107,14 @@ void EventPipe::Enable()
         s_pJsonFile = new EventPipeJsonFile(outputFilePath);
     }
 
+    // Enable tracing.
+    s_pConfig->Enable();
+
+    // Enable the sample profiler
     SampleProfiler::Enable();
+
+    // TODO: Iterate through the set of providers, enable them as appropriate.
+    // This in-turn will iterate through all of the events and set their isEnabled bits.
 }
 
 void EventPipe::Disable()
@@ -90,32 +127,38 @@ void EventPipe::Disable()
     }
     CONTRACTL_END;
 
-    CrstHolder _crst(&s_initCrst);
-    s_tracingEnabled = false;
+    // Don't block GC during clean-up.
+    GCX_PREEMP();
+
+    // Take the lock before disabling tracing.
+    CrstHolder _crst(GetLock());
+
+    // Disable the profiler.
     SampleProfiler::Disable();
 
+    // Disable tracing.
+    s_pConfig->Disable();
+
     if(s_pJsonFile != NULL)
     {
         delete(s_pJsonFile);
         s_pJsonFile = NULL;
     }
-}
 
-bool EventPipe::EventEnabled(GUID& providerID, INT64 keyword)
-{
-    CONTRACTL
+    if(s_pFile != NULL)
     {
-        NOTHROW;
-        GC_NOTRIGGER;
-        MODE_ANY;
+        delete(s_pFile);
+        s_pFile = NULL;
     }
-    CONTRACTL_END;
 
-    // TODO: Implement filtering.
-    return false;
+    if(s_pConfig != NULL)
+    {
+        delete(s_pConfig);
+        s_pConfig = NULL;
+    }
 }
 
-void EventPipe::WriteEvent(GUID& providerID, INT64 eventID, BYTE *pData, size_t length, bool sampleStack)
+void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length)
 {
     CONTRACTL
     {
@@ -125,41 +168,53 @@ void EventPipe::WriteEvent(GUID& providerID, INT64 eventID, BYTE *pData, size_t
     }
     CONTRACTL_END;
 
-    StackContents stackContents;
-    bool stackWalkSucceeded;
-
-    if(sampleStack)
+    // Exit early if the event is not enabled.
+    if(!event.IsEnabled())
     {
-        stackWalkSucceeded = WalkManagedStackForCurrentThread(stackContents);
+        return;
     }
 
-    // TODO: Write the event.
+    DWORD threadID = GetCurrentThreadId();
+
+    // Create an instance of the event.
+    EventPipeEventInstance instance(
+        event,
+        threadID,
+        pData,
+        length);
+
+    // Write to the EventPipeFile.
+    _ASSERTE(s_pFile != NULL);
+    s_pFile->WriteEvent(instance);
+
+    // Write to the EventPipeJsonFile if it exists.
+    if(s_pJsonFile != NULL)
+    {
+        s_pJsonFile->WriteEvent(instance);
+    }
 }
 
-void EventPipe::WriteSampleProfileEvent(Thread *pThread, StackContents &stackContents)
+void EventPipe::WriteSampleProfileEvent(SampleProfilerEventInstance &instance)
 {
     CONTRACTL
     {
         NOTHROW;
         GC_TRIGGERS;
         MODE_PREEMPTIVE;
-        PRECONDITION(pThread != NULL);
     }
     CONTRACTL_END;
 
-    EX_TRY
+    // Write to the EventPipeFile.
+    if(s_pFile != NULL)
     {
-        if(s_pJsonFile != NULL)
-        {
-            CommonEventFields eventFields;
-            QueryPerformanceCounter(&eventFields.TimeStamp);
-            eventFields.ThreadID = pThread->GetOSThreadId();
+        s_pFile->WriteEvent(instance);
+    }
 
-            static SString message(W("THREAD_TIME"));
-            s_pJsonFile->WriteEvent(eventFields, message, stackContents);
-        }
+    // Write to the EventPipeJsonFile if it exists.
+    if(s_pJsonFile != NULL)
+    {
+        s_pJsonFile->WriteEvent(instance);
     }
-    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
 }
 
 bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
@@ -173,8 +228,12 @@ bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
     CONTRACTL_END;
 
     Thread *pThread = GetThread();
-    _ASSERTE(pThread != NULL);
-    return WalkManagedStackForThread(pThread, stackContents);
+    if(pThread != NULL)
+    {
+        return WalkManagedStackForThread(pThread, stackContents);
+    }
+
+    return false;
 }
 
 bool EventPipe::WalkManagedStackForThread(Thread *pThread, StackContents &stackContents)
@@ -232,3 +291,19 @@ StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pDa
     // Continue the stack walk.
     return SWA_CONTINUE;
 }
+
+EventPipeConfiguration* EventPipe::GetConfiguration()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return s_pConfig;
+}
+
+CrstStatic* EventPipe::GetLock()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return &s_configCrst;
+}
+
+#endif // FEATURE_PERFTRACING
index 2978412..c6d7f61 100644 (file)
@@ -5,19 +5,17 @@
 #ifndef __EVENTPIPE_H__
 #define __EVENTPIPE_H__
 
-#include "common.h"
+#ifdef FEATURE_PERFTRACING
 
-class EventPipeJsonFile;
-
-// The data fields common to every event.
-struct CommonEventFields
-{
-    // Timestamp generated by QueryPerformanceCounter.
-    LARGE_INTEGER TimeStamp;
+#include "crst.h"
+#include "stackwalk.h"
 
-    // Thread ID.
-    DWORD ThreadID;
-};
+class EventPipeConfiguration;
+class EventPipeEvent;
+class EventPipeFile;
+class EventPipeJsonFile;
+class MethodDesc;
+class SampleProfilerEventInstance;
 
 class StackContents
 {
@@ -103,10 +101,30 @@ public:
             m_nextAvailableFrame++;
         }
     }
+
+    BYTE* GetPointer() const
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        return (BYTE*)m_stackFrames;
+    }
+
+    unsigned int GetSize() const
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        return (m_nextAvailableFrame * sizeof(UINT_PTR));
+    }
 };
 
 class EventPipe
 {
+    // Declare friends.
+    friend class EventPipeConfiguration;
+    friend class EventPipeFile;
+    friend class EventPipeProvider;
+    friend class SampleProfiler;
+
     public:
 
         // Initialize the event pipe.
@@ -124,15 +142,12 @@ class EventPipe
         // Disable tracing via the event pipe.
         static void Disable();
 
-        // Determine whether or not the specified provider/keyword combination is enabled.
-        static bool EventEnabled(GUID& providerID, INT64 keyword);
-
-        // Write out an event.  The event is identified by the providerID/eventID pair.
+        // Write out an event.
         // Data is written as a serialized blob matching the ETW serialization conventions.
-        static void WriteEvent(GUID& providerID, INT64 eventID, BYTE *pData, size_t length, bool sampleStack);
+        static void WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length);
 
-        // Write out a sample profile event with the specified stack.
-        static void WriteSampleProfileEvent(Thread *pThread, StackContents &stackContents);
+        // Write out a sample profile event.
+        static void WriteSampleProfileEvent(SampleProfilerEventInstance &instance);
         
         // Get the managed call stack for the current thread.
         static bool WalkManagedStackForCurrentThread(StackContents &stackContents);
@@ -145,10 +160,20 @@ class EventPipe
         // Callback function for the stack walker.  For each frame walked, this callback is invoked.
         static StackWalkAction StackWalkCallback(CrawlFrame *pCf, StackContents *pData);
 
-        static CrstStatic s_initCrst;
+        // Get the configuration object.
+        // This is called directly by the EventPipeProvider constructor to register the new provider.
+        static EventPipeConfiguration* GetConfiguration();
+
+        // Get the event pipe configuration lock.
+        static CrstStatic* GetLock();
+
+        static CrstStatic s_configCrst;
         static bool s_tracingInitialized;
-        static bool s_tracingEnabled;
+        static EventPipeConfiguration *s_pConfig;
+        static EventPipeFile *s_pFile;
         static EventPipeJsonFile *s_pJsonFile;
 };
 
+#endif // FEATURE_PERFTRACING
+
 #endif // __EVENTPIPE_H__
diff --git a/src/vm/eventpipeconfiguration.cpp b/src/vm/eventpipeconfiguration.cpp
new file mode 100644 (file)
index 0000000..cfb96fc
--- /dev/null
@@ -0,0 +1,271 @@
+// 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.
+
+#include "common.h"
+#include "eventpipe.h"
+#include "eventpipeconfiguration.h"
+#include "eventpipeeventinstance.h"
+#include "eventpipeprovider.h"
+
+#ifdef FEATURE_PERFTRACING
+
+// {5291C09C-2660-4D6A-83A3-C383FD020DEC}
+const GUID EventPipeConfiguration::s_configurationProviderID =
+    { 0x5291c09c, 0x2660, 0x4d6a, { 0x83, 0xa3, 0xc3, 0x83, 0xfd, 0x2, 0xd, 0xec } };
+
+EventPipeConfiguration::EventPipeConfiguration()
+{
+    STANDARD_VM_CONTRACT;
+
+    m_pProviderList = new SList<SListElem<EventPipeProvider*>>();
+}
+
+EventPipeConfiguration::~EventPipeConfiguration()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    if(m_pProviderList != NULL)
+    {
+        delete(m_pProviderList);
+        m_pProviderList = NULL;
+    }
+}
+
+void EventPipeConfiguration::Initialize()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Create the configuration provider.
+    m_pConfigProvider = new EventPipeProvider(s_configurationProviderID);
+
+    // Create the metadata event.
+    m_pMetadataEvent = m_pConfigProvider->AddEvent(
+        0,      /* keywords */
+        0,      /* eventID */
+        0,      /* eventVersion */
+        EventPipeEventLevel::Critical,
+        false); /* needStack */
+}
+
+bool EventPipeConfiguration::RegisterProvider(EventPipeProvider &provider)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Take the lock before manipulating the provider list.
+    CrstHolder _crst(EventPipe::GetLock());
+
+    // See if we've already registered this provider.
+    EventPipeProvider *pExistingProvider = GetProviderNoLock(provider.GetProviderID());
+    if(pExistingProvider != NULL)
+    {
+        return false;
+    }
+
+    // The provider has not been registered, so register it.
+    m_pProviderList->InsertTail(new SListElem<EventPipeProvider*>(&provider));
+
+    // TODO: Set the provider configuration and enable it if we know
+    // anything about the provider before it is registered.
+
+    return true;
+}
+
+bool EventPipeConfiguration::UnregisterProvider(EventPipeProvider &provider)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Take the lock before manipulating the provider list.
+    CrstHolder _crst(EventPipe::GetLock());
+
+    // Find the provider.
+    SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
+    while(pElem != NULL)
+    {
+        if(pElem->GetValue() == &provider)
+        {
+            break;
+        }
+
+        pElem = m_pProviderList->GetNext(pElem);
+    }
+
+    // If we found the provider, remove it.
+    if(pElem != NULL)
+    {
+        if(m_pProviderList->FindAndRemove(pElem) != NULL)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+EventPipeProvider* EventPipeConfiguration::GetProvider(const GUID &providerID)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Take the lock before touching the provider list to ensure no one tries to
+    // modify the list.
+    CrstHolder _crst(EventPipe::GetLock());
+
+    return GetProviderNoLock(providerID);
+}
+
+EventPipeProvider* EventPipeConfiguration::GetProviderNoLock(const GUID &providerID)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+    }
+    CONTRACTL_END;
+
+    SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
+    while(pElem != NULL)
+    {
+        EventPipeProvider *pProvider = pElem->GetValue();
+        if(pProvider->GetProviderID() == providerID)
+        {
+            return pProvider;
+        }
+
+        pElem = m_pProviderList->GetNext(pElem);
+    }
+
+    return NULL;
+}
+
+void EventPipeConfiguration::Enable()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+        // Lock must be held by EventPipe::Enable.
+        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+    }
+    CONTRACTL_END;
+
+    SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
+    while(pElem != NULL)
+    {
+        // TODO: Only enable the providers that have been explicitly enabled with specified keywords/level.
+        EventPipeProvider *pProvider = pElem->GetValue();
+        pProvider->SetConfiguration(true /* providerEnabled */, 0xFFFFFFFFFFFFFFFF /* keywords */, EventPipeEventLevel::Verbose /* level */);
+
+        pElem = m_pProviderList->GetNext(pElem);
+    }
+
+}
+
+void EventPipeConfiguration::Disable()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+        // Lock must be held by EventPipe::Disable.
+        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+    }
+    CONTRACTL_END;
+
+    SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
+    while(pElem != NULL)
+    {
+        EventPipeProvider *pProvider = pElem->GetValue();
+        pProvider->SetConfiguration(false /* providerEnabled */, 0 /* keywords */, EventPipeEventLevel::Critical /* level */);
+
+        pElem = m_pProviderList->GetNext(pElem);
+    }
+}
+
+EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEvent &sourceEvent, BYTE *pPayloadData, unsigned int payloadLength)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // The payload of the event should contain:
+    // - GUID ProviderID.
+    // - unsigned int EventID.
+    // - unsigned int EventVersion.
+    // - Optional event description payload.
+
+    // Calculate the size of the event.
+    const GUID &providerID = sourceEvent.GetProvider()->GetProviderID();
+    unsigned int eventID = sourceEvent.GetEventID();
+    unsigned int eventVersion = sourceEvent.GetEventVersion();
+    unsigned int instancePayloadSize = sizeof(providerID) + sizeof(eventID) + sizeof(eventVersion) + payloadLength;
+
+    // Allocate the payload.
+    BYTE *pInstancePayload = new BYTE[instancePayloadSize];
+
+    // Fill the buffer with the payload.
+    BYTE *currentPtr = pInstancePayload;
+
+    // Write the provider ID.
+    memcpy(currentPtr, (BYTE*)&providerID, sizeof(providerID));
+    currentPtr += sizeof(providerID);
+
+    // Write the event ID.
+    memcpy(currentPtr, &eventID, sizeof(eventID));
+    currentPtr += sizeof(eventID);
+
+    // Write the event version.
+    memcpy(currentPtr, &eventVersion, sizeof(eventVersion));
+    currentPtr += sizeof(eventVersion);
+
+    // Write the incoming payload data.
+    memcpy(currentPtr, pPayloadData, payloadLength);
+
+    // Construct the event instance.
+    EventPipeEventInstance *pInstance = new EventPipeEventInstance(
+        *m_pMetadataEvent,
+        GetCurrentThreadId(),
+        pInstancePayload,
+        instancePayloadSize);
+
+    return pInstance;
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipeconfiguration.h b/src/vm/eventpipeconfiguration.h
new file mode 100644 (file)
index 0000000..a237775
--- /dev/null
@@ -0,0 +1,64 @@
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __EVENTPIPE_CONFIGURATION_H__
+#define __EVENTPIPE_CONFIGURATION_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "slist.h"
+
+class EventPipeEvent;
+class EventPipeEventInstance;
+class EventPipeProvider;
+
+class EventPipeConfiguration
+{
+public:
+
+    EventPipeConfiguration();
+    ~EventPipeConfiguration();
+
+    // Perform initialization that cannot be performed in the constructor.
+    void Initialize();
+
+    // Register a provider.
+    bool RegisterProvider(EventPipeProvider &provider);
+
+    // Unregister a provider.
+    bool UnregisterProvider(EventPipeProvider &provider);
+
+    // Get the provider with the specified provider ID if it exists.
+    EventPipeProvider* GetProvider(const GUID &providerID);
+
+    // Enable the event pipe.
+    void Enable();
+
+    // Disable the event pipe.
+    void Disable();
+
+    // Get the event used to write metadata to the event stream.
+    EventPipeEventInstance* BuildEventMetadataEvent(EventPipeEvent &sourceEvent, BYTE *pPayloadData = NULL, unsigned int payloadLength = 0);
+
+private:
+
+    // Get the provider without taking the lock.
+    EventPipeProvider* GetProviderNoLock(const GUID &providerID);
+
+    // The list of event pipe providers.
+    SList<SListElem<EventPipeProvider*>> *m_pProviderList;
+
+    // The provider used to write configuration events to the event stream.
+    EventPipeProvider *m_pConfigProvider;
+
+    // The event used to write event information to the event stream.
+    EventPipeEvent *m_pMetadataEvent;
+
+    // The provider ID for the configuration event pipe provider.
+    // This provider is used to emit configuration events.
+    static const GUID s_configurationProviderID;
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_CONFIGURATION_H__
diff --git a/src/vm/eventpipeevent.cpp b/src/vm/eventpipeevent.cpp
new file mode 100644 (file)
index 0000000..3b9f36b
--- /dev/null
@@ -0,0 +1,86 @@
+// 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.
+
+#include "common.h"
+#include "eventpipeevent.h"
+#include "eventpipeprovider.h"
+
+#ifdef FEATURE_PERFTRACING
+
+EventPipeEvent::EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    m_pProvider = &provider;
+    m_keywords = keywords;
+    m_eventID = eventID;
+    m_eventVersion = eventVersion;
+    m_level = level;
+    m_needStack = needStack;
+    m_enabled = false;
+}
+
+EventPipeProvider* EventPipeEvent::GetProvider() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_pProvider;
+}
+
+INT64 EventPipeEvent::GetKeywords() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_keywords;
+}
+
+unsigned int EventPipeEvent::GetEventID() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_eventID;
+}
+
+unsigned int EventPipeEvent::GetEventVersion() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_eventVersion;
+}
+
+EventPipeEventLevel EventPipeEvent::GetLevel() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_level;
+}
+
+bool EventPipeEvent::NeedStack() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_needStack;
+}
+
+bool EventPipeEvent::IsEnabled() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_enabled;
+}
+
+void EventPipeEvent::RefreshState()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    m_enabled = m_pProvider->EventEnabled(m_keywords, m_level);
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipeevent.h b/src/vm/eventpipeevent.h
new file mode 100644 (file)
index 0000000..9e42615
--- /dev/null
@@ -0,0 +1,74 @@
+// 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.
+
+#ifndef __EVENTPIPE_EVENT_H__
+#define __EVENTPIPE_EVENT_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "eventpipeprovider.h"
+
+class EventPipeEvent
+{
+    // Declare friends.
+    friend class EventPipeProvider;
+
+private:
+
+    // The provider that contains the event.
+    EventPipeProvider *m_pProvider;
+
+    // Bit vector containing the keywords that enable the event.
+    INT64 m_keywords;
+
+    // The ID (within the provider) of the event.
+    unsigned int m_eventID;
+
+    // The version of the event.
+    unsigned int m_eventVersion;
+
+    // The verbosity of the event.
+    EventPipeEventLevel m_level;
+
+    // True if a call stack should be captured when writing the event.
+    bool m_needStack;
+
+    // True if the event is current enabled.
+    bool m_enabled;
+
+    // Refreshes the runtime state for this event.
+    // Called by EventPipeProvider when the provider configuration changes.
+    void RefreshState();
+
+    // Only EventPipeProvider can create events.
+    // The provider is responsible for allocating and freeing events.
+    EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack);
+
+public:
+
+    // Get the provider associated with this event.
+    EventPipeProvider* GetProvider() const;
+
+    // Get the keywords that enable the event.
+    INT64 GetKeywords() const;
+
+    // Get the ID (within the provider) of the event.
+    unsigned int GetEventID() const;
+
+    // Get the version of the event.
+    unsigned int GetEventVersion() const;
+
+    // Get the verbosity of the event.
+    EventPipeEventLevel GetLevel() const;
+
+    // True if a call stack should be captured when writing the event.
+    bool NeedStack() const;
+
+    // True if the event is currently enabled.
+    bool IsEnabled() const;
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_EVENT_H__
diff --git a/src/vm/eventpipeeventinstance.cpp b/src/vm/eventpipeeventinstance.cpp
new file mode 100644 (file)
index 0000000..2bf500b
--- /dev/null
@@ -0,0 +1,157 @@
+// 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.
+
+#include "common.h"
+#include "eventpipeeventinstance.h"
+#include "eventpipejsonfile.h"
+#include "fastserializer.h"
+#include "sampleprofiler.h"
+
+#ifdef FEATURE_PERFTRACING
+
+EventPipeEventInstance::EventPipeEventInstance(
+    EventPipeEvent &event,
+    DWORD threadID,
+    BYTE *pData,
+    unsigned int length)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    m_pEvent = &event;
+    m_threadID = threadID;
+    m_pData = pData;
+    m_dataLength = length;
+    QueryPerformanceCounter(&m_timeStamp);
+
+    if(event.NeedStack())
+    {
+        EventPipe::WalkManagedStackForCurrentThread(m_stackContents);
+    }
+}
+
+StackContents* EventPipeEventInstance::GetStack()
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return &m_stackContents;
+}
+
+EventPipeEvent* EventPipeEventInstance::GetEvent() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_pEvent;
+}
+
+BYTE* EventPipeEventInstance::GetData() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_pData;
+}
+
+unsigned int EventPipeEventInstance::GetLength() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_dataLength;
+}
+
+void EventPipeEventInstance::FastSerialize(FastSerializer *pSerializer, StreamLabel metadataLabel)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+#ifdef _DEBUG
+    // Useful for diagnosing serialization bugs.
+    const unsigned int value = 0xDEADBEEF;
+    pSerializer->WriteBuffer((BYTE*)&value, sizeof(value));
+#endif
+
+    // Calculate the size of the total payload so that it can be written to the file.
+    unsigned int payloadLength =
+        sizeof(metadataLabel) +
+        sizeof(m_threadID) +        // Thread ID
+        sizeof(m_timeStamp) +       // TimeStamp
+        m_dataLength +              // Event payload data length
+        m_stackContents.GetSize();  // Stack payload size
+
+    // Write the size of the event to the file.
+    pSerializer->WriteBuffer((BYTE*)&payloadLength, sizeof(payloadLength));
+
+    // Write the metadata label.
+    pSerializer->WriteBuffer((BYTE*)&metadataLabel, sizeof(metadataLabel));
+
+    // Write the thread ID.
+    pSerializer->WriteBuffer((BYTE*)&m_threadID, sizeof(m_threadID));
+
+    // Write the timestamp.
+    pSerializer->WriteBuffer((BYTE*)&m_timeStamp, sizeof(m_timeStamp));
+
+    // Write the event data payload.
+    if(m_dataLength > 0)
+    {
+        pSerializer->WriteBuffer(m_pData, m_dataLength);
+    }
+
+    // Write the stack if present.
+    if(m_stackContents.GetSize() > 0)
+    {
+        pSerializer->WriteBuffer(m_stackContents.GetPointer(), m_stackContents.GetSize());
+    }
+}
+
+void EventPipeEventInstance::SerializeToJsonFile(EventPipeJsonFile *pFile)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    if(pFile == NULL)
+    {
+        return;
+    }
+
+    EX_TRY
+    {
+        const unsigned int guidSize = 39;
+        WCHAR wszProviderID[guidSize];
+        if(!StringFromGUID2(m_pEvent->GetProvider()->GetProviderID(), wszProviderID, guidSize))
+        {
+            wszProviderID[0] = '\0';
+        }
+
+        // Strip off the {}.
+        StackScratchBuffer scratch;
+        SString guidStr(&wszProviderID[1], guidSize-3);
+
+        SString message;
+        message.Printf("Provider=%s/EventID=%d/Version=%d", guidStr.GetANSI(scratch), m_pEvent->GetEventID(), m_pEvent->GetEventVersion());
+        pFile->WriteEvent(m_timeStamp, m_threadID, message, m_stackContents);
+    }
+    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
+}
+
+SampleProfilerEventInstance::SampleProfilerEventInstance(Thread *pThread)
+    :EventPipeEventInstance(*SampleProfiler::s_pThreadTimeEvent, pThread->GetOSThreadId(), NULL, 0)
+{
+    LIMITED_METHOD_CONTRACT;
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipeeventinstance.h b/src/vm/eventpipeeventinstance.h
new file mode 100644 (file)
index 0000000..84ad566
--- /dev/null
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef __EVENTPIPE_EVENTINSTANCE_H__
+#define __EVENTPIPE_EVENTINSTANCE_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "eventpipe.h"
+#include "eventpipeevent.h"
+#include "fastserializableobject.h"
+#include "fastserializer.h"
+
+class EventPipeEventInstance
+{
+
+public:
+
+    EventPipeEventInstance(EventPipeEvent &event, DWORD threadID, BYTE *pData, unsigned int length);
+
+    // Get the event associated with this instance.
+    EventPipeEvent* GetEvent() const;
+
+    // Get the stack contents object to either read or write to it.
+    StackContents* GetStack();
+
+    // Get a pointer to the data payload.
+    BYTE* GetData() const;
+
+    // Get the length of the data.
+    unsigned int GetLength() const;
+
+    // Serialize this object using FastSerialization.
+    void FastSerialize(FastSerializer *pSerializer, StreamLabel metadataLabel);
+
+    // Serialize this event to the JSON file.
+    void SerializeToJsonFile(EventPipeJsonFile *pFile);
+
+protected:
+
+    EventPipeEvent *m_pEvent;
+    DWORD m_threadID;
+    LARGE_INTEGER m_timeStamp;
+
+    BYTE *m_pData;
+    unsigned int m_dataLength;
+    StackContents m_stackContents;
+};
+
+// A specific type of event instance for use by the SampleProfiler.
+// This is needed because the SampleProfiler knows how to walk stacks belonging
+// to threads other than the current thread.
+class SampleProfilerEventInstance : public EventPipeEventInstance
+{
+
+public:
+
+    SampleProfilerEventInstance(Thread *pThread);
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_EVENTINSTANCE_H__
diff --git a/src/vm/eventpipefile.cpp b/src/vm/eventpipefile.cpp
new file mode 100644 (file)
index 0000000..895f732
--- /dev/null
@@ -0,0 +1,146 @@
+// 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.
+
+#include "common.h"
+#include "eventpipeconfiguration.h"
+#include "eventpipefile.h"
+
+#ifdef FEATURE_PERFTRACING
+
+EventPipeFile::EventPipeFile(SString &outputFilePath)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    m_pSerializer = new FastSerializer(outputFilePath, *this);
+    m_serializationLock.Init(LOCK_TYPE_DEFAULT);
+    m_pMetadataLabels = new MapSHashWithRemove<EventPipeEvent*, StreamLabel>();
+
+    // File start time information.
+    GetSystemTime(&m_fileOpenSystemTime);
+    QueryPerformanceCounter(&m_fileOpenTimeStamp);
+    QueryPerformanceFrequency(&m_timeStampFrequency);
+
+    // Write a forward reference to the beginning of the event stream.
+    // This also allows readers to know where the event stream ends and skip it if needed.
+    m_beginEventsForwardReferenceIndex = m_pSerializer->AllocateForwardReference();
+    m_pSerializer->WriteForwardReference(m_beginEventsForwardReferenceIndex);
+
+    // Write the header information into the file.
+
+    // Write the current date and time.
+    m_pSerializer->WriteBuffer((BYTE*)&m_fileOpenSystemTime, sizeof(m_fileOpenSystemTime));
+
+    // Write FileOpenTimeStamp
+    m_pSerializer->WriteBuffer((BYTE*)&m_fileOpenTimeStamp, sizeof(m_fileOpenTimeStamp));
+
+    // Write ClockFrequency
+    m_pSerializer->WriteBuffer((BYTE*)&m_timeStampFrequency, sizeof(m_timeStampFrequency));
+}
+
+EventPipeFile::~EventPipeFile()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Mark the end of the event stream.
+    StreamLabel currentLabel = m_pSerializer->GetStreamLabel();
+
+    // Define the event start forward reference.
+    m_pSerializer->DefineForwardReference(m_beginEventsForwardReferenceIndex, currentLabel);
+
+    // Close the serializer.
+    if(m_pSerializer != NULL)
+    {
+        delete(m_pSerializer);
+        m_pSerializer = NULL;
+    }
+}
+
+void EventPipeFile::WriteEvent(EventPipeEventInstance &instance)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Take the serialization lock.
+    SpinLockHolder _slh(&m_serializationLock);
+
+    // Check to see if we've seen this event type before.
+    // If not, then write the event metadata to the event stream first.
+    StreamLabel metadataLabel = GetMetadataLabel(*instance.GetEvent());
+    if(metadataLabel == 0)
+    {
+        EventPipeEventInstance* pMetadataInstance = EventPipe::GetConfiguration()->BuildEventMetadataEvent(*instance.GetEvent());
+
+        metadataLabel = m_pSerializer->GetStreamLabel();
+        pMetadataInstance->FastSerialize(m_pSerializer, (StreamLabel)0); // 0 breaks recursion and represents the metadata event.
+
+        SaveMetadataLabel(*instance.GetEvent(), metadataLabel);
+
+        delete (pMetadataInstance->GetData());
+        delete (pMetadataInstance);
+    }
+
+    // Write the event to the stream.
+    instance.FastSerialize(m_pSerializer, metadataLabel);
+}
+
+StreamLabel EventPipeFile::GetMetadataLabel(EventPipeEvent &event)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    StreamLabel outLabel;
+    if(m_pMetadataLabels->Lookup(&event, &outLabel))
+    {
+        _ASSERTE(outLabel != 0);
+        return outLabel;
+    }
+
+    return 0;
+}
+
+void EventPipeFile::SaveMetadataLabel(EventPipeEvent &event, StreamLabel label)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+        PRECONDITION(label > 0);
+    }
+    CONTRACTL_END;
+
+    // If a pre-existing metadata label exists, remove it.
+    StreamLabel outLabel;
+    if(m_pMetadataLabels->Lookup(&event, &outLabel))
+    {
+        m_pMetadataLabels->Remove(&event);
+    }
+
+    // Add the metadata label.
+    m_pMetadataLabels->Add(&event, label);
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipefile.h b/src/vm/eventpipefile.h
new file mode 100644 (file)
index 0000000..1fbb4c0
--- /dev/null
@@ -0,0 +1,75 @@
+// 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.
+
+
+#ifndef __EVENTPIPE_FILE_H__
+#define __EVENTPIPE_FILE_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "eventpipe.h"
+#include "eventpipeeventinstance.h"
+#include "fastserializableobject.h"
+#include "fastserializer.h"
+
+class EventPipeFile : public FastSerializableObject
+{
+    public:
+        EventPipeFile(SString &outputFilePath);
+        ~EventPipeFile();
+
+        // Write an event to the file.
+        void WriteEvent(EventPipeEventInstance &instance);
+
+        // Serialize this object.
+        // Not supported - this is the entry object for the trace,
+        // which means that the contents hasn't yet been created.
+        void FastSerialize(FastSerializer *pSerializer)
+        {
+            LIMITED_METHOD_CONTRACT;
+            _ASSERTE(!"This function should never be called!");
+        }
+
+        // Get the type name of this object.
+        const char* GetTypeName()
+        {
+            LIMITED_METHOD_CONTRACT;
+            return "Microsoft.DotNet.Runtime.EventPipeFile";
+        }
+
+    private:
+
+        // Get the metadata address in the file for an event.
+        // The return value can be written into the file as a back-pointer to the event metadata.
+        StreamLabel GetMetadataLabel(EventPipeEvent &event);
+
+        // Save the metadata address in the file for an event.
+        void SaveMetadataLabel(EventPipeEvent &event, StreamLabel label);
+
+        // The object responsible for serialization.
+        FastSerializer *m_pSerializer;
+
+        // The system time when the file was opened.
+        SYSTEMTIME m_fileOpenSystemTime;
+
+        // The timestamp when the file was opened.  Used for calculating file-relative timestamps.
+        LARGE_INTEGER m_fileOpenTimeStamp;
+
+        // The frequency of the timestamps used for this file.
+        LARGE_INTEGER m_timeStampFrequency;
+
+        // The forward reference index that marks the beginning of the event stream.
+        unsigned int m_beginEventsForwardReferenceIndex;
+
+        // The serialization which is responsible for making sure only a single event
+        // or block of events gets written to the file at once.
+        SpinLock m_serializationLock;
+
+        // Hashtable of metadata labels.
+        MapSHashWithRemove<EventPipeEvent*, StreamLabel> *m_pMetadataLabels;
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_FILE_H__
index 6353c91..ea2dd29 100644 (file)
@@ -5,6 +5,8 @@
 #include "common.h"
 #include "eventpipejsonfile.h"
 
+#ifdef FEATURE_PERFTRACING
+
 EventPipeJsonFile::EventPipeJsonFile(SString &outFilePath)
 {
     CONTRACTL
@@ -15,6 +17,7 @@ EventPipeJsonFile::EventPipeJsonFile(SString &outFilePath)
     }
     CONTRACTL_END;
 
+    m_writeErrorEncountered = false;
     m_pFileStream = new CFileStream();
     if(FAILED(m_pFileStream->OpenForWrite(outFilePath)))
     {
@@ -52,7 +55,14 @@ EventPipeJsonFile::~EventPipeJsonFile()
     }
 }
 
-void EventPipeJsonFile::WriteEvent(CommonEventFields &commonFields, SString &message, StackContents &stackContents)
+void EventPipeJsonFile::WriteEvent(EventPipeEventInstance &instance)
+{
+    STANDARD_VM_CONTRACT;
+
+    instance.SerializeToJsonFile(this);
+}
+
+void EventPipeJsonFile::WriteEvent(LARGE_INTEGER timeStamp, DWORD threadID, SString &message, StackContents &stackContents)
 {
     STANDARD_VM_CONTRACT;
 
@@ -67,16 +77,16 @@ void EventPipeJsonFile::WriteEvent(CommonEventFields &commonFields, SString &mes
 
     // Convert the timestamp from a QPC value to a trace-relative timestamp.
     double millisecondsSinceTraceStart = 0.0;
-    if(commonFields.TimeStamp.QuadPart != m_fileOpenTimeStamp.QuadPart)
+    if(timeStamp.QuadPart != m_fileOpenTimeStamp.QuadPart)
     {
         LARGE_INTEGER elapsedNanoseconds;
-        elapsedNanoseconds.QuadPart = commonFields.TimeStamp.QuadPart - m_fileOpenTimeStamp.QuadPart;
+        elapsedNanoseconds.QuadPart = timeStamp.QuadPart - m_fileOpenTimeStamp.QuadPart;
         millisecondsSinceTraceStart = elapsedNanoseconds.QuadPart / 1000000.0;
     }
 
     StackScratchBuffer scratch;
     SString threadFrame;
-    threadFrame.Printf("Thread (%d)", commonFields.ThreadID);
+    threadFrame.Printf("Thread (%d)", threadID);
     SString event;
     event.Printf("{\"Time\" : \"%f\", \"Metric\" : \"1\",\n\"Stack\": [\n\"%s\",\n%s\"%s\"]},", millisecondsSinceTraceStart, message.GetANSI(scratch), strCallStack.GetANSI(scratch), threadFrame.GetANSI(scratch));
     Write(event);
@@ -129,3 +139,5 @@ void EventPipeJsonFile::FormatCallStack(StackContents &stackContents, SString &r
         resultStr.Append(frameStr);
     }
 }
+
+#endif // FEATURE_PERFTRACING
index b6e42de..2b836d2 100644 (file)
@@ -6,8 +6,11 @@
 #ifndef __EVENTPIPE_JSONFILE_H__
 #define __EVENTPIPE_JSONFILE_H__
 
+#ifdef FEATURE_PERFTRACING
+
 #include "common.h"
 #include "eventpipe.h"
+#include "eventpipeeventinstance.h"
 #include "fstream.h"
 
 class EventPipeJsonFile
@@ -16,8 +19,11 @@ class EventPipeJsonFile
         EventPipeJsonFile(SString &outFilePath);
         ~EventPipeJsonFile();
 
+        // Write an event instance.
+        void WriteEvent(EventPipeEventInstance &instance);
+
         // Write an event with the specified message and stack.
-        void WriteEvent(CommonEventFields &commonFields, SString &message, StackContents &stackContents);
+        void WriteEvent(LARGE_INTEGER timeStamp, DWORD threadID, SString &message, StackContents &stackContents);
 
     private:
 
@@ -37,4 +43,6 @@ class EventPipeJsonFile
         LARGE_INTEGER m_fileOpenTimeStamp;
 };
 
+#endif // FEATURE_PERFTRACING
+
 #endif // __EVENTPIPE_JSONFILE_H__
diff --git a/src/vm/eventpipeprovider.cpp b/src/vm/eventpipeprovider.cpp
new file mode 100644 (file)
index 0000000..da18533
--- /dev/null
@@ -0,0 +1,253 @@
+// 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.
+
+#include "common.h"
+#include "eventpipe.h"
+#include "eventpipeconfiguration.h"
+#include "eventpipeevent.h"
+#include "eventpipeprovider.h"
+
+#ifdef FEATURE_PERFTRACING
+
+EventPipeProvider::EventPipeProvider(const GUID &providerID)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    m_providerID = providerID;
+    m_enabled = false;
+    m_keywords = 0;
+    m_providerLevel = EventPipeEventLevel::Critical;
+    m_pEventList = new SList<SListElem<EventPipeEvent*>>();
+    m_pCallbackFunction = NULL;
+    m_pCallbackData = NULL;
+
+    // Register the provider.
+    EventPipeConfiguration* pConfig = EventPipe::GetConfiguration();
+    _ASSERTE(pConfig != NULL);
+    pConfig->RegisterProvider(*this);
+}
+
+EventPipeProvider::~EventPipeProvider()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Unregister the provider.
+    // This call is re-entrant.
+    EventPipeConfiguration* pConfig = EventPipe::GetConfiguration();
+    _ASSERTE(pConfig != NULL);
+    pConfig->UnregisterProvider(*this);
+
+    // Free all of the events.
+    if(m_pEventList != NULL)
+    {
+        // Take the lock before manipulating the list.
+        CrstHolder _crst(EventPipe::GetLock());
+
+        SListElem<EventPipeEvent*> *pElem = m_pEventList->GetHead();
+        while(pElem != NULL)
+        {
+            EventPipeEvent *pEvent = pElem->GetValue();
+            delete pEvent;
+
+            pElem = m_pEventList->GetNext(pElem);
+        }
+
+        delete m_pEventList;
+        m_pEventList = NULL;
+    }
+}
+
+const GUID& EventPipeProvider::GetProviderID() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_providerID;
+}
+
+bool EventPipeProvider::Enabled() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_enabled;
+}
+
+bool EventPipeProvider::EventEnabled(INT64 keywords) const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    // The event is enabled if:
+    //  - The provider is enabled.
+    //  - The event keywords are unspecified in the manifest (== 0) or when masked with the enabled config are != 0.
+    return (Enabled() && ((keywords == 0) || ((m_keywords & keywords) != 0)));
+}
+
+bool EventPipeProvider::EventEnabled(INT64 keywords, EventPipeEventLevel eventLevel) const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    // The event is enabled if:
+    //  - The provider is enabled.
+    //  - The event keywords are unspecified in the manifest (== 0) or when masked with the enabled config are != 0.
+    //  - The event level is LogAlways or the provider's verbosity level is set to greater than the event's verbosity level in the manifest.
+    return (EventEnabled(keywords) &&
+        ((eventLevel == EventPipeEventLevel::LogAlways) || (m_providerLevel >= eventLevel)));
+}
+
+void EventPipeProvider::SetConfiguration(bool providerEnabled, INT64 keywords, EventPipeEventLevel providerLevel)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+    }
+    CONTRACTL_END;
+
+    m_enabled = providerEnabled;
+    m_keywords = keywords;
+    m_providerLevel = providerLevel;
+
+    RefreshAllEvents();
+    InvokeCallback();
+}
+
+EventPipeEvent* EventPipeProvider::AddEvent(INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Create the event.
+    EventPipeEvent *pEvent = new EventPipeEvent(
+        *this,
+        keywords,
+        eventID,
+        eventVersion,
+        level,
+        needStack);
+
+    // Add it to the list of events.
+    AddEvent(*pEvent);
+    return pEvent;
+}
+
+void EventPipeProvider::AddEvent(EventPipeEvent &event)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Take the config lock before inserting a new event.
+    CrstHolder _crst(EventPipe::GetLock());
+
+    m_pEventList->InsertTail(new SListElem<EventPipeEvent*>(&event));
+}
+
+void EventPipeProvider::RegisterCallback(EventPipeCallback pCallbackFunction, void *pData)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Take the config lock before setting the callback.
+    CrstHolder _crst(EventPipe::GetLock());
+
+    if(m_pCallbackFunction == NULL)
+    {
+        m_pCallbackFunction = pCallbackFunction;
+        m_pCallbackData = pData;
+    }
+}
+
+void EventPipeProvider::UnregisterCallback(EventPipeCallback pCallbackFunction)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Take the config lock before setting the callback.
+    CrstHolder _crst(EventPipe::GetLock());
+
+    if(m_pCallbackFunction == pCallbackFunction)
+    {
+        m_pCallbackFunction = NULL;
+        m_pCallbackData = NULL;
+    }
+}
+
+void EventPipeProvider::InvokeCallback()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+    }
+    CONTRACTL_END;
+
+    if(m_pCallbackFunction != NULL)
+    {
+        (*m_pCallbackFunction)(
+            &m_providerID,
+            m_enabled,
+            (UCHAR) m_providerLevel,
+            m_keywords,
+            0 /* matchAllKeywords */,
+            NULL /* FilterData */,
+            m_pCallbackData /* CallbackContext */);
+    }
+}
+
+void EventPipeProvider::RefreshAllEvents()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        MODE_ANY;
+        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+    }
+    CONTRACTL_END;
+
+    SListElem<EventPipeEvent*> *pElem = m_pEventList->GetHead();
+    while(pElem != NULL)
+    {
+        EventPipeEvent *pEvent = pElem->GetValue();
+        pEvent->RefreshState();
+
+        pElem = m_pEventList->GetNext(pElem);
+    }
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipeprovider.h b/src/vm/eventpipeprovider.h
new file mode 100644 (file)
index 0000000..610d76d
--- /dev/null
@@ -0,0 +1,106 @@
+// 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.
+
+#ifndef __EVENTPIPE_PROVIDER_H__
+#define __EVENTPIPE_PROVIDER_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "slist.h"
+
+class EventPipeEvent;
+
+// Define the event pipe callback to match the ETW callback signature.
+typedef void (*EventPipeCallback)(
+    LPCGUID SourceID,
+    ULONG IsEnabled,
+    UCHAR Level,
+    ULONGLONG MatchAnyKeywords,
+    ULONGLONG MatchAllKeywords,
+    void *FilterData,
+    void *CallbackContext);
+
+enum class EventPipeEventLevel
+{
+    LogAlways,
+    Critical,
+    Error,
+    Warning,
+    Informational,
+    Verbose
+};
+
+class EventPipeProvider
+{
+    // Declare friends.
+    friend class EventPipeConfiguration;
+
+private:
+    // The GUID of the provider.
+    GUID m_providerID;
+
+    // True if the provider is enabled.
+    bool m_enabled;
+
+    // Bit vector containing the currently enabled keywords.
+    INT64 m_keywords;
+
+    // The current verbosity of the provider.
+    EventPipeEventLevel m_providerLevel;
+
+    // List of every event currently associated with the provider.
+    // New events can be added on-the-fly.
+    SList<SListElem<EventPipeEvent*>> *m_pEventList;
+
+    // The optional provider callback.
+    EventPipeCallback m_pCallbackFunction;
+
+    // The optional provider callback data pointer.
+    void *m_pCallbackData;
+
+public:
+
+    EventPipeProvider(const GUID &providerID);
+    ~EventPipeProvider();
+
+    // Get the provider ID.
+    const GUID& GetProviderID() const;
+
+    // Determine if the provider is enabled.
+    bool Enabled() const;
+
+    // Determine if the specified keywords are enabled.
+    bool EventEnabled(INT64 keywords) const;
+
+    // Determine if the specified keywords and level match the configuration.
+    bool EventEnabled(INT64 keywords, EventPipeEventLevel eventLevel) const;
+
+    // Create a new event.
+    EventPipeEvent* AddEvent(INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack);
+
+    // Register a callback with the provider to be called on state change.
+    void RegisterCallback(EventPipeCallback pCallbackFunction, void *pData);
+
+    // Unregister a callback.
+    void UnregisterCallback(EventPipeCallback pCallbackFunction);
+
+private:
+
+    // Add an event to the provider.
+    void AddEvent(EventPipeEvent &event);
+
+    // Set the provider configuration (enable and disable sets of events).
+    // This is called by EventPipeConfiguration.
+    void SetConfiguration(bool providerEnabled, INT64 keywords, EventPipeEventLevel providerLevel);
+
+    // Refresh the runtime state of all events.
+    void RefreshAllEvents();
+
+    // Invoke the provider callback.
+    void InvokeCallback();
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_PROVIDER_H__
index b3ee17e..70ea18f 100644 (file)
@@ -6760,9 +6760,9 @@ VOID ETW::MethodLog::SendHelperEvent(ULONGLONG ullHelperStartAddress, ULONG ulHe
                                      ulHelperSize, 
                                      0, 
                                      methodFlags, 
-                                     NULL, 
+                                     NULL,
                                      pHelperName, 
-                                     NULL, 
+                                     NULL,
                                      GetClrInstanceId());
     }
 }
diff --git a/src/vm/fastserializableobject.h b/src/vm/fastserializableobject.h
new file mode 100644 (file)
index 0000000..cbfcfc9
--- /dev/null
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef __FASTSERIALIZABLE_OBJECT_H__
+#define __FASTSERIALIZABLE_OBJECT_H__
+
+#ifdef FEATURE_PERFTRACING
+
+class FastSerializer;
+
+class FastSerializableObject
+{
+
+public:
+
+    // Virtual destructor to ensure that derived class destructors get called.
+    virtual ~FastSerializableObject()
+    {
+        LIMITED_METHOD_CONTRACT;
+    }
+
+    // Serialize the object using the specified serializer.
+    virtual void FastSerialize(FastSerializer *pSerializer) = 0;
+
+    // Get the type name for the current object.
+    virtual const char* GetTypeName() = 0;
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // _FASTSERIALIZABLE_OBJECT_H__
diff --git a/src/vm/fastserializer.cpp b/src/vm/fastserializer.cpp
new file mode 100644 (file)
index 0000000..7f9b4e2
--- /dev/null
@@ -0,0 +1,337 @@
+// 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.
+
+#include "common.h"
+#include "fastserializer.h"
+
+#ifdef FEATURE_PERFTRACING
+
+FastSerializer::FastSerializer(SString &outputFilePath, FastSerializableObject &object)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    m_writeErrorEncountered = false;
+    m_pEntryObject = &object;
+    m_currentPos = 0;
+    m_nextForwardReference = 0;
+    m_pFileStream = new CFileStream();
+    if(FAILED(m_pFileStream->OpenForWrite(outputFilePath)))
+    {
+        delete(m_pFileStream);
+        m_pFileStream = NULL;
+        return;
+    }
+
+    // Write the file header.
+    WriteFileHeader();
+
+    // Write the entry object.
+    WriteEntryObject();
+}
+
+FastSerializer::~FastSerializer()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // Write the end of the entry object.
+    WriteTag(FastSerializerTags::EndObject);
+
+    // Write forward reference table.
+    StreamLabel forwardReferenceLabel = WriteForwardReferenceTable();
+
+    // Write trailer.
+    WriteTrailer(forwardReferenceLabel);
+
+    if(m_pFileStream != NULL)
+    {
+        delete(m_pFileStream);
+        m_pFileStream = NULL;
+    }
+}
+
+StreamLabel FastSerializer::GetStreamLabel() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return (StreamLabel)m_currentPos;
+}
+
+void FastSerializer::WriteObject(FastSerializableObject *pObject)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+        PRECONDITION(pObject != NULL);
+    }
+    CONTRACTL_END;
+
+    // Write a BeginObject tag.
+    WriteTag(FastSerializerTags::BeginObject);
+
+    // Write object begin tag.
+    WriteSerializationType(pObject);
+
+    // Ask the object to serialize itself using the current serializer.
+    pObject->FastSerialize(this);
+
+    // Write object end tag.
+    WriteTag(FastSerializerTags::EndObject);
+}
+
+void FastSerializer::WriteBuffer(BYTE *pBuffer, unsigned int length)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+        PRECONDITION(pBuffer != NULL);
+        PRECONDITION(length > 0);
+    }
+    CONTRACTL_END;
+
+    if(m_writeErrorEncountered || m_pFileStream == NULL)
+    {
+        return;
+    }
+
+    EX_TRY
+    {
+        ULONG outCount;
+        m_pFileStream->Write(pBuffer, length, &outCount);
+
+#ifdef _DEBUG
+        size_t prevPos = m_currentPos;
+#endif
+        m_currentPos += outCount;
+#ifdef _DEBUG
+        _ASSERTE(prevPos < m_currentPos);
+#endif
+
+        if (length != outCount)
+        {
+            // This will cause us to stop writing to the file.
+            // The file will still remain open until shutdown so that we don't have to take a lock at this level when we touch the file stream.
+            m_writeErrorEncountered = true;
+        }
+    }
+    EX_CATCH
+    {
+        m_writeErrorEncountered = true;
+    } 
+    EX_END_CATCH(SwallowAllExceptions);
+}
+
+void FastSerializer::WriteEntryObject()
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    }
+    CONTRACTL_END;
+
+    // Write begin entry object tag.
+    WriteTag(FastSerializerTags::BeginObject);
+
+    // Write the type information for the entry object.
+    WriteSerializationType(m_pEntryObject);
+
+    // The object is now initialized.  Fields or other objects can now be written.
+}
+
+unsigned int FastSerializer::AllocateForwardReference()
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+        PRECONDITION(m_nextForwardReference < MaxForwardReferences);
+    }
+    CONTRACTL_END;
+
+    // TODO: Handle failure.
+
+    // Save the index.
+    int index = m_nextForwardReference;
+
+    // Allocate the forward reference and zero-fill it so that the reader
+    // will know if it was not properly defined.
+    m_forwardReferences[m_nextForwardReference++] = 0;
+
+    return index;
+}
+
+void FastSerializer::DefineForwardReference(unsigned int index, StreamLabel value)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+        PRECONDITION(index < MaxForwardReferences-1);
+    }
+    CONTRACTL_END;
+
+    m_forwardReferences[index] = value;
+}
+
+void FastSerializer::WriteForwardReference(unsigned int index)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+        PRECONDITION(index < MaxForwardReferences-1);
+    }
+    CONTRACTL_END;
+
+    WriteBuffer((BYTE*)&index, sizeof(index));
+}
+
+void FastSerializer::WriteSerializationType(FastSerializableObject *pObject)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+        PRECONDITION(pObject != NULL);
+    }
+    CONTRACTL_END;
+
+    // Write the BeginObject tag.
+    WriteTag(FastSerializerTags::BeginObject);
+
+    // Write a NullReferenceTag, which implies that the following fields belong to SerializationType.
+    WriteTag(FastSerializerTags::NullReference);
+
+    // Write the SerializationType version fields.
+    int serializationType[2];
+    serializationType[0] = 1; // Object Version.
+    serializationType[1] = 0; // Minimum Reader Version.
+    WriteBuffer((BYTE*) &serializationType, sizeof(serializationType));
+
+    // Write the SerializationType TypeName field.
+    const char *strTypeName = pObject->GetTypeName();
+    unsigned int length = (unsigned int)strlen(strTypeName);
+    WriteString(strTypeName, length);
+
+    // Write the EndObject tag.
+    WriteTag(FastSerializerTags::EndObject);
+}
+
+
+void FastSerializer::WriteTag(FastSerializerTags tag, BYTE *payload, unsigned int payloadLength)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    }
+    CONTRACTL_END;
+
+    WriteBuffer((BYTE *)&tag, sizeof(tag));
+    if(payload != NULL)
+    {
+        _ASSERTE(payloadLength > 0);
+        WriteBuffer(payload, payloadLength);
+    }
+}
+
+
+void FastSerializer::WriteFileHeader()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    const char *strSignature = "!FastSerialization.1";
+    unsigned int length = (unsigned int)strlen(strSignature);
+    WriteString(strSignature, length);
+}
+
+void FastSerializer::WriteString(const char *strContents, unsigned int length)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    }
+    CONTRACTL_END;
+
+    // Write the string length .
+    WriteBuffer((BYTE*) &length, sizeof(length));
+
+    // Write the string contents.
+    WriteBuffer((BYTE*) strContents, length);
+}
+
+StreamLabel FastSerializer::WriteForwardReferenceTable()
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    }
+    CONTRACTL_END;
+
+    // Save the position of the start of the forward references table.
+    StreamLabel current = GetStreamLabel();
+
+    // Write the count of allocated references.
+    WriteBuffer((BYTE*) &m_nextForwardReference, sizeof(m_nextForwardReference));
+
+    // Write each of the allocated references.
+    WriteBuffer((BYTE*) m_forwardReferences, sizeof(StreamLabel) * m_nextForwardReference);
+
+    return current;
+}
+
+void FastSerializer::WriteTrailer(StreamLabel forwardReferencesTableStart)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    }
+    CONTRACTL_END;
+
+    // Get the current location to mark the beginning of the trailer.
+    StreamLabel current = GetStreamLabel();
+
+    // Write the trailer, which contains the start of the forward references table.
+    WriteBuffer((BYTE*) &forwardReferencesTableStart, sizeof(forwardReferencesTableStart));
+
+    // Write the location of the trailer.  This is the final piece of data written to the file,
+    // so that it can be easily found by a reader that can seek to the end of the file.
+    WriteBuffer((BYTE*) &current, sizeof(current));
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/fastserializer.h b/src/vm/fastserializer.h
new file mode 100644 (file)
index 0000000..5fd2cfd
--- /dev/null
@@ -0,0 +1,74 @@
+// 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.
+
+#ifndef __FASTSERIALIZER_H__
+#define __FASTSERIALIZER_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "fastserializableobject.h"
+#include "fstream.h"
+
+class FastSerializer;
+
+typedef unsigned int StreamLabel;
+
+enum class FastSerializerTags : BYTE 
+{
+    Error,              // To improve debugabilty, 0 is an illegal tag.  
+    NullReference,      // Tag for a null object forwardReference. 
+    ObjectReference,    // Followed by StreamLabel 
+    ForwardReference,   // Followed by an index (32-bit integer) into the Forward forwardReference array and a Type object
+    BeginObject,        // Followed by Type object, object data, tagged EndObject
+    BeginPrivateObject, // Like beginObject, but not placed in interning table on deserialiation 
+    EndObject,          // Placed after an object to mark its end. 
+    ForwardDefinition,  // Followed by a forward forwardReference index and an object definition (BeginObject)
+    Byte,
+    Int16,
+    Int32,
+    Int64,
+    SkipRegion,
+    String,
+    Limit,              // Just past the last valid tag, used for asserts.  
+};
+
+class FastSerializer
+{
+public:
+
+    FastSerializer(SString &outputFilePath, FastSerializableObject &object);
+    ~FastSerializer();
+
+    StreamLabel GetStreamLabel() const;
+
+    void WriteObject(FastSerializableObject *pObject);
+    void WriteBuffer(BYTE *pBuffer, unsigned int length);
+    void WriteTag(FastSerializerTags tag, BYTE *payload = NULL, unsigned int payloadLength = 0);
+    void WriteString(const char *strContents, unsigned int length);
+
+    unsigned int AllocateForwardReference();
+    void DefineForwardReference(unsigned int index, StreamLabel value);
+    void WriteForwardReference(unsigned int index);
+
+private:
+
+    void WriteEntryObject();
+    void WriteSerializationType(FastSerializableObject *pObject);
+    void WriteFileHeader();
+    StreamLabel WriteForwardReferenceTable();
+    void WriteTrailer(StreamLabel forwardReferencesTableStart);
+
+    CFileStream *m_pFileStream;
+    bool m_writeErrorEncountered;
+    FastSerializableObject *m_pEntryObject;
+    size_t m_currentPos;
+
+    static const unsigned int MaxForwardReferences = 100;
+    StreamLabel m_forwardReferences[MaxForwardReferences];
+    unsigned int m_nextForwardReference;
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __FASTSERIALIZER_H__
index 77a6a0d..34ae6d9 100644 (file)
@@ -4571,6 +4571,35 @@ c_CentralJumpCode = {
 };
 #include <poppack.h>
 
+#elif defined(_TARGET_ARM_)
+
+#include <pshpack1.h>
+struct CentralJumpCode {
+    BYTE m_ldrPC[4];
+    BYTE m_short[2];
+    MethodDescChunk *m_pChunk;
+    PCODE m_target;
+
+    inline void Setup(PCODE target, MethodDescChunk *pChunk) {
+        WRAPPER_NO_CONTRACT;
+
+        m_target = target;
+        m_pChunk = pChunk;
+    }
+
+    inline BOOL CheckTarget(TADDR target) {
+        WRAPPER_NO_CONTRACT;
+        return ((TADDR)m_target == target);
+    }
+}
+c_CentralJumpCode = {
+    { 0xDF, 0xF8, 0x08, 0xF0 },                         //   ldr pc, =pTarget
+    { 0x00, 0x00 },                                     //   short offset for alignment
+    0,                                                  //   pChunk
+    0                                                   //   pTarget
+};
+#include <poppack.h>
+
 #else
 #error Unsupported platform
 #endif
@@ -4580,10 +4609,92 @@ typedef DPTR(struct CentralJumpCode) PTR_CentralJumpCode;
 static_assert_no_msg((TEP_CENTRAL_JUMP_SIZE & 1) == 0);
 
 #define TEP_ENTRY_SIZE          4
+
+#ifdef _TARGET_ARM_
+
+#define TEP_HALF_ENTRY_SIZE (TEP_ENTRY_SIZE / 2)
+
+// Compact entry point on arm consists of two thumb instructions:
+//   mov r12, pc
+//   b CentralJumpCode
+
+// First instruction 0x46fc
+#define TEP_ENTRY_INSTR1_BYTE1 0xFC
+#define TEP_ENTRY_INSTR1_BYTE2 0x46
+
+// Mask for unconditional branch opcode
+#define TEP_ENTRY_INSTR2_MASK1 0xE0
+
+// Mask for opcode
+#define TEP_ENTRY_INSTR2_MASK2 0xF8
+
+// Bit used for ARM to identify compact entry points
+#define COMPACT_ENTRY_ARM_CODE 0x2
+
+/* static */ int MethodDescChunk::GetCompactEntryPointMaxCount ()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    return MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB / TEP_ENTRY_SIZE;
+}
+
+// Get offset from the start of current compact entry point to the CentralJumpCode
+static uint16_t DecodeOffsetFromBranchToCentralJump (uint16_t instr)
+{
+    int16_t offset = decodeUnconditionalBranchThumb ((LPBYTE) &instr);
+
+    offset += PC_REG_RELATIVE_OFFSET + TEP_HALF_ENTRY_SIZE;
+
+    _ASSERTE (offset >= TEP_ENTRY_SIZE && (offset % TEP_ENTRY_SIZE == 0));
+
+    return (uint16_t) offset;
+}
+
+#ifndef DACCESS_COMPILE
+
+// Encode branch instruction to central jump for current compact entry point
+static uint16_t EncodeBranchToCentralJump (int16_t offset)
+{
+    _ASSERTE (offset >= 0 && (offset % TEP_ENTRY_SIZE == 0));
+
+    offset += TEP_HALF_ENTRY_SIZE - PC_REG_RELATIVE_OFFSET;
+
+    uint16_t instr;
+    emitUnconditionalBranchThumb ((LPBYTE) &instr, offset);
+
+    return instr;
+}
+
+#endif // DACCESS_COMPILE
+
+#else // _TARGET_ARM_
+
 #define TEP_MAX_BEFORE_INDEX    (1 + (127 / TEP_ENTRY_SIZE))
 #define TEP_MAX_BLOCK_INDEX     (TEP_MAX_BEFORE_INDEX + (128 - TEP_CENTRAL_JUMP_SIZE) / TEP_ENTRY_SIZE)
 #define TEP_FULL_BLOCK_SIZE     (TEP_MAX_BLOCK_INDEX * TEP_ENTRY_SIZE + TEP_CENTRAL_JUMP_SIZE)
 
+#endif // _TARGET_ARM_
+
+BOOL MethodDescChunk::IsCompactEntryPointAtAddress(PCODE addr)
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+
+    // Compact entrypoints start at odd addresses
+    return (addr & 1) != 0;
+
+#elif defined(_TARGET_ARM_)
+
+    // Compact entrypoints start at odd addresses (thumb) with second bit set to 1
+    uint8_t compactEntryPointMask = THUMB_CODE | COMPACT_ENTRY_ARM_CODE;
+    return (addr & compactEntryPointMask) == compactEntryPointMask;
+
+#else
+    #error Unsupported platform
+#endif
+}
+
 //*******************************************************************************
 /* static */ MethodDesc* MethodDescChunk::GetMethodDescFromCompactEntryPoint(PCODE addr, BOOL fSpeculative /*=FALSE*/)
 {
@@ -4597,18 +4708,39 @@ static_assert_no_msg((TEP_CENTRAL_JUMP_SIZE & 1) == 0);
     // Always do consistency check in debug
     if (fSpeculative INDEBUG(|| TRUE))
     {
+#ifdef _TARGET_ARM_
+        if (!IsCompactEntryPointAtAddress(addr))
+#else // _TARGET_ARM_
         if ((addr & 3) != 1 ||
             *PTR_BYTE(addr) != X86_INSTR_MOV_AL ||
             *PTR_BYTE(addr+2) != X86_INSTR_JMP_REL8)
+#endif // _TARGET_ARM_
         {
             if (fSpeculative) return NULL;
             _ASSERTE(!"Unexpected code in temporary entrypoint");
         }
     }
 
+#ifdef _TARGET_ARM_
+
+    // On ARM compact entry points are thumb
+    _ASSERTE ((addr & THUMB_CODE) != 0);
+    addr = addr - THUMB_CODE;
+
+    // Get offset for CentralJumpCode from current compact entry point
+    PTR_UINT16 pBranchInstr = (PTR_UINT16(addr)) + 1;
+    uint16_t offset = DecodeOffsetFromBranchToCentralJump (*pBranchInstr);
+
+    TADDR centralJump = addr + offset;
+    int index = (centralJump - addr - TEP_ENTRY_SIZE) / TEP_ENTRY_SIZE;
+
+#else // _TARGET_ARM_
+
     int index = *PTR_BYTE(addr+1);
     TADDR centralJump = addr + 4 + *PTR_SBYTE(addr+3);
 
+#endif // _TARGET_ARM_
+
     CentralJumpCode* pCentralJumpCode = PTR_CentralJumpCode(centralJump);
 
     // Always do consistency check in debug
@@ -4625,10 +4757,42 @@ static_assert_no_msg((TEP_CENTRAL_JUMP_SIZE & 1) == 0);
             }
         }
 
+#ifdef _TARGET_ARM_
+
+        _ASSERTE_IMPL(pCentralJumpCode->CheckTarget(GetPreStubCompactARMEntryPoint()));
+
+#else // _TARGET_ARM_
+
         _ASSERTE_IMPL(pCentralJumpCode->CheckTarget(GetPreStubEntryPoint()));
+
+#endif // _TARGET_ARM_
     }
 
+#ifdef _TARGET_ARM_
+    // Go through all MethodDesc in MethodDescChunk and find the one with the required index
+    PTR_MethodDescChunk pChunk = *((DPTR(PTR_MethodDescChunk))(centralJump + offsetof(CentralJumpCode, m_pChunk)));
+    TADDR pMD = PTR_HOST_TO_TADDR (pChunk->GetFirstMethodDesc ());
+
+    _ASSERTE (index >= 0 && index < ((int) pChunk->GetCount ()));
+
+    index = ((int) pChunk->GetCount ()) - 1 - index;
+
+    SIZE_T totalSize = 0;
+    int curIndex = 0;
+
+    while (index != curIndex)
+    {
+        SIZE_T sizeCur = (PTR_MethodDesc (pMD))->SizeOf ();
+        totalSize += sizeCur;
+
+        pMD += sizeCur;
+        ++curIndex;
+    }
+
+    return PTR_MethodDesc (pMD);
+#else // _TARGET_ARM_
     return PTR_MethodDesc((TADDR)pCentralJumpCode->m_pBaseMD + index * MethodDesc::ALIGNMENT);
+#endif // _TARGET_ARM_
 }
 
 //*******************************************************************************
@@ -4636,11 +4800,19 @@ SIZE_T MethodDescChunk::SizeOfCompactEntryPoints(int count)
 {
     LIMITED_METHOD_DAC_CONTRACT;
 
+#ifdef _TARGET_ARM_
+
+    return COMPACT_ENTRY_ARM_CODE + count * TEP_ENTRY_SIZE + TEP_CENTRAL_JUMP_SIZE;
+
+#else // _TARGET_ARM_
+
     int fullBlocks = count / TEP_MAX_BLOCK_INDEX;
     int remainder = count % TEP_MAX_BLOCK_INDEX;
 
     return 1 + (fullBlocks * TEP_FULL_BLOCK_SIZE) +
         (remainder * TEP_ENTRY_SIZE) + ((remainder != 0) ? TEP_CENTRAL_JUMP_SIZE : 0);
+
+#endif // _TARGET_ARM_
 }
 
 #ifndef DACCESS_COMPILE
@@ -4657,16 +4829,37 @@ TADDR MethodDescChunk::AllocateCompactEntryPoints(LoaderAllocator *pLoaderAlloca
 
     TADDR temporaryEntryPoints = (TADDR)pamTracker->Track(pLoaderAllocator->GetPrecodeHeap()->AllocAlignedMem(size, sizeof(TADDR)));
 
+#ifdef _TARGET_ARM_
+    BYTE* p = (BYTE*)temporaryEntryPoints + COMPACT_ENTRY_ARM_CODE;
+    int relOffset        = count * TEP_ENTRY_SIZE - TEP_ENTRY_SIZE; // relative offset for the short jump
+
+    _ASSERTE (relOffset < MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB);
+#else // _TARGET_ARM_
     // make the temporary entrypoints unaligned, so they are easy to identify
     BYTE* p = (BYTE*)temporaryEntryPoints + 1;
+    int indexInBlock     = TEP_MAX_BLOCK_INDEX;         // recompute relOffset in first iteration
+    int relOffset        = 0;                           // relative offset for the short jump
+#endif // _TARGET_ARM_
 
-    int indexInBlock     = TEP_MAX_BLOCK_INDEX; // recompute relOffset in first iteration
-    int relOffset        = 0;                   // relative offset for the short jump
     MethodDesc * pBaseMD = 0;                   // index of the start of the block
 
     MethodDesc * pMD = GetFirstMethodDesc();
     for (int index = 0; index < count; index++)
     {
+#ifdef _TARGET_ARM_
+
+        uint8_t *pMovInstrByte1 = (uint8_t *)p;
+        uint8_t *pMovInstrByte2 = (uint8_t *)p+1;
+        uint16_t *pBranchInstr = ((uint16_t *)p)+1;
+
+        *pMovInstrByte1 = TEP_ENTRY_INSTR1_BYTE1;
+        *pMovInstrByte2 = TEP_ENTRY_INSTR1_BYTE2;
+        *pBranchInstr = EncodeBranchToCentralJump ((int16_t) relOffset);
+
+        p += TEP_ENTRY_SIZE;
+
+#else // _TARGET_ARM_
+
         if (indexInBlock == TEP_MAX_BLOCK_INDEX)
         {
             relOffset = (min(count - index, TEP_MAX_BEFORE_INDEX) - 1) * TEP_ENTRY_SIZE;
@@ -4698,14 +4891,28 @@ TADDR MethodDescChunk::AllocateCompactEntryPoints(LoaderAllocator *pLoaderAlloca
             relOffset -= TEP_CENTRAL_JUMP_SIZE;
         }
 
-        relOffset -= TEP_ENTRY_SIZE;
         indexInBlock++;
 
+#endif // _TARGET_ARM_
+
+        relOffset -= TEP_ENTRY_SIZE;
         pMD = (MethodDesc *)((BYTE *)pMD + pMD->SizeOf());
     }
 
+#ifdef _TARGET_ARM_
+
+    CentralJumpCode* pCode = (CentralJumpCode*)p;
+    memcpy(pCode, &c_CentralJumpCode, TEP_CENTRAL_JUMP_SIZE);
+    pCode->Setup (GetPreStubCompactARMEntryPoint(), this);
+
+    _ASSERTE(p + TEP_CENTRAL_JUMP_SIZE == (BYTE*)temporaryEntryPoints + size);
+
+#else // _TARGET_ARM_
+
     _ASSERTE(p == (BYTE*)temporaryEntryPoints + size);
 
+#endif // _TARGET_ARM_
+
     ClrFlushInstructionCache((LPVOID)temporaryEntryPoints, size);
 
     SetHasCompactEntryPoints();
@@ -4725,11 +4932,19 @@ PCODE MethodDescChunk::GetTemporaryEntryPoint(int index)
 #ifdef HAS_COMPACT_ENTRYPOINTS
     if (HasCompactEntryPoints())
     {
+#ifdef _TARGET_ARM_
+
+        return GetTemporaryEntryPoints() + COMPACT_ENTRY_ARM_CODE + THUMB_CODE + index * TEP_ENTRY_SIZE;
+
+#else // _TARGET_ARM_
+
         int fullBlocks = index / TEP_MAX_BLOCK_INDEX;
         int remainder = index % TEP_MAX_BLOCK_INDEX;
 
         return GetTemporaryEntryPoints() + 1 + (fullBlocks * TEP_FULL_BLOCK_SIZE) +
             (remainder * TEP_ENTRY_SIZE) + ((remainder >= TEP_MAX_BEFORE_INDEX) ? TEP_CENTRAL_JUMP_SIZE : 0);
+
+#endif // _TARGET_ARM_
     }
 #endif // HAS_COMPACT_ENTRYPOINTS
 
index 9545da2..3354e57 100644 (file)
@@ -2031,23 +2031,18 @@ public:
     // direct call to direct jump.
     //
     // We use (1) for x86 and (2) for 64-bit to get the best performance on each platform.
-    //
+    // For ARM (1) is used.
 
     TADDR AllocateCompactEntryPoints(LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
 
     static MethodDesc* GetMethodDescFromCompactEntryPoint(PCODE addr, BOOL fSpeculative = FALSE);
     static SIZE_T SizeOfCompactEntryPoints(int count);
 
-    static BOOL IsCompactEntryPointAtAddress(PCODE addr)
-    {
-#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
-        // Compact entrypoints start at odd addresses
-        LIMITED_METHOD_DAC_CONTRACT;
-        return (addr & 1) != 0;
-#else
-        #error Unsupported platform
-#endif
-    }
+    static BOOL IsCompactEntryPointAtAddress(PCODE addr);
+
+#ifdef _TARGET_ARM_
+    static int GetCompactEntryPointMaxCount ();
+#endif // _TARGET_ARM_
 #endif // HAS_COMPACT_ENTRYPOINTS
 
     FORCEINLINE PTR_MethodTable GetMethodTable()
index 87927f6..338ba1e 100644 (file)
@@ -146,12 +146,6 @@ DEFINE_CLASS(ARRAY,                 System,                 Array)
 DEFINE_PROPERTY(ARRAY,              LENGTH,                 Length,                     Int)
 DEFINE_METHOD(ARRAY,                GET_DATA_PTR_OFFSET_INTERNAL, GetDataPtrOffsetInternal, IM_RetInt)
 
-#ifdef FEATURE_NONGENERIC_COLLECTIONS 
-DEFINE_CLASS(ARRAY_LIST,            Collections,            ArrayList)
-DEFINE_METHOD(ARRAY_LIST,           CTOR,                   .ctor,                      IM_RetVoid)
-DEFINE_METHOD(ARRAY_LIST,           ADD,                    Add,                        IM_Obj_RetInt)
-#endif // FEATURE_NONGENERIC_COLLECTIONS 
-
 DEFINE_CLASS(ARRAY_WITH_OFFSET,     Interop,                ArrayWithOffset)                 
 DEFINE_FIELD(ARRAY_WITH_OFFSET,     M_ARRAY,                m_array)
 DEFINE_FIELD(ARRAY_WITH_OFFSET,     M_OFFSET,               m_offset)
index 9707b27..1daf6e3 100644 (file)
@@ -525,6 +525,16 @@ TADDR Precode::AllocateTemporaryEntryPoints(MethodDescChunk *  pChunk,
     // Note that these are just best guesses to save memory. If we guessed wrong,
     // we will allocate a new exact type of precode in GetOrCreatePrecode.
     BOOL fForcedPrecode = pFirstMD->RequiresStableEntryPoint(count > 1);
+
+#ifdef _TARGET_ARM_
+    if (pFirstMD->RequiresMethodDescCallingConvention(count > 1)
+        || count >= MethodDescChunk::GetCompactEntryPointMaxCount ())
+    {
+        // We do not pass method desc on scratch register
+        fForcedPrecode = TRUE;
+    }
+#endif // _TARGET_ARM_
+
     if (!fForcedPrecode && (totalSize > MethodDescChunk::SizeOfCompactEntryPoints(count)))
         return NULL;
 #endif
index 7dd4cd2..8947192 100644 (file)
@@ -170,6 +170,11 @@ public:
             align = 8;
 #endif // _TARGET_X86_ && HAS_FIXUP_PRECODE
 
+#if defined(_TARGET_ARM_) && defined(HAS_COMPACT_ENTRYPOINTS)
+        // Precodes have to be aligned to allow fast compact entry points check
+        _ASSERTE (align >= sizeof(void*));
+#endif // _TARGET_ARM_ && HAS_COMPACT_ENTRYPOINTS
+
         return align;
     }
 
index 67639e9..fccec51 100644 (file)
 #ifndef DACCESS_COMPILE 
 
 EXTERN_C void STDCALL ThePreStub();
+
+#if defined(HAS_COMPACT_ENTRYPOINTS) && defined (_TARGET_ARM_)
+
+EXTERN_C void STDCALL ThePreStubCompactARM();
+
+#endif // defined(HAS_COMPACT_ENTRYPOINTS) && defined (_TARGET_ARM_)
+
 EXTERN_C void STDCALL ThePreStubPatch();
 
 //==========================================================================
@@ -1002,6 +1009,21 @@ Stub * MakeInstantiatingStubWorker(MethodDesc *pMD)
 }
 #endif // defined(FEATURE_SHARE_GENERIC_CODE)
 
+#if defined (HAS_COMPACT_ENTRYPOINTS) && defined (_TARGET_ARM_)
+
+extern "C" MethodDesc * STDCALL PreStubGetMethodDescForCompactEntryPoint (PCODE pCode)
+{
+    _ASSERTE (pCode >= PC_REG_RELATIVE_OFFSET);
+
+    pCode = (PCODE) (pCode - PC_REG_RELATIVE_OFFSET + THUMB_CODE);
+
+    _ASSERTE (MethodDescChunk::IsCompactEntryPointAtAddress (pCode));
+
+    return MethodDescChunk::GetMethodDescFromCompactEntryPoint(pCode, FALSE);
+}
+
+#endif // defined (HAS_COMPACT_ENTRYPOINTS) && defined (_TARGET_ARM_)
+
 //=============================================================================
 // This function generates the real code for a method and installs it into
 // the methoddesc. Usually ***BUT NOT ALWAYS***, this function runs only once
index 004b3c6..6a6a23a 100644 (file)
@@ -3,18 +3,23 @@
 // See the LICENSE file in the project root for more information.
 
 #include "common.h"
+#include "eventpipeeventinstance.h"
 #include "sampleprofiler.h"
 #include "hosting.h"
 #include "threadsuspend.h"
 
+#ifdef FEATURE_PERFTRACING
+
 Volatile<BOOL> SampleProfiler::s_profilingEnabled = false;
 Thread* SampleProfiler::s_pSamplingThread = NULL;
+const GUID SampleProfiler::s_providerID = {0x3c530d44,0x97ae,0x513a,{0x1e,0x6d,0x78,0x3e,0x8f,0x8e,0x03,0xa9}}; // {3c530d44-97ae-513a-1e6d-783e8f8e03a9}
+EventPipeProvider* SampleProfiler::s_pEventPipeProvider = NULL;
+EventPipeEvent* SampleProfiler::s_pThreadTimeEvent = NULL;
 CLREventStatic SampleProfiler::s_threadShutdownEvent;
 #ifdef FEATURE_PAL
 long SampleProfiler::s_samplingRateInNs = 1000000; // 1ms
 #endif
 
-// Synchronization of multiple callers occurs in EventPipe::Enable.
 void SampleProfiler::Enable()
 {
     CONTRACTL
@@ -23,9 +28,22 @@ void SampleProfiler::Enable()
         GC_TRIGGERS;
         MODE_ANY;
         PRECONDITION(s_pSamplingThread == NULL);
+        // Synchronization of multiple callers occurs in EventPipe::Enable.
+        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
     }
     CONTRACTL_END;
 
+    if(s_pEventPipeProvider == NULL)
+    {
+        s_pEventPipeProvider = new EventPipeProvider(s_providerID);
+        s_pThreadTimeEvent = s_pEventPipeProvider->AddEvent(
+            0, /* keywords */
+            0, /* eventID */
+            0, /* eventVersion */
+            EventPipeEventLevel::Informational,
+            false /* NeedStack */);
+    }
+
     s_profilingEnabled = true;
     s_pSamplingThread = SetupUnstartedThread();
     if(s_pSamplingThread->CreateNewThread(0, ThreadProc, NULL))
@@ -40,7 +58,6 @@ void SampleProfiler::Enable()
     }
 }
 
-// Synchronization of multiple callers occurs in EventPipe::Disable.
 void SampleProfiler::Disable()
 {
     CONTRACTL
@@ -48,6 +65,8 @@ void SampleProfiler::Disable()
         THROWS;
         GC_TRIGGERS;
         MODE_ANY;
+        // Synchronization of multiple callers occurs in EventPipe::Disable.
+        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
     }
     CONTRACTL_END;
 
@@ -140,16 +159,20 @@ void SampleProfiler::WalkManagedThreads()
     CONTRACTL_END;
 
     Thread *pThread = NULL;
-    StackContents stackContents;
 
     // Iterate over all managed threads.
     // Assumes that the ThreadStoreLock is held because we've suspended all threads.
     while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
     {
+        SampleProfilerEventInstance instance(pThread);
+        StackContents &stackContents = *(instance.GetStack());
+
         // Walk the stack and write it out as an event.
         if(EventPipe::WalkManagedStackForThread(pThread, stackContents) && !stackContents.IsEmpty())
         {
-            EventPipe::WriteSampleProfileEvent(pThread, stackContents);
+            EventPipe::WriteSampleProfileEvent(instance);
         }
     }
 }
+
+#endif // FEATURE_PERFTRACING
index a5c5fc3..5ad388d 100644 (file)
@@ -5,11 +5,17 @@
 #ifndef __SAMPLEPROFILER_H__
 #define __SAMPLEPROFILER_H__
 
+#ifdef FEATURE_PERFTRACING
+
 #include "common.h"
 #include "eventpipe.h"
 
 class SampleProfiler
 {
+
+    // Declare friends.
+    friend class SampleProfilerEventInstance;
+
     public:
 
         // Enable profiling.
@@ -32,6 +38,11 @@ class SampleProfiler
         // The sampling thread.
         static Thread *s_pSamplingThread;
 
+        // The provider and event emitted by the profiler.
+        static const GUID s_providerID;
+        static EventPipeProvider *s_pEventPipeProvider;
+        static EventPipeEvent *s_pThreadTimeEvent;
+
         // Thread shutdown event for synchronization between Disable() and the sampling thread.
         static CLREventStatic s_threadShutdownEvent;
 
@@ -41,4 +52,6 @@ class SampleProfiler
 #endif
 };
 
+#endif // FEATURE_PERFTRACING
+
 #endif // __SAMPLEPROFILER_H__
index e49e564..2d08e91 100644 (file)
@@ -129,7 +129,7 @@ EXIT /B %ERRORLEVEL%
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)  do%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    filename=%24{fileToPrecompile}%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    echo Precompiling %24filename%0a</WrapperShContents>
-      <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    %24overlayDir/crossgen /Platform_Assemblies_Paths %24overlayDir %24filename 1> %24filename.stdout 2>%24filename.stderr%0a</WrapperShContents>
+      <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    %24overlayDir/crossgen /Platform_Assemblies_Paths %24overlayDir /in %24filename /out %24overlayDir/temp.ni.dll 1> %24filename.stdout 2>%24filename.stderr%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    exitCode=%24%3F%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    if [ %24exitCode != 0 ]%3B then%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)      if grep -q -e '(COR_E_ASSEMBLYEXPECTED)' %24filename.stderr%3B then%0a</WrapperShContents>
@@ -137,7 +137,10 @@ EXIT /B %ERRORLEVEL%
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)      else%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)        echo Unable to precompile %24filename.%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)      fi%0a</WrapperShContents>
-      <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    fi%0a</WrapperShContents>
+      <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    else%0a</WrapperShContents>
+      <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)      rm %24filename%0a</WrapperShContents>
+      <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)      mv %24overlayDir/temp.ni.dll %24filename%0a</WrapperShContents>
+      <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    fi%0a</WrapperShContents> 
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    rm %24filename.stdout%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)    rm %24filename.stderr%0a</WrapperShContents>
       <WrapperShContents Condition="'$(Crossgen)' == 'true'">$(WrapperShContents)  done%0a</WrapperShContents>
index a40c6ac..f947c3d 100644 (file)
         <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\Dev11\dev10_865840\dev10_865840\dev10_865840.cmd">
             <Issue>2445</Issue>
         </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\JitBlue\GitHub_11408\GitHub_11408\GitHub_11408.cmd">
+            <Issue>11408</Issue>
+        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\TypeGeneratorTests\TypeGeneratorTest612\Generated612\*">
             <Issue>6707</Issue>
         </ExcludeList>
diff --git a/tests/scripts/run-gc-reliability-framework.cmd b/tests/scripts/run-gc-reliability-framework.cmd
new file mode 100644 (file)
index 0000000..f9a6ae2
--- /dev/null
@@ -0,0 +1,10 @@
+@rem Licensed to the .NET Foundation under one or more agreements.
+@rem The .NET Foundation licenses this file to you under the MIT license.
+@rem See the LICENSE file in the project root for more information.
+
+@echo off
+
+set CORE_ROOT=%CD%\bin\tests\Windows_NT.%1.%2\Tests\Core_Root
+set FRAMEWORK_DIR=%CD%\bin\tests\Windows_NT.%1.%2\GC\Stress\Framework\ReliabilityFramework
+powershell "%CORE_ROOT%\CoreRun.exe %FRAMEWORK_DIR%\ReliabilityFramework.exe %FRAMEWORK_DIR%\testmix_gc.config | tee stdout.txt"
+
diff --git a/tests/scripts/run-gc-reliability-framework.sh b/tests/scripts/run-gc-reliability-framework.sh
new file mode 100755 (executable)
index 0000000..d1c200e
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+export CORE_ROOT=`pwd`/bin/tests/Windows_NT.$1.$2/Tests/coreoverlay
+FRAMEWORK_DIR=`pwd`/bin/tests/Windows_NT.$1.$2/GC/Stress/Framework/ReliabilityFramework
+$CORE_ROOT/corerun $FRAMEWORK_DIR/ReliabilityFramework.exe $FRAMEWORK_DIR/testmix_gc.config | tee stdout.txt
+
index 11279ae..622e33a 100644 (file)
@@ -18,11 +18,15 @@ setlocal
   set USAGE_DISPLAYED=
   set SHOULD_UPLOAD_TO_BENCHVIEW=
   set BENCHVIEW_PATH=
+  set COLLECTION_FLAGS=stopwatch
+  set ETW_COLLECTION=Off
+  set STABILITY_PREFIX=
 
   call :parse_command_line_arguments %*
   if defined USAGE_DISPLAYED exit /b %ERRORLEVEL%
 
   call :set_test_architecture  || exit /b 1
+  call :set_collection_config  || exit /b 1
   call :verify_benchview_tools || exit /b 1
   call :verify_core_overlay    || exit /b 1
   call :set_perf_run_log       || exit /b 1
@@ -86,7 +90,7 @@ setlocal
   if defined IS_SCENARIO_TEST (
     call :run_cmd corerun.exe "%CORECLR_REPO%\sandbox\%BENCHNAME%.%TEST_FILE_EXT%" --perf:runid Perf 1>"%BENCHNAME_LOG_FILE_NAME%" 2>&1
   ) else (
-    call :run_cmd corerun.exe PerfHarness.dll "%CORECLR_REPO%\sandbox\%BENCHNAME%.%TEST_FILE_EXT%" --perf:runid Perf 1>"%BENCHNAME_LOG_FILE_NAME%" 2>&1
+    call :run_cmd %STABILITY_PREFIX% corerun.exe PerfHarness.dll "%CORECLR_REPO%\sandbox\%BENCHNAME%.%TEST_FILE_EXT%" --perf:runid Perf --perf:collect %COLLECTION_FLAGS% 1>"%BENCHNAME_LOG_FILE_NAME%" 2>&1
   )
 
   IF %ERRORLEVEL% NEQ 0 (
@@ -103,8 +107,12 @@ setlocal
   )
 
   rem Save off the results to the root directory for recovery later in Jenkins
-  call :run_cmd xcopy "Perf-%BENCHNAME%*.xml" "%CORECLR_REPO%\" || exit /b 1
-  call :run_cmd xcopy "Perf-%BENCHNAME%*.etl" "%CORECLR_REPO%\" || exit /b 1
+  IF EXIST "Perf-%BENCHNAME%.xml" (
+    call :run_cmd copy "Perf-%BENCHNAME%.xml" "%CORECLR_REPO%\Perf-%BENCHNAME%-%ETW_COLLECTION%.xml" || exit /b 1
+  )
+  IF EXIST "Perf-%BENCHNAME%.etl" (
+    call :run_cmd copy "Perf-%BENCHNAME%.etl" "%CORECLR_REPO%\Perf-%BENCHNAME%-%ETW_COLLECTION%.etl" || exit /b 1
+  )
 
   exit /b 0
 
@@ -118,6 +126,12 @@ rem ****************************************************************************
     shift
     goto :parse_command_line_arguments
   )
+  IF /I [%~1] == [-stabilityPrefix] (
+    set STABILITY_PREFIX=%~2
+    shift
+    shift
+    goto :parse_command_line_arguments
+  )
   IF /I [%~1] == [-scenarioTest] (
     set IS_SCENARIO_TEST=1
     shift
@@ -134,6 +148,12 @@ rem ****************************************************************************
     shift
     goto :parse_command_line_arguments
   )
+  IF /I [%~1] == [-collectionflags] (
+    set COLLECTION_FLAGS=%~2
+    shift
+    shift
+    goto :parse_command_line_arguments
+  )
   IF /I [%~1] == [-library] (
     set TEST_FILE_EXT=dll
     shift
@@ -208,6 +228,18 @@ rem ****************************************************************************
   )
   exit /b 0
 
+  :set_collection_config
+rem ****************************************************************************
+rem   Set's the config based on the providers used for collection
+rem ****************************************************************************
+  if /I [%COLLECTION_FLAGS%] == [stopwatch] (
+    set ETW_COLLECTION=Off
+  ) else (
+    set ETW_COLLECTION=On
+  )
+  exit /b 0
+
+  
 :set_perf_run_log
 rem ****************************************************************************
 rem   Sets the script's output log file.
@@ -266,6 +298,7 @@ setlocal
   set LV_SUBMISSION_ARGS=%LV_SUBMISSION_ARGS% --config-name "%TEST_CONFIG%"
   set LV_SUBMISSION_ARGS=%LV_SUBMISSION_ARGS% --config Configuration "%TEST_CONFIG%"
   set LV_SUBMISSION_ARGS=%LV_SUBMISSION_ARGS% --config OS "Windows_NT"
+  set LV_SUBMISSION_ARGS=%LV_SUBMISSION_ARGS% --config Profile "%ETW_COLLECTION%"
   set LV_SUBMISSION_ARGS=%LV_SUBMISSION_ARGS% --arch "%TEST_ARCHITECTURE%"
   set LV_SUBMISSION_ARGS=%LV_SUBMISSION_ARGS% --machinepool "PerfSnake"
   call :run_cmd py.exe "%BENCHVIEW_PATH%\submission.py" measurement.json %LV_SUBMISSION_ARGS%
@@ -288,7 +321,7 @@ rem ****************************************************************************
 rem   Script's usage.
 rem ****************************************************************************
   set USAGE_DISPLAYED=1
-  echo run-xunit-perf.cmd -testBinLoc ^<path_to_tests^> [-library] [-arch] ^<x86^|x64^> [-configuration] ^<Release^|Debug^> [-generateBenchviewData] ^<path_to_benchview_tools^> [-runtype] ^<rolling^|private^> [-scenarioTest]
+  echo run-xunit-perf.cmd -testBinLoc ^<path_to_tests^> [-library] [-arch] ^<x86^|x64^> [-configuration] ^<Release^|Debug^> [-generateBenchviewData] ^<path_to_benchview_tools^> [-runtype] ^<rolling^|private^> [-scenarioTest] [-collectionFlags] ^<default^+CacheMisses^+InstructionRetired^+BranchMispredictions^+gcapi^>
   echo/
   echo For the path to the tests you can pass a parent directory and the script will grovel for
   echo all tests in subdirectories and run them.
@@ -300,6 +333,10 @@ rem ****************************************************************************
   echo Runtype sets the runtype that we upload to Benchview, rolling for regular runs, and private for
   echo PRs.
   echo -scenarioTest should be included if you are running a scenario benchmark.
+  echo -collectionFlags This is used to specify what collectoin flags get passed to the performance
+  echo harness that is doing the test running.  If this is not specified we only use stopwatch.
+  echo Other flags are "default", which is the whatever the test being run specified, "CacheMisses",
+  echo "BranchMispredictions", and "InstructionsRetired".  
   exit /b %ERRORLEVEL%
 
 :print_error
index a1ecb28..bed9544 100644 (file)
@@ -12,7 +12,7 @@
           "type": "platform",
           "version": "1.1.0"
         },
-        "xunit.performance.api": "1.0.0-beta-build0003"
+        "xunit.performance.api": "1.0.0-beta-build0004"
       }
     }
   }
index c918557..7ed051c 100644 (file)
@@ -1,10 +1,10 @@
 {
   "dependencies": {
-    "Microsoft.NETCore.ILAsm": "2.0.0-preview2-25303-03",
-    "Microsoft.NETCore.ILDAsm": "2.0.0-preview2-25303-03",
-    "Microsoft.NETCore.Jit": "2.0.0-preview2-25303-03",
-    "Microsoft.NETCore.Runtime.CoreCLR": "2.0.0-preview2-25303-03",
-    "Microsoft.NETCore.TestHost": "2.0.0-preview2-25303-03"
+    "Microsoft.NETCore.ILAsm": "2.0.0-preview2-25309-01",
+    "Microsoft.NETCore.ILDAsm": "2.0.0-preview2-25309-01",
+    "Microsoft.NETCore.Jit": "2.0.0-preview2-25309-01",
+    "Microsoft.NETCore.Runtime.CoreCLR": "2.0.0-preview2-25309-01",
+    "Microsoft.NETCore.TestHost": "2.0.0-preview2-25309-01"
   },
   "frameworks": {
     "netcoreapp2.0": {
index 12c986a..b5e378d 100644 (file)
@@ -1,10 +1,10 @@
 {
   "dependencies": {
     "Microsoft.CodeAnalysis.Compilers": "1.1.1",
-    "xunit.performance.api": "1.0.0-beta-build0003",
-    "xunit.performance.core": "1.0.0-beta-build0003",
-    "xunit.performance.execution": "1.0.0-beta-build0003",
-    "xunit.performance.metrics": "1.0.0-beta-build0003",
+    "xunit.performance.api": "1.0.0-beta-build0004",
+    "xunit.performance.core": "1.0.0-beta-build0004",
+    "xunit.performance.execution": "1.0.0-beta-build0004",
+    "xunit.performance.metrics": "1.0.0-beta-build0004",
     "Microsoft.Diagnostics.Tracing.TraceEvent": "1.0.3-alpha-experimental",
     "Newtonsoft.Json": "9.0.1",
     "xunit": "2.2.0-beta2-build3300",
index c8031bc..da16b39 100644 (file)
@@ -1,7 +1,7 @@
 {
   "dependencies": {
     "Microsoft.NETCore.App": "2.0.0-beta-001494-00",
-    "System.Runtime.CompilerServices.Unsafe": "4.4.0-preview2-25303-04"
+    "System.Runtime.CompilerServices.Unsafe": "4.4.0-preview2-25309-01"
   },
   "frameworks": {
     "netcoreapp2.0": {}
index dde0c93..0db60bc 100644 (file)
@@ -1,6 +1,6 @@
 {
   "dependencies": {
-    "Microsoft.TargetingPack.Private.CoreCLR": "2.0.0-preview2-25303-03"
+    "Microsoft.TargetingPack.Private.CoreCLR": "2.0.0-preview2-25309-01"
   },
   "frameworks": {
     "netcoreapp1.1": {
index 50b1774..847c16b 100644 (file)
@@ -1,10 +1,10 @@
 {
   "dependencies": {
-    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25303-04",
-    "Microsoft.Private.CoreFx.NETCoreApp": "4.4.0-preview2-25303-04",
-    "System.Memory": "4.4.0-preview2-25303-04",
-    "System.Runtime.CompilerServices.Unsafe": "4.4.0-preview2-25303-04",
-    "System.Security.Permissions": "4.4.0-preview2-25303-04"
+    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25309-01",
+    "Microsoft.Private.CoreFx.NETCoreApp": "4.4.0-preview2-25309-01",
+    "System.Memory": "4.4.0-preview2-25309-01",
+    "System.Runtime.CompilerServices.Unsafe": "4.4.0-preview2-25309-01",
+    "System.Security.Permissions": "4.4.0-preview2-25309-01"
   },
   "frameworks": {
     "netcoreapp2.0": {
index 9e4e308..e7ca2fe 100644 (file)
@@ -1,6 +1,6 @@
 {
   "dependencies": {
-    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25303-04",
+    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25309-01",
     "Microsoft.DotNet.CoreCLR.TestDependencies": "1.0.0-prerelease",
     "jit-dasm": "0.0.1.4",
     "cijobs": "0.0.1.2",
index 7b42bd1..91921ab 100644 (file)
@@ -10,9 +10,9 @@
     <OutputType>Exe</OutputType>
     <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
     <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
-    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <CLRTestKind>BuildOnly</CLRTestKind>
+    <GenerateRunScript>false</GenerateRunScript>
     <CLRTestPriority>1</CLRTestPriority>
-    <CLRTestExecutionArguments>testmix_gc.config /maximumExecutionTime:-1</CLRTestExecutionArguments>
     <DefineConstants>$(DefineConstants);STATIC;PROJECTK_BUILD</DefineConstants>
   </PropertyGroup>
   <!-- Default configurations to help VS understand the configurations -->
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_11343/GitHub_11343.cs b/tests/src/JIT/Regression/JitBlue/GitHub_11343/GitHub_11343.cs
new file mode 100644 (file)
index 0000000..e23d9fc
--- /dev/null
@@ -0,0 +1,33 @@
+// 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.
+
+using System;
+using System.Runtime.CompilerServices;
+
+class GitHub_11343
+{
+    const int Passed = 100;
+    const int Failed = 0;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static void Test()
+    {
+        string s = null;
+        // Should throw NullReferenceException even if the result is not used
+        int unused = s.Length;
+    }
+
+    static int Main()
+    {
+        try
+        {
+            Test();
+            return Failed;
+        }
+        catch (NullReferenceException)
+        {
+            return Passed;
+        }
+    }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_11343/GitHub_11343.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_11343/GitHub_11343.csproj
new file mode 100644 (file)
index 0000000..c493c4e
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+  </PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <PropertyGroup>
+    <DebugType></DebugType>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="GitHub_11343.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+  </PropertyGroup> 
+</Project>
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_11408/GitHub_11408.cs b/tests/src/JIT/Regression/JitBlue/GitHub_11408/GitHub_11408.cs
new file mode 100644 (file)
index 0000000..715cd5f
--- /dev/null
@@ -0,0 +1,45 @@
+// 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.
+
+using System;
+using System.Runtime.CompilerServices;
+
+class GitHub_11408
+{
+    const int Pass = 100;
+    const int Fail = -1;
+
+    unsafe class Program
+    {
+        static int save = 7;
+
+        static void foo(IntPtr x)
+        {
+            save = *(int*)x;
+            Console.WriteLine(*(int*)x);
+        }
+
+        static void bar()
+        {
+            int x = 42;
+            foo((IntPtr)(&x));
+        }
+
+        public static int Main(string[] args)
+        {
+            bar();
+
+            if (save == 42)
+            {
+                Console.WriteLine("Pass");
+                return Pass;
+            }
+            else
+            {
+                Console.WriteLine("Fail");
+                return Fail;
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_11408/GitHub_11408.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_11408/GitHub_11408.csproj
new file mode 100644 (file)
index 0000000..251856c
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+  </PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <PropertyGroup>
+    <DebugType></DebugType>
+    <Optimize>True</Optimize>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="GitHub_11408.cs" />
+  </ItemGroup>
+  <PropertyGroup>
+    <CLRTestBatchPreCommands><![CDATA[
+$(CLRTestBatchPreCommands)
+set COMPlus_TailcallStress=1
+]]></CLRTestBatchPreCommands>
+  <BashCLRTestPreCommands><![CDATA[
+$(BashCLRTestPreCommands)
+export COMPlus_TailcallStress=1
+]]></BashCLRTestPreCommands>
+  </PropertyGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+  </PropertyGroup> 
+</Project>
index 493c939..2326932 100644 (file)
@@ -1,20 +1,20 @@
 {
   "dependencies": {
     "Microsoft.CodeAnalysis.Compilers": "1.1.1",
-    "xunit.performance.api": "1.0.0-beta-build0003",
-    "xunit.performance.core": "1.0.0-beta-build0003",
-    "xunit.performance.execution": "1.0.0-beta-build0003",
-    "xunit.performance.metrics": "1.0.0-beta-build0003",
+    "xunit.performance.api": "1.0.0-beta-build0004",
+    "xunit.performance.core": "1.0.0-beta-build0004",
+    "xunit.performance.execution": "1.0.0-beta-build0004",
+    "xunit.performance.metrics": "1.0.0-beta-build0004",
     "Microsoft.Diagnostics.Tracing.TraceEvent": "1.0.3-alpha-experimental",
-    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25303-04",
+    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25309-01",
     "System.Console": "4.4.0-beta-24913-02",
     "System.Dynamic.Runtime": "4.4.0-beta-24913-02",
     "System.Linq": "4.4.0-beta-24913-02",
     "System.IO.FileSystem": "4.4.0-beta-24913-02",
-    "System.Numerics.Vectors": "4.4.0-preview2-25303-04",
+    "System.Numerics.Vectors": "4.4.0-preview2-25309-01",
     "System.Reflection": "4.4.0-beta-24913-02",
     "System.Reflection.Extensions": "4.4.0-beta-24913-02",
-    "System.Reflection.TypeExtensions": "4.4.0-preview2-25303-04",
+    "System.Reflection.TypeExtensions": "4.4.0-preview2-25309-01",
     "System.Runtime": "4.4.0-beta-24913-02",
     "System.Runtime.Extensions": "4.4.0-beta-24913-02",
     "System.Runtime.Numerics": "4.4.0-beta-24913-02",
index 237ae2c..fe78880 100644 (file)
@@ -1,11 +1,11 @@
 {
   "dependencies": {
-    "xunit.performance.api": "1.0.0-beta-build0003",
-    "xunit.performance.core": "1.0.0-beta-build0003",
-    "xunit.performance.execution": "1.0.0-beta-build0003",
-    "xunit.performance.metrics": "1.0.0-beta-build0003",
+    "xunit.performance.api": "1.0.0-beta-build0004",
+    "xunit.performance.core": "1.0.0-beta-build0004",
+    "xunit.performance.execution": "1.0.0-beta-build0004",
+    "xunit.performance.metrics": "1.0.0-beta-build0004",
     "Microsoft.Diagnostics.Tracing.TraceEvent": "1.0.3-alpha-experimental",
-    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25303-04",
+    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25309-01",
     "Newtonsoft.Json": "7.0.1",
     "System.Console": "4.4.0-beta-24913-02",
     "System.IO": "4.4.0-beta-24913-02",
@@ -15,7 +15,7 @@
     "System.Dynamic.Runtime": "4.4.0-beta-24913-02",
     "System.Reflection": "4.4.0-beta-24913-02",
     "System.Reflection.Extensions": "4.4.0-beta-24913-02",
-    "System.Reflection.TypeExtensions": "4.4.0-preview2-25303-04",
+    "System.Reflection.TypeExtensions": "4.4.0-preview2-25309-01",
     "System.Runtime": "4.4.0-beta-24913-02",
     "System.Runtime.Serialization.Json": "4.4.0-beta-24913-02",
     "System.Runtime.Serialization.Primitives": "4.4.0-beta-24913-02",
index a8085d6..6035c4a 100644 (file)
@@ -1,24 +1,24 @@
 {
   "dependencies": {
-    "xunit.performance.api": "1.0.0-beta-build0003",
-    "xunit.performance.core": "1.0.0-beta-build0003",
-    "xunit.performance.execution": "1.0.0-beta-build0003",
-    "xunit.performance.metrics": "1.0.0-beta-build0003",
+    "xunit.performance.api": "1.0.0-beta-build0004",
+    "xunit.performance.core": "1.0.0-beta-build0004",
+    "xunit.performance.execution": "1.0.0-beta-build0004",
+    "xunit.performance.metrics": "1.0.0-beta-build0004",
     "Microsoft.Diagnostics.Tracing.TraceEvent": "1.0.3-alpha-experimental",
-    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25303-04",
+    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25309-01",
     "System.Collections.NonGeneric": "4.4.0-beta-24913-02",
     "System.Console": "4.4.0-beta-24913-02",
     "System.IO.FileSystem": "4.4.0-beta-24913-02",
     "System.Linq": "4.4.0-beta-24913-02",
     "System.Linq.Parallel": "4.4.0-beta-24913-02",
     "System.Linq.Expressions": "4.4.0-beta-24913-02",
-    "System.Memory": "4.4.0-preview2-25303-04",
-    "System.Numerics.Vectors": "4.4.0-preview2-25303-04",
+    "System.Memory": "4.4.0-preview2-25309-01",
+    "System.Numerics.Vectors": "4.4.0-preview2-25309-01",
     "System.Reflection": "4.4.0-beta-24913-02",
     "System.Reflection.Extensions": "4.4.0-beta-24913-02",
-    "System.Reflection.TypeExtensions": "4.4.0-preview2-25303-04",
+    "System.Reflection.TypeExtensions": "4.4.0-preview2-25309-01",
     "System.Runtime": "4.4.0-beta-24913-02",
-    "System.Runtime.CompilerServices.Unsafe": "4.4.0-preview2-25303-04",
+    "System.Runtime.CompilerServices.Unsafe": "4.4.0-preview2-25309-01",
     "System.Runtime.Extensions": "4.4.0-beta-24913-02",
     "System.Runtime.Numerics": "4.4.0-beta-24913-02",
     "System.Text.RegularExpressions": "4.4.0-beta-24913-02",
index 93f7b61..f302bbb 100644 (file)
@@ -1,6 +1,6 @@
 {
   "dependencies": {
-    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25303-04",
+    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25309-01",
     "xunit": "2.2.0-beta2-build3300",
     "xunit.assert": "2.2.0-beta2-build3300",
     "xunit.core": "2.2.0-beta2-build3300",
index f02866d..05d1d24 100644 (file)
@@ -5,16 +5,16 @@
     "xunit.performance.execution": "1.0.0-beta-build0003",
     "xunit.performance.metrics": "1.0.0-beta-build0003",
     "Microsoft.Diagnostics.Tracing.TraceEvent": "1.0.3-alpha-experimental",
-    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25303-04",
+    "Microsoft.NETCore.Platforms": "2.0.0-preview2-25309-01",
     "System.Collections.NonGeneric": "4.4.0-beta-24913-02",
     "System.Console": "4.4.0-beta-24913-02",
     "System.IO.FileSystem": "4.4.0-beta-24913-02",
     "System.Linq": "4.4.0-beta-24913-02",
     "System.Linq.Expressions": "4.4.0-beta-24913-02",
-    "System.Numerics.Vectors": "4.4.0-preview2-25303-04",
+    "System.Numerics.Vectors": "4.4.0-preview2-25309-01",
     "System.Reflection": "4.4.0-beta-24913-02",
     "System.Reflection.Extensions": "4.4.0-beta-24913-02",
-    "System.Reflection.TypeExtensions": "4.4.0-preview2-25303-04",
+    "System.Reflection.TypeExtensions": "4.4.0-preview2-25309-01",
     "System.Runtime": "4.4.0-beta-24913-02",
     "System.Runtime.Extensions": "4.4.0-beta-24913-02",
     "System.Runtime.Loader": "4.0.0",
index f286b21..3b59343 100644 (file)
@@ -57,6 +57,7 @@ JIT/Methodical/Boxing/xlang/_dbgsin_cs_il/_dbgsin_cs_il.sh
 JIT/Methodical/Boxing/xlang/_odbgsin_cs_il/_odbgsin_cs_il.sh
 JIT/Methodical/Boxing/xlang/_orelsin_cs_il/_orelsin_cs_il.sh
 JIT/Methodical/Boxing/xlang/_relsin_cs_il/_relsin_cs_il.sh
+JIT/Regression/JitBlue/GitHub_11408/GitHub_11408/GitHub_11408.sh
 Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp/MarshalStructAsLayoutExp.sh
 GC/LargeMemory/Allocation/finalizertest/finalizertest.sh
 GC/LargeMemory/API/gc/reregisterforfinalize/reregisterforfinalize.sh