bld/
[Bb]in/
[Oo]bj/
+localpkg/
msbuild.log
# add back architecture directories ignored in 'Build results'
-1.0.27-prerelease-01205-03
\ No newline at end of file
+1.0.27-prerelease-01209-01
JIT64 attempts to speed the normal control flow by 'inlining' a called finally along the 'normal' control flow (i.e., leaving a try body in a non-exceptional manner via C# fall-through). Because the VM semantics for non-rude Thread.Abort dictate that handlers will not be aborted, the JIT must mark these 'inlined' finally bodies. These show up as special entries at the end of the EH tables and are marked with `COR_ILEXCEPTION_CLAUSE_FINALLY | COR_ILEXCEPTION_CLAUSE_DUPLICATED`, and the try_start, try_end, and handler_start are all the same: the start of the cloned finally.
-JIT32 and RyuJIT currently do not implement finally cloning.
+RyuJit also implements finally cloning, for all supported architectures. However, the implementation does not yet handle the thread abort case; cloned finally bodies are not guaranteed to remain intact and are not reported to the runtime. Because of this, finally cloning is disabled for VMs that support thread abort (desktop clr).
+
+JIT32 does not implement finally cloning.
## Invoking Finallys/Non-local exits
--- /dev/null
+Finally Optimizations
+=====================
+
+In MSIL, a try-finally is a construct where a block of code
+(the finally) is guaranteed to be executed after control leaves a
+protected region of code (the try) either normally or via an
+exception.
+
+In RyuJit a try-finally is currently implemented by transforming the
+finally into a local function that is invoked via jitted code at normal
+exits from the try block and is invoked via the runtime for exceptional
+exits from the try block.
+
+For x86 the local function is simply a part of the method and shares
+the same stack frame with the method. For other architectures the
+local function is promoted to a potentially separable "funclet"
+which is almost like a regular function with a prolog and epilog. A
+custom calling convention gives the funclet access to the parent stack
+frame.
+
+In this proposal we outline two optimizations for finallys: removing
+empty finallys and finally cloning.
+
+Empty Finally Removal
+---------------------
+
+An empty finally is one that has no observable effect. These often
+arise from `foreach` or `using` constructs (which induce a
+try-finally) where the cleanup method called in the finally does
+nothing. Often, after inlining, the empty finally is readily apparent.
+
+For example, this snippet of C# code
+```C#
+static int Sum(List<int> x) {
+ int sum = 0;
+ foreach(int i in x) {
+ sum += i;
+ }
+ return sum;
+}
+```
+produces the following jitted code:
+```asm
+; Successfully inlined Enumerator[Int32][System.Int32]:Dispose():this
+; (1 IL bytes) (depth 1) [below ALWAYS_INLINE size]
+G_M60484_IG01:
+ 55 push rbp
+ 57 push rdi
+ 56 push rsi
+ 4883EC50 sub rsp, 80
+ 488D6C2460 lea rbp, [rsp+60H]
+ 488BF1 mov rsi, rcx
+ 488D7DD0 lea rdi, [rbp-30H]
+ B906000000 mov ecx, 6
+ 33C0 xor rax, rax
+ F3AB rep stosd
+ 488BCE mov rcx, rsi
+ 488965C0 mov qword ptr [rbp-40H], rsp
+
+G_M60484_IG02:
+ 33C0 xor eax, eax
+ 8945EC mov dword ptr [rbp-14H], eax
+ 8B01 mov eax, dword ptr [rcx]
+ 8B411C mov eax, dword ptr [rcx+28]
+ 33D2 xor edx, edx
+ 48894DD0 mov gword ptr [rbp-30H], rcx
+ 8955D8 mov dword ptr [rbp-28H], edx
+ 8945DC mov dword ptr [rbp-24H], eax
+ 8955E0 mov dword ptr [rbp-20H], edx
+
+G_M60484_IG03:
+ 488D4DD0 lea rcx, bword ptr [rbp-30H]
+ E89B35665B call Enumerator[Int32][System.Int32]:MoveNext():bool:this
+ 85C0 test eax, eax
+ 7418 je SHORT G_M60484_IG05
+
+; Body of foreach loop
+
+G_M60484_IG04:
+ 8B4DE0 mov ecx, dword ptr [rbp-20H]
+ 8B45EC mov eax, dword ptr [rbp-14H]
+ 03C1 add eax, ecx
+ 8945EC mov dword ptr [rbp-14H], eax
+ 488D4DD0 lea rcx, bword ptr [rbp-30H]
+ E88335665B call Enumerator[Int32][System.Int32]:MoveNext():bool:this
+ 85C0 test eax, eax
+ 75E8 jne SHORT G_M60484_IG04
+
+; Normal exit from the implicit try region created by `foreach`
+; Calls the finally to dispose of the iterator
+
+G_M60484_IG05:
+ 488BCC mov rcx, rsp
+ E80C000000 call G_M60484_IG09 // call to finally
+
+G_M60484_IG06:
+ 90 nop
+
+G_M60484_IG07:
+ 8B45EC mov eax, dword ptr [rbp-14H]
+
+G_M60484_IG08:
+ 488D65F0 lea rsp, [rbp-10H]
+ 5E pop rsi
+ 5F pop rdi
+ 5D pop rbp
+ C3 ret
+
+; Finally funclet. Note it simply sets up and then tears down a stack
+; frame. The dispose method was inlined and is empty.
+
+G_M60484_IG09:
+ 55 push rbp
+ 57 push rdi
+ 56 push rsi
+ 4883EC30 sub rsp, 48
+ 488B6920 mov rbp, qword ptr [rcx+32]
+ 48896C2420 mov qword ptr [rsp+20H], rbp
+ 488D6D60 lea rbp, [rbp+60H]
+
+G_M60484_IG10:
+ 4883C430 add rsp, 48
+ 5E pop rsi
+ 5F pop rdi
+ 5D pop rbp
+ C3 ret
+```
+
+In such cases the try-finally can be removed, leading to code like the following:
+```asm
+G_M60484_IG01:
+ 57 push rdi
+ 56 push rsi
+ 4883EC38 sub rsp, 56
+ 488BF1 mov rsi, rcx
+ 488D7C2420 lea rdi, [rsp+20H]
+ B906000000 mov ecx, 6
+ 33C0 xor rax, rax
+ F3AB rep stosd
+ 488BCE mov rcx, rsi
+
+G_M60484_IG02:
+ 33F6 xor esi, esi
+ 8B01 mov eax, dword ptr [rcx]
+ 8B411C mov eax, dword ptr [rcx+28]
+ 48894C2420 mov gword ptr [rsp+20H], rcx
+ 89742428 mov dword ptr [rsp+28H], esi
+ 8944242C mov dword ptr [rsp+2CH], eax
+ 89742430 mov dword ptr [rsp+30H], esi
+
+G_M60484_IG03:
+ 488D4C2420 lea rcx, bword ptr [rsp+20H]
+ E8A435685B call Enumerator[Int32][System.Int32]:MoveNext():bool:this
+ 85C0 test eax, eax
+ 7414 je SHORT G_M60484_IG05
+
+G_M60484_IG04:
+ 8B4C2430 mov ecx, dword ptr [rsp+30H]
+ 03F1 add esi, ecx
+ 488D4C2420 lea rcx, bword ptr [rsp+20H]
+ E89035685B call Enumerator[Int32][System.Int32]:MoveNext():bool:this
+ 85C0 test eax, eax
+ 75EC jne SHORT G_M60484_IG04
+
+G_M60484_IG05:
+ 8BC6 mov eax, esi
+
+G_M60484_IG06:
+ 4883C438 add rsp, 56
+ 5E pop rsi
+ 5F pop rdi
+ C3 ret
+```
+
+Empty finally removal is unconditionally profitable: it should always
+reduce code size and improve code speed.
+
+Finally Cloning
+---------------
+
+Finally cloning is an optimization where the jit duplicates the code
+in the finally for one or more of the normal exit paths from the try,
+and has those exit points branch to the duplicated code directly,
+rather than calling the finally. This transformation allows for
+improved performance and optimization of the common case where the try
+completes without an exception.
+
+Finally cloning also allows hot/cold splitting of finally bodies: the
+cloned finally code covers the normal try exit paths (the hot cases)
+and can be placed in the main method region, and the original finally,
+now used largely or exclusively for exceptional cases (the cold cases)
+spilt off into the cold code region. Without cloning, RyuJit
+would always treat the finally as cold code.
+
+Finally cloning will increase code size, though often the size
+increase is mitigated somewhat by more compact code generation in the
+try body and streamlined invocation of the cloned finallys.
+
+Try-finally regions may have multiple normal exit points. For example
+the following `try` has two: one at the `return 3` and one at the try
+region end:
+
+```C#
+try {
+ if (p) return 3;
+ ...
+}
+finally {
+ ...
+}
+return 4;
+```
+
+Here the finally must be executed no matter how the try exits. So
+there are to two normal exit paths from the try, both of which pass
+through the finally but which then diverge. The fact that some try
+regions can have multiple exits opens the potential for substantial
+code growth from finally cloning, and so leads to a choice point in
+the implementation:
+
+* Share the clone along all exit paths
+* Share the clone along some exit paths
+* Clone along all exit paths
+* Clone along some exit paths
+* Only clone along one exit path
+* Only clone when there is one exit path
+
+The shared clone option must essentially recreate or simulate the
+local call mechanism for the finally, though likely somewhat more
+efficiently. Each exit point must designate where control should
+resume once the shared finally has finished. For instance the jit
+could introduce a new local per try-finally to determine where the
+cloned finally should resume, and enumerate the possibilities using a
+small integer. The end of the cloned finally would then use a switch
+to determine what code to execute next. This has the downside of
+introducing unrealizable paths into the control flow graph.
+
+Cloning along all exit paths can potentially lead to large amounts of
+code growth.
+
+Cloning along some paths or only one path implies that some normal
+exit paths won't be as well optimized. Nonetheless cloning along one
+path was the choice made by JIT64 and the one we recommend for
+implementation. In particular we suggest only cloning along the end of
+try region exit path, so that any early exit will continue to invoke
+the funclet for finally cleanup (unless that exit happens to have the
+same post-finally continuation as the end try region exit, in which
+case it can simply jump to the cloned finally).
+
+One can imagine adaptive strategies. The size of the finally can
+be roughly estimated and the number of clones needed for full cloning
+readily computed. Selective cloning can be based on profile
+feedback or other similar mechanisms for choosing the profitable
+cases.
+
+The current implementation will clone the finally and retarget the
+last (largest IL offset) leave in the try region to the clone. Any
+other leave that ultimately transfers control to the same post-finally
+offset will also be modified to jump to the clone.
+
+Empirical studies have shown that most finallys are small. Thus to
+avoid excessive code growth, a crude size estimate is formed by
+counting the number of statements in the blocks that make up the
+finally. Any finally larger that 15 statements is not cloned. In our
+study this disqualifed about 0.5% of all finallys from cloning.
+
+### EH Nesting Considerations
+
+Finally cloning is also more complicated when the finally encloses
+other EH regions, since the clone will introduce copies of all these
+regions. While it is possible to implement cloning in such cases we
+propose to defer for now.
+
+Finally cloning is also a bit more complicated if the finally is
+enclosed by another finally region, so we likewise propose deferring
+support for this. (Seems like a rare enough thing but maybe not too
+hard to handle -- though possibly not worth it if we're not going to
+support the enclosing case).
+
+### Control-Flow and Other Considerations
+
+If the try never exits normally, then the finally can only be invoked
+in exceptional cases. There is no benefit to cloning since the cloned
+finally would be unreachable. We can detect a subset of such cases
+because there will be no call finally blocks.
+
+JIT64 does not clone finallys that contained switch. We propose to
+do likewise. (Initially I did not include this restriction but
+hit a failing test case where the finally contained a switch. Might be
+worth a deeper look, though such cases are presumably rare.)
+
+If the finally never exits normally, then we presume it is cold code,
+and so will not clone.
+
+If the finally is marked as run rarely, we will not clone.
+
+Implementation Proposal
+-----------------------
+
+We propose that empty finally removal and finally cloning be run back
+to back, spliced into the phase list just after fgInline and
+fgAddInternal, and just before implicit by-ref and struct
+promotion. We want to run these early before a lot of structural
+invariants regarding EH are put in place, and before most
+other optimization, but run them after inlining
+(so empty finallys can be more readily identified) and after the
+addition of implicit try-finallys created by the jit. Empty finallys
+may arise later because of optimization, but this seems relatively
+uncommon.
+
+We will remove empty finallys first, then clone.
+
+Neither optimization will run when the jit is generating debuggable
+code or operating in min opts mode.
+
+### Empty Finally Removal (Sketch)
+
+Skip over methods that have no EH, are compiled with min opts, or
+where the jit is generating debuggable code.
+
+Walk the handler table, looking for try-finally (we could also look
+for and remove try-faults with empty faults, but those are presumably
+rare).
+
+If the finally is a single block and contains only a `retfilter`
+statement, then:
+
+* Retarget the callfinally(s) to jump always to the continuation blocks.
+* Remove the paired jump always block(s) (note we expect all finally
+calls to be paired since the empty finally returns).
+* For funclet EH models with finally target bits, clear the finally
+target from the continuations.
+* For non-funclet EH models only, clear out the GT_END_LFIN statement
+in the finally continuations.
+* Remove the handler block.
+* Reparent all directly contained try blocks to the enclosing try region
+or to the method region if there is no enclosing try.
+* Remove the try-finally from the EH table via `fgRemoveEHTableEntry`.
+
+After the walk, if any empty finallys were removed, revalidate the
+integrity of the handler table.
+
+### Finally Cloning (Sketch)
+
+Skip over all methods, if the runtime suports thread abort. More on
+this below.
+
+Skip over methods that have no EH, are compiled with min opts, or
+where the jit is generating debuggable code.
+
+Walk the handler table, looking for try-finally. If the finally is
+enclosed in a handler or encloses another handler, skip.
+
+Walk the finally body blocks. If any is BBJ_SWITCH, or if none
+is BBJ_EHFINALLYRET, skip cloning. If all blocks are RunRarely
+skip cloning. If the finally has more that 15 statements, skip
+cloning.
+
+Walk the try region from back to front (from largest to smallest IL
+offset). Find the last block in the try that invokes the finally. That
+will be the path that will invoke the clone.
+
+If the EH model requires callfinally thunks, and there are multiple
+thunks that invoke the finally, and the callfinally thunk along the
+clone path is not the first, move it to the front (this helps avoid
+extra jumps).
+
+Set the insertion point to just after the callfinally in the path (for
+thunk models) or the end of the try (for non-thunk models). Set up a
+block map. Clone the finally body using `fgNewBBinRegion` and
+`fgNewBBafter` to make the first and subsequent blocks, and
+`CloneBlockState` to fill in the block contents. Clear the handler
+region on the cloned blocks. Bail out if cloning fails. Mark the first
+and last cloned blocks with appropriate BBF flags. Patch up inter-clone
+branches and convert the returns into jumps to the continuation.
+
+Walk the callfinallys, retargeting the ones that return to the
+continuation so that they invoke the clone. Remove the paired always
+blocks. Clear the finally target bit and any GT_END_LFIN from the
+continuation.
+
+If all call finallys are converted, modify the region to be try/fault
+(interally EH_HANDLER_FAULT_WAS_FINALLY, so we can distinguish it
+later from "organic" try/faults). Otherwise leave it as a
+try/finally.
+
+Clear the catch type on the clone entry.
+
+### Thread Abort
+
+For runtimes that support thread abort (desktop), more work is
+required:
+
+* The cloned finally must be reported to the runtime. Likely this
+can trigger off of the BBF_CLONED_FINALLY_BEGIN/END flags.
+* The jit must maintain the integrity of the clone by not losing
+track of the blocks involved, and not allowing code to move in our
+out of the cloned region
+
+Code Size Impact
+----------------
+
+Code size impact from finally cloning was measured for CoreCLR on
+Windows x64.
+
+```
+Total bytes of diff: 16158 (0.12 % of base)
+ diff is a regression.
+Total byte diff includes 0 bytes from reconciling methods
+ Base had 0 unique methods, 0 unique bytes
+ Diff had 0 unique methods, 0 unique bytes
+Top file regressions by size (bytes):
+ 3518 : Microsoft.CodeAnalysis.CSharp.dasm (0.16 % of base)
+ 1895 : System.Linq.Expressions.dasm (0.32 % of base)
+ 1626 : Microsoft.CodeAnalysis.VisualBasic.dasm (0.07 % of base)
+ 1428 : System.Threading.Tasks.Parallel.dasm (4.66 % of base)
+ 1248 : System.Linq.Parallel.dasm (0.20 % of base)
+Top file improvements by size (bytes):
+ -4529 : System.Private.CoreLib.dasm (-0.14 % of base)
+ -975 : System.Reflection.Metadata.dasm (-0.28 % of base)
+ -239 : System.Private.Uri.dasm (-0.27 % of base)
+ -104 : System.Runtime.InteropServices.RuntimeInformation.dasm (-3.36 % of base)
+ -99 : System.Security.Cryptography.Encoding.dasm (-0.61 % of base)
+57 total files with size differences.
+Top method regessions by size (bytes):
+ 645 : System.Diagnostics.Process.dasm - System.Diagnostics.Process:StartCore(ref):bool:this
+ 454 : Microsoft.CSharp.dasm - Microsoft.CSharp.RuntimeBinder.Semantics.ExpressionBinder:AdjustCallArgumentsForParams(ref,ref,ref,ref,ref,byref):this
+ 447 : System.Threading.Tasks.Dataflow.dasm - System.Threading.Tasks.Dataflow.Internal.SpscTargetCore`1[__Canon][System.__Canon]:ProcessMessagesLoopCore():this
+ 421 : Microsoft.CodeAnalysis.VisualBasic.dasm - Microsoft.CodeAnalysis.VisualBasic.Symbols.ImplementsHelper:FindExplicitlyImplementedMember(ref,ref,ref,ref,ref,ref,byref):ref
+ 358 : System.Private.CoreLib.dasm - System.Threading.TimerQueueTimer:Change(int,int):bool:this
+Top method improvements by size (bytes):
+ -2512 : System.Private.CoreLib.dasm - DomainNeutralILStubClass:IL_STUB_CLRtoWinRT():ref:this (68 methods)
+ -824 : Microsoft.CodeAnalysis.dasm - Microsoft.Cci.PeWriter:WriteHeaders(ref,ref,ref,ref,byref):this
+ -663 : System.Private.CoreLib.dasm - DomainNeutralILStubClass:IL_STUB_CLRtoWinRT(ref):int:this (17 methods)
+ -627 : System.Private.CoreLib.dasm - System.Diagnostics.Tracing.ManifestBuilder:CreateManifestString():ref:this
+ -546 : System.Private.CoreLib.dasm - DomainNeutralILStubClass:IL_STUB_WinRTtoCLR(long):int:this (67 methods)
+3014 total methods with size differences.
+```
+
+The largest growth is seen in `Process:StartCore`, which has 4
+try-finally constructs.
+
+Diffs generally show improved codegen in the try bodies with cloned
+finallys. However some of this improvement comes from more aggressive
+use of callee save registers, and this causes size inflation in the
+funclets (note finally cloning does not alter the number of
+funclets). So if funclet save/restore could be contained to registers
+used in the funclet, the size impact would be slightly smaller.
+
+There are also some instances where cloning relatively small finallys
+leads to large code size increases. xxx is one example.
add_definitions(-DUNIX_AMD64_ABI)
elseif (CLR_CMAKE_PLATFORM_UNIX_ARM)
add_definitions(-DUNIX_ARM_ABI)
+ elseif (CLR_CMAKE_PLATFORM_UNIX_X86)
+ add_definitions(-DUNIX_X86_ABI)
endif()
endif(CLR_CMAKE_PLATFORM_UNIX)
<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>ef2f3c2b059e208ac188399cc10204861f9dfb70</CoreFxCurrentRef>
- <CoreClrCurrentRef>ef2f3c2b059e208ac188399cc10204861f9dfb70</CoreClrCurrentRef>
+ <CoreFxCurrentRef>50316aab6400fcb2894d608f997d6483962b6642</CoreFxCurrentRef>
+ <CoreClrCurrentRef>50316aab6400fcb2894d608f997d6483962b6642</CoreClrCurrentRef>
</PropertyGroup>
<!-- Auto-upgraded properties for each build info dependency. -->
<PropertyGroup>
- <CoreFxExpectedPrerelease>beta-24906-02</CoreFxExpectedPrerelease>
+ <CoreFxExpectedPrerelease>beta-24911-08</CoreFxExpectedPrerelease>
</PropertyGroup>
<!-- Full package version strings that are used in other parts of the build. -->
<PropertyGroup>
- <CoreClrPackageVersion>1.2.0-beta-24906-01</CoreClrPackageVersion>
+ <CoreClrPackageVersion>1.2.0-beta-24911-02</CoreClrPackageVersion>
<XunitPackageVersion>2.2.0-beta2-build3300</XunitPackageVersion>
</PropertyGroup>
if (configuration == 'Checked') {
Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} Build and Test")
}
+ else if (configuration == 'Release') {
+ Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} Build and Test",
+ "(?i).*test\\W+${os}\\W+${architecture}\\W+${configuration}.*")
+ }
break
case 'pri1':
if (configuration == 'Release') {
}
if (scenario == 'gcstress15_pri1r2r')
{
- gcstressStr = 'gcstresslevel 0xF'
+ gcstressStr = 'gcstresslevel 0xF'
}
if (scenario == 'jitdiff')
// 10s of thousands of files around.
buildCommands += "powershell -Command \"Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('.\\bin\\tests\\${osGroup}.${arch}.${configuration}', '.\\bin\\tests\\tests.zip')\"";
- if (!Constants.jitStressModeScenarios.containsKey(scenario) && scenario != 'jitdiff') {
+ if (!Constants.jitStressModeScenarios.containsKey(scenario)) {
// For windows, pull full test results and test drops for x86/x64.
// No need to pull for stress mode scenarios (downstream builds use the default scenario)
Utilities.addArchival(newJob, "bin/Product/**,bin/tests/tests.zip")
--mountPath=${armrootfs_mountpath} \\
--buildConfig=${lowerConfiguration} \\
--testRootDir=./bin/tests/Windows_NT.x64.${configuration} \\
- --coreFxNativeBinDir=./bin/Linux.arm-softfp.${configuration} \\
+ --coreFxNativeBinDir=./bin/Linux.armel.${configuration} \\
--coreFxBinDir=\"./bin/Linux.AnyCPU.${configuration};./bin/Unix.AnyCPU.${configuration};./bin/AnyOS.AnyCPU.${configuration}\" \\
--testDirFile=./tests/testsRunningInsideARM.txt"""
{
parameters
{
- stringParam('BenchviewCommitName', '%ghprbPullTitle%', 'The name that you will be used to build the full title of a run in Benchview. The final name will be of the form <branch> private BenchviewCommitName')
+ stringParam('BenchviewCommitName', '\${ghprbPullTitle}', 'The name that you will be used to build the full title of a run in Benchview. The final name will be of the form <branch> private BenchviewCommitName')
}
}
def configuration = 'Release'
{
parameters
{
- stringParam('BenchviewCommitName', '\$ghprbPullTitle', 'The name that you will be used to build the full title of a run in Benchview. The final name will be of the form <branch> private BenchviewCommitName')
+ stringParam('BenchviewCommitName', '\${ghprbPullTitle}', 'The name that you will be used to build the full title of a run in Benchview. The final name will be of the form <branch> private BenchviewCommitName')
}
}
def osGroup = getOSGroup(os)
--- /dev/null
+<?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>
+ <!-- This property must be set to the same value as $(PackageOutputPath) for the nuspecs and nupkgs to be binplaced to the intended location. -->
+ <OutputPath>$(PackageOutputPath)</OutputPath>
+ </PropertyGroup>
+
+ <!-- We always build the identity/redirection package. However, the platform specific runtime-*.nupkg is built based upon the target OS we are building the product for. -->
+ <ItemGroup>
+ <Project Include="Microsoft.NETCore.Native.pkgproj">
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'linux-x64'" Include="linux/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'debian.8-x64'" Include="debian/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'fedora.23-x64'" Include="fedora/23/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'fedora.24-x64'" Include="fedora/24/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'opensuse.13.2-x64'" Include="opensuse/13.2/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'opensuse.42.1-x64'" Include="opensuse/42.1/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and $(DistroRid.StartsWith('rhel.7'))" Include="rhel/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'ubuntu.14.04-x64'" Include="ubuntu/14.04/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'ubuntu.16.04-x64'" Include="ubuntu/16.04/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'ubuntu.16.10-x64'" Include="ubuntu/16.10/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsLinux)' == 'true' and '$(DistroRid)' == 'alpine.3.4.3-x64'" Include="alpine/3.4.3/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>Linux</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ <Project Condition="'$(TargetsOSX)' == 'true'" Include="osx/Microsoft.NETCore.Native.pkgproj">
+ <OSGroup>OSX</OSGroup>
+ <Platform>amd64</Platform>
+ </Project>
+ </ItemGroup>
+
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <SkipValidatePackage>true</SkipValidatePackage>
+ <PackagePlatforms>x64;x86;arm64;arm;</PackagePlatforms>
+ <OutputPath>$(PackagesOutputPath)</OutputPath>
+ <IncludeRuntimeJson>true</IncludeRuntimeJson>
+ </PropertyGroup>
+ <ItemGroup>
+ <ProjectReference Include="linux\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="debian\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="fedora\23\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="fedora\24\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="opensuse\13.2\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="opensuse\42.1\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="rhel\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="ubuntu\14.04\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="ubuntu\16.04\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="ubuntu\16.10\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="alpine\3.4.3\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ <ProjectReference Include="osx\Microsoft.NETCore.Native.pkgproj">
+ <Platform>amd64</Platform>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>alpine.3.4.3-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>debian.8-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>fedora.23-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>fedora.24-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>linux-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>opensuse.13.2-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>opensuse.42.1-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>osx.10.10-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.dylib" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dwarf')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dwarf" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dylib" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>rhel.7-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>ubuntu.14.04-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>ubuntu.16.04-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+<?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>
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ <PackageTargetRuntime>ubuntu.16.10-$(PackagePlatform)</PackageTargetRuntime>
+ <!-- only build for x64 -->
+ <PackagePlatforms>x64;</PackagePlatforms>
+ </PropertyGroup>
+ <ItemGroup>
+ <NativeBinary Include="$(BinDir)libSystem.Globalization.Native.a" />
+ <NativeSplittableBinary Include="$(BinDir)System.Globalization.Native.so" />
+ <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" />
+ <File Include="@(ArchitectureSpecificNativeFile);@(NativeBinary)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ </File>
+ </ItemGroup>
+ <ItemGroup Condition="'$(__BuildType)' == 'Release'">
+ <ArchitectureSpecificNativeSymbol Include="@(NativeSplittableBinary -> '%(Identity).dbg')" />
+ <AdditionalLibPackageExcludes Include="%2A%2A\%2A.dbg" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.so" />
+ <AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
+ <ArchitectureSpecificNativeSymbol Include="..\..\..\_.pdb" />
+ <File Include="@(ArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
"Name": "Microsoft.NETCore.TestHost",
"Description": "CoreCLR application host for test applications",
"CommonTypes": [ ]
+ },
+ {
+ "Name": "Microsoft.NETCore.Native",
+ "Description": "Native shims for .NET Core runtime",
+ "CommonTypes": [ ]
}
]
<ItemGroup Condition="'$(__SkipNativeBuild)'==''">
<Project Include="Microsoft.NETCore.Jit\Microsoft.NETCore.Jit.builds" />
<Project Include="Microsoft.NETCore.TestHost\Microsoft.NETCore.TestHost.builds" />
+ <Project Include="Microsoft.NETCore.Native\Microsoft.NETCore.Native.builds" />
</ItemGroup>
<ItemGroup>
namespace ARMGCDump
{
#undef _TARGET_X86_
+#define WIN64EXCEPTIONS
#undef LIMITED_METHOD_CONTRACT
#define LIMITED_METHOD_DAC_CONTRACT
#define SUPPORTS_DAC
\**********************************************************************/
void PrintHeapSize(DWORD_PTR total, DWORD_PTR wasted)
{
- ExtOut("Size: 0x%" POINTERSIZE_TYPE "x (%" POINTERSIZE_TYPE "lu) bytes", total, total);
+ ExtOut("Size: 0x%" POINTERSIZE_TYPE "x (%" POINTERSIZE_TYPE "u) bytes", total, total);
if (wasted)
- ExtOut(" total, 0x%" POINTERSIZE_TYPE "x (%" POINTERSIZE_TYPE "lu) bytes wasted", wasted, wasted);
+ ExtOut(" total, 0x%" POINTERSIZE_TYPE "x (%" POINTERSIZE_TYPE "u) bytes wasted", wasted, wasted);
ExtOut(".\n");
}
endif()
# Check for LLDB library
-find_library(LLDB NAMES LLDB lldb lldb-3.8 lldb-3.6 lldb-3.5 PATHS "${WITH_LLDB_LIBS}" PATH_SUFFIXES llvm NO_DEFAULT_PATH)
-find_library(LLDB NAMES LLDB lldb lldb-3.8 lldb-3.6 lldb-3.5 PATH_SUFFIXES llvm)
+find_library(LLDB NAMES LLDB lldb lldb-3.8 lldb-3.7 lldb-3.6 lldb-3.5 PATHS "${WITH_LLDB_LIBS}" PATH_SUFFIXES llvm NO_DEFAULT_PATH)
+find_library(LLDB NAMES LLDB lldb lldb-3.8 lldb-3.7 lldb-3.6 lldb-3.5 PATH_SUFFIXES llvm)
if(LLDB STREQUAL LLDB-NOTFOUND)
if(REQUIRE_LLDBPLUGIN)
message(FATAL_ERROR "Cannot find lldb-3.5, lldb-3.6 or lldb-3.8. Try installing lldb-3.6-dev (or the appropriate package for your platform)")
if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.8/include")
if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
- find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.6/include")
- if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
- find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.5/include")
- if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
- if(REQUIRE_LLDBPLUGIN)
- message(FATAL_ERROR "Cannot find LLDB.h. Try installing lldb-3.6-dev (or the appropriate package for your platform)")
- else()
- message(WARNING "Cannot find LLDB.h Try installing lldb-3.6-dev (or the appropriate package for your platform)")
- endif()
- return()
- endif()
- endif()
+ find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.7/include")
+ if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
+ find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.6/include")
+ if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
+ find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.5/include")
+ if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
+ if(REQUIRE_LLDBPLUGIN)
+ message(FATAL_ERROR "Cannot find LLDB.h. Try installing lldb-3.6-dev (or the appropriate package for your platform)")
+ else()
+ message(WARNING "Cannot find LLDB.h Try installing lldb-3.6-dev (or the appropriate package for your platform)")
+ endif()
+ return()
+ endif()
+ endif()
+ endif()
endif()
endif()
${NATIVEGLOBALIZATION_SOURCES}
)
+_add_library(System.Globalization.Native_Static
+ STATIC
+ ${NATIVEGLOBALIZATION_SOURCES}
+)
+
+# Remove the _Static postfix from the static library name
+set_target_properties(System.Globalization.Native_Static PROPERTIES OUTPUT_NAME System.Globalization.Native)
+
# Disable the "lib" prefix.
set_target_properties(System.Globalization.Native PROPERTIES PREFIX "")
${ICUUC}
${ICUI18N}
)
+ target_link_libraries(System.Globalization.Native_Static
+ ${ICUUC}
+ ${ICUI18N}
+ )
elseif(NOT CMAKE_SYSTEM_NAME STREQUAL FreeBSD AND NOT CMAKE_SYSTEM_NAME STREQUAL NetBSD)
target_link_libraries(System.Globalization.Native
dl
)
+ target_link_libraries(System.Globalization.Native_Static
+ dl
+ )
endif()
else()
target_link_libraries(System.Globalization.Native
# add the install targets
install_clr(System.Globalization.Native)
+install(TARGETS System.Globalization.Native_Static DESTINATION .)
#ifdef FEATURE_PAL
HRESULT
-DacVirtualUnwind(DWORD threadId, PCONTEXT context, PT_KNONVOLATILE_CONTEXT_POINTERS contextPointers)
+DacVirtualUnwind(DWORD threadId, PT_CONTEXT context, PT_KNONVOLATILE_CONTEXT_POINTERS contextPointers)
{
if (!g_dacImpl)
{
// Pulls in sequence points and local variable info
DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, pMethodDesc);
-#ifdef WIN64EXCEPTIONS
+#if defined(WIN64EXCEPTIONS) && defined(USE_GC_INFO_DECODER)
if (addr != NULL)
{
DacEnumMemoryRegion(dac_cast<TADDR>(pGCInfo), gcDecoder.GetNumBytesRead(), true);
}
}
-#endif // WIN64EXCEPTIONS
+#endif // WIN64EXCEPTIONS && USE_GC_INFO_DECODER
}
pMethodDefinition.Clear();
}
// new-style constructor
CordbMiscFrame(DebuggerIPCE_JITFuncData * pJITFuncData);
-#if defined(DBG_TARGET_WIN64) || defined(DBG_TARGET_ARM)
+#ifdef WIN64EXCEPTIONS
SIZE_T parentIP;
FramePointer fpParentOrSelf;
bool fIsFilterFunclet;
-#endif // DBG_TARGET_WIN64 || DBG_TARGET_ARM
+#endif // WIN64EXCEPTIONS
};
// the real constructor which stores the funclet-related information in the CordbMiscFrame
CordbMiscFrame::CordbMiscFrame(DebuggerIPCE_JITFuncData * pJITFuncData)
{
-#if defined(DBG_TARGET_WIN64) || defined(DBG_TARGET_ARM)
+#ifdef WIN64EXCEPTIONS
this->parentIP = pJITFuncData->parentNativeOffset;
this->fpParentOrSelf = pJITFuncData->fpParentOrSelf;
this->fIsFilterFunclet = (pJITFuncData->fIsFilterFrame == TRUE);
-#endif // DBG_TARGET_WIN64 || DBG_TARGET_ARM
+#endif // WIN64EXCEPTIONS
}
/* ------------------------------------------------------------------------- *
{
case 0xff:
{
-
BYTE modrm = *ip++;
- _ASSERT(modrm != NULL);
+ // Ignore "inc dword ptr [reg]" instructions
+ if (modrm == 0)
+ break;
BYTE mod = (modrm & 0xC0) >> 6;
BYTE reg = (modrm & 0x38) >> 3;
LSPTR_DJI nativeCodeJITInfoToken;
VMPTR_MethodDesc vmNativeCodeMethodDescToken;
-#if defined(DBG_TARGET_WIN64) || defined(DBG_TARGET_ARM)
+#ifdef WIN64EXCEPTIONS
BOOL fIsFilterFrame;
SIZE_T parentNativeOffset;
FramePointer fpParentOrSelf;
-#endif // DBG_TARGET_WIN64 || DBG_TARGET_ARM
+#endif // WIN64EXCEPTIONS
// indicates if the MethodDesc is a generic function or a method inside a generic class (or
// both!).
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCRetainVM, W("GCRetainVM"), 0, "When set we put the segments that should be deleted on a standby list (instead of releasing them back to the OS) which will be considered to satisfy new segment requests (note that the same thing can be specified via API which is the supported way)")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCSegmentSize, W("GCSegmentSize"), "Specifies the managed heap segment size")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCLOHCompact, W("GCLOHCompact"), "Specifies the LOH compaction mode")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_gcAllowVeryLargeObjects, W("gcAllowVeryLargeObjects"), 0, "allow allocation of 2GB+ objects on GC heap")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_gcAllowVeryLargeObjects, W("gcAllowVeryLargeObjects"), 1, "allow allocation of 2GB+ objects on GC heap")
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_GCStress, W("GCStress"), 0, "trigger GCs at regular intervals", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_GcStressOnDirectCalls, W("GcStressOnDirectCalls"), 0, "whether to trigger a GC on direct calls", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCStressStart, W("GCStressStart"), 0, "start GCStress after N stress GCs have been attempted")
#ifdef _TARGET_X86_
#ifndef FEATURE_PAL
+//
+// x86 ABI does not define RUNTIME_FUNCTION. Define our own to allow unification between x86 and other platforms.
+//
+typedef struct _RUNTIME_FUNCTION {
+ DWORD BeginAddress;
+ DWORD UnwindData;
+} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
typedef struct _DISPATCHER_CONTEXT {
_EXCEPTION_REGISTRATION_RECORD* RegistrationPointer;
#endif // !FEATURE_PAL
#define RUNTIME_FUNCTION__BeginAddress(prf) (prf)->BeginAddress
+#define RUNTIME_FUNCTION__SetBeginAddress(prf,addr) ((prf)->BeginAddress = (addr))
+
+#ifdef WIN64EXCEPTIONS
+EXTERN_C ULONG
+RtlpGetFunctionEndAddress (
+ __in PT_RUNTIME_FUNCTION FunctionEntry,
+ __in ULONG ImageBase
+ );
+
+#define RUNTIME_FUNCTION__EndAddress(prf, ImageBase) RtlpGetFunctionEndAddress(prf, ImageBase)
+
+#define RUNTIME_FUNCTION__GetUnwindInfoAddress(prf) (prf)->UnwindData
+#define RUNTIME_FUNCTION__SetUnwindInfoAddress(prf, addr) do { (prf)->UnwindData = (addr); } while(0)
+
+#define UNW_FLAG_NHANDLER 0x0 /* any handler */
+#define UNW_FLAG_EHANDLER 0x1 /* filter handler */
+#define UNW_FLAG_UHANDLER 0x2 /* unwind handler */
+
+typedef struct _UNWIND_INFO {
+ // dummy
+} UNWIND_INFO, *PUNWIND_INFO;
+
+EXTERN_C
+NTSYSAPI
+PEXCEPTION_ROUTINE
+NTAPI
+RtlVirtualUnwind (
+ __in DWORD HandlerType,
+ __in DWORD ImageBase,
+ __in DWORD ControlPc,
+ __in PRUNTIME_FUNCTION FunctionEntry,
+ __inout PT_CONTEXT ContextRecord,
+ __out PVOID *HandlerData,
+ __out PDWORD EstablisherFrame,
+ __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
+ );
+#endif // WIN64EXCEPTIONS
#endif // _TARGET_X86_
#error FEATURE_PREJIT is required for this file
#endif // FEATURE_PREJIT
-#if !defined(_TARGET_X86_)
+#if !defined(_TARGET_X86_) || defined(FEATURE_PAL)
#ifndef WIN64EXCEPTIONS
#define WIN64EXCEPTIONS
#endif
-#endif // !_TARGET_X86_
+#endif // !_TARGET_X86_ || FEATURE_PAL
#include <cor.h>
#include <corhdr.h>
PTR_CORCOMPILE_IMPORT_SECTION;
#ifdef _TARGET_X86_
-#ifndef FEATURE_PAL
-//
-// x86 ABI does not define RUNTIME_FUNCTION. Define our own to allow unification between x86 and other platforms.
-//
-typedef struct _RUNTIME_FUNCTION {
- DWORD BeginAddress;
- DWORD UnwindData;
-} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
-
-#endif // !FEATURE_PAL
typedef DPTR(RUNTIME_FUNCTION) PTR_RUNTIME_FUNCTION;
CORINFO_INTRINSIC_MemoryBarrier,
CORINFO_INTRINSIC_GetCurrentManagedThread,
CORINFO_INTRINSIC_GetManagedThreadId,
+ CORINFO_INTRINSIC_ByReference_Ctor,
+ CORINFO_INTRINSIC_ByReference_Value,
CORINFO_INTRINSIC_Count,
CORINFO_INTRINSIC_Illegal = -1, // Not a true intrinsic,
#if defined(FEATURE_PAL)
// call back through data target to unwind out-of-process
-HRESULT DacVirtualUnwind(ULONG32 threadId, PCONTEXT context, PT_KNONVOLATILE_CONTEXT_POINTERS contextPointers);
+HRESULT DacVirtualUnwind(ULONG32 threadId, PT_CONTEXT context, PT_KNONVOLATILE_CONTEXT_POINTERS contextPointers);
#endif // FEATURE_PAL
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
#endif // #ifndef DACCESS_COMPILE
-#ifndef _TARGET_X86_
+#ifdef WIN64EXCEPTIONS
static void EnsureCallerContextIsValid( PREGDISPLAY pRD, StackwalkCacheEntry* pCacheEntry, EECodeInfo * pCodeInfo = NULL );
static size_t GetCallerSp( PREGDISPLAY pRD );
#endif
GcSlotDesc* m_pLastSlot;
};
+#ifdef USE_GC_INFO_DECODER
class GcInfoDecoder
{
public:
}
}
};
+#endif // USE_GC_INFO_DECODER
#endif // _GC_INFO_DECODER_
JITHELPER(CORINFO_HELP_FIELD_ACCESS_EXCEPTION,JIT_ThrowFieldAccessException, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_CLASS_ACCESS_EXCEPTION,JIT_ThrowClassAccessException, CORINFO_HELP_SIG_REG_ONLY)
-#ifdef WIN64EXCEPTIONS
+// UNIXTODO: Disable JIT_EndCatch after revising the jitter not to use this (for x86/Linux)
+#ifndef _TARGET_X86_
JITHELPER(CORINFO_HELP_ENDCATCH, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
#else
JITHELPER(CORINFO_HELP_ENDCATCH, JIT_EndCatch, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
READYTORUN_HELPER_DblRound = 0xE2,
READYTORUN_HELPER_FltRound = 0xE3,
-#ifndef _TARGET_X86_
+#ifdef WIN64EXCEPTIONS
// Personality rountines
READYTORUN_HELPER_PersonalityRoutine = 0xF0,
READYTORUN_HELPER_PersonalityRoutineFilterFunclet = 0xF1,
// returned by GetContext or provided
// at exception time.
+#ifndef WIN64EXCEPTIONS
// TODO: Unify with pCurrentContext / pCallerContext used on 64-bit
PCONTEXT pContextForUnwind; // scratch context for unwinding
// used to preserve context saved in the frame that
// could be otherwise wiped by the unwinding
+#else // !WIN64EXCEPTIONS
+ PT_CONTEXT pCurrentContext; // [trashed] points to current Context of stackwalk
+ PT_CONTEXT pCallerContext; // [trashed] points to the Context of the caller during stackwalk -- used for GC crawls
+
+ // [trashed] points to current context pointers of stackwalk
+ T_KNONVOLATILE_CONTEXT_POINTERS *pCurrentContextPointers;
+ // [trashed] points to the context pointers of the caller during stackwalk -- used for GC crawls
+ T_KNONVOLATILE_CONTEXT_POINTERS *pCallerContextPointers;
+
+ BOOL IsCallerContextValid; // TRUE if pCallerContext really contains the caller's context
+ BOOL IsCallerSPValid; // Don't add usage of this field. This is only temporary.
+
+ T_CONTEXT ctxOne; // used by stackwalk
+ T_CONTEXT ctxTwo; // used by stackwalk
+
+ T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsOne; // used by stackwalk
+ T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsTwo; // used by stackwalk
+
+#ifdef DEBUG_REGDISPLAY
+ Thread *_pThread;
+#endif // DEBUG_REGDISPLAY
+#endif // !WIN64EXCEPTIONS
DWORD * pEdi;
DWORD * pEsi;
void CheckRegDisplaySP (REGDISPLAY *pRD);
#endif // DEBUG_REGDISPLAY
-inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD)
-{
- LIMITED_METHOD_CONTRACT;
-
- pRD->SP = (INT_PTR)GetSP(pRD->pCurrentContext);
-
-#ifdef DEBUG_REGDISPLAY
- CheckRegDisplaySP(pRD);
-#endif // DEBUG_REGDISPLAY
-
- pRD->ControlPC = INT_PTR(GetIP(pRD->pCurrentContext));
-}
// This function tells us if the given stack pointer is in one of the frames of the functions called by the given frame
inline BOOL IsInCalleesFrames(REGDISPLAY *display, LPVOID stackPointer)
#endif // _TARGET_AMD64_
}
-// This needs to be implemented for platforms that have funclets.
-inline LPVOID GetRegdisplayReturnValue(REGDISPLAY *display)
-{
- LIMITED_METHOD_CONTRACT;
-
-#if defined(_TARGET_AMD64_)
- return (LPVOID)display->pCurrentContext->Rax;
-#elif defined(_TARGET_ARM64_)
- return (LPVOID)display->pCurrentContext->X0;
-#else
- PORTABILITY_ASSERT("GetRegdisplayReturnValue NYI for this platform (Regdisp.h)");
- return NULL;
-#endif
-}
#elif defined(_TARGET_ARM_)
return GetSP(display->pCallerContext);
}
-inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD)
-{
- LIMITED_METHOD_CONTRACT;
- pRD->SP = (DWORD)GetSP(pRD->pCurrentContext);
- pRD->ControlPC = (DWORD)GetIP(pRD->pCurrentContext);
-}
-
-// This needs to be implemented for platforms that have funclets.
-inline LPVOID GetRegdisplayReturnValue(REGDISPLAY *display)
-{
- LIMITED_METHOD_CONTRACT;
- return (LPVOID)display->pCurrentContext->R0;
-}
#else // none of the above processors
#endif
+#if defined(_WIN64) || defined(_TARGET_ARM_) || (defined(_TARGET_X86_) && defined(WIN64EXCEPTIONS))
+// This needs to be implemented for platforms that have funclets.
+inline LPVOID GetRegdisplayReturnValue(REGDISPLAY *display)
+{
+ LIMITED_METHOD_CONTRACT;
+
+#if defined(_TARGET_AMD64_)
+ return (LPVOID)display->pCurrentContext->Rax;
+#elif defined(_TARGET_ARM64_)
+ return (LPVOID)display->pCurrentContext->X0;
+#elif defined(_TARGET_ARM_)
+ return (LPVOID)display->pCurrentContext->R0;
+#elif defined(_TARGET_X86_)
+ return (LPVOID)display->pCurrentContext->Eax;
+#else
+ PORTABILITY_ASSERT("GetRegdisplayReturnValue NYI for this platform (Regdisp.h)");
+ return NULL;
+#endif
+}
+
+inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD)
+{
+ LIMITED_METHOD_CONTRACT;
+
+#if defined(_WIN64)
+ pRD->SP = (INT_PTR)GetSP(pRD->pCurrentContext);
+
+#ifdef DEBUG_REGDISPLAY
+ CheckRegDisplaySP(pRD);
+#endif // DEBUG_REGDISPLAY
+
+ pRD->ControlPC = INT_PTR(GetIP(pRD->pCurrentContext));
+#elif defined(_TARGET_ARM_) // _WIN64
+ pRD->SP = (DWORD)GetSP(pRD->pCurrentContext);
+ pRD->ControlPC = (DWORD)GetIP(pRD->pCurrentContext);
+#elif defined(_TARGET_X86_) // _TARGET_ARM_
+ pRD->Esp = (DWORD)GetSP(pRD->pCurrentContext);
+ pRD->ControlPC = (DWORD)GetIP(pRD->pCurrentContext);
+#else // _TARGET_X86_
+ PORTABILITY_ASSERT("SyncRegDisplayToCurrentContext");
+#endif // _TARGET_ARM_ || _TARGET_X86_
+}
+#endif // _WIN64 || _TARGET_ARM_ || (_TARGET_X86_ && WIN64EXCEPTIONS)
+
typedef REGDISPLAY *PREGDISPLAY;
SUPPORTS_DAC;
+#ifndef WIN64EXCEPTIONS
#ifdef _TARGET_X86_
pRD->pContext = pctx;
pRD->pContextForUnwind = NULL;
pRD->Esp = pctx->Esp;
pRD->ControlPC = (PCODE)(pctx->Eip);
pRD->PCTAddr = (UINT_PTR)&(pctx->Eip);
-#elif defined(_WIN64)
+#else // _TARGET_X86_
+ PORTABILITY_ASSERT("FillRegDisplay");
+#endif // _TARGET_???_ (ELSE)
+
+#else // !WIN64EXCEPTIONS
pRD->pContext = pctx;
#ifdef _TARGET_AMD64_
for (int i = 0; i < 16; i++)
{
*(&pRD->ctxPtrsOne.Rax + i) = (&pctx->Rax + i);
}
-#elif defined(_TARGET_ARM64_)
+#elif defined(_TARGET_ARM64_) // _TARGET_AMD64_
for (int i = 0; i < 12; i++)
{
*(&pRD->ctxPtrsOne.X19 + i) = (&pctx->X19 + i);
}
-#endif // _TARGET_AMD64_
-
- pRD->pCurrentContextPointers = &pRD->ctxPtrsOne;
- pRD->pCallerContextPointers = &pRD->ctxPtrsTwo;
-
- pRD->pCurrentContext = &(pRD->ctxOne);
- pRD->pCallerContext = &(pRD->ctxTwo);
-
- // copy the active context to initialize our stackwalk
- *(pRD->pCurrentContext) = *(pctx);
-
- // copy the caller context as well if it's specified
- if (pCallerCtx == NULL)
- {
- pRD->IsCallerContextValid = FALSE;
- pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
- }
- else
- {
- *(pRD->pCallerContext) = *(pCallerCtx);
- pRD->IsCallerContextValid = TRUE;
- pRD->IsCallerSPValid = TRUE; // Don't add usage of this field. This is only temporary.
- }
-
-#ifdef DEBUG_REGDISPLAY
- pRD->_pThread = NULL;
-#endif // DEBUG_REGDISPLAY
-
- SyncRegDisplayToCurrentContext(pRD);
-#elif defined(_TARGET_ARM_)
- pRD->pContext = pctx;
-
+#elif defined(_TARGET_ARM_) // _TARGET_ARM64_
// Copy over the nonvolatile integer registers (R4-R11)
for (int i = 0; i < 8; i++)
{
*(&pRD->ctxPtrsOne.R4 + i) = (&pctx->R4 + i);
}
- pRD->ctxPtrsOne.Lr = &pctx->Lr;
+ pRD->ctxPtrsOne.Lr = &pctx->Lr;
+#elif defined(_TARGET_X86_) // _TARGET_ARM_
+ for (int i = 0; i < 4; ++i)
+ {
+ *(&pRD->ctxPtrsOne.Ebx + i) = (&pctx->Ebx + i);
+ }
+#else // _TARGET_X86_
+ PORTABILITY_ASSERT("FillRegDisplay");
+#endif // _TARGET_???_ (ELSE)
// Setup the references
pRD->pCurrentContextPointers = &pRD->ctxPtrsOne;
pRD->IsCallerSPValid = TRUE; // Don't add usage of this field. This is only temporary.
}
+#ifdef _TARGET_ARM_
pRD->pPC = &pRD->pCurrentContext->Pc;
+#endif
#ifdef DEBUG_REGDISPLAY
pRD->_pThread = NULL;
// This will setup the PC and SP
SyncRegDisplayToCurrentContext(pRD);
-#else
- PORTABILITY_ASSERT("@NYI Platform - InitRegDisplay (Threads.cpp)");
-#endif
+#endif // !WIN64EXCEPTIONS
}
// Initialize a new REGDISPLAY/CONTEXT pair from an existing valid REGDISPLAY.
#define LOGGING
#endif
-#if !defined(_TARGET_X86_)
+#if !defined(_TARGET_X86_) || defined(FEATURE_PAL)
#define WIN64EXCEPTIONS
#endif
{
printf("KEEP ");
}
+ if (bbFlags & BBF_CLONED_FINALLY_BEGIN)
+ {
+ printf("cfb ");
+ }
+ if (bbFlags & BBF_CLONED_FINALLY_END)
+ {
+ printf("cfe ");
+ }
}
/*****************************************************************************
// Return Value:
// The first statement in the block's bbTreeList.
//
-GenTreeStmt* BasicBlock::firstStmt()
+GenTreeStmt* BasicBlock::firstStmt() const
{
if (bbTreeList == nullptr)
{
// Return Value:
// The last statement in the block's bbTreeList.
//
-GenTreeStmt* BasicBlock::lastStmt()
+GenTreeStmt* BasicBlock::lastStmt() const
{
if (bbTreeList == nullptr)
{
// BBJ_CALLFINALLY block, as well as, on x86, the final step block out of a
// finally.
+#define BBF_CLONED_FINALLY_BEGIN 0x100000000 // First block of a cloned finally region
+#define BBF_CLONED_FINALLY_END 0x200000000 // Last block of a cloned finally region
+
// Flags that relate blocks to loop structure.
#define BBF_LOOP_FLAGS (BBF_LOOP_PREHEADER | BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1)
- bool isRunRarely()
+ bool isRunRarely() const
{
return ((bbFlags & BBF_RUN_RARELY) != 0);
}
- bool isLoopHead()
+ bool isLoopHead() const
{
return ((bbFlags & BBF_LOOP_HEAD) != 0);
}
// For example, the top block might or might not have BBF_GC_SAFE_POINT,
// but we assume it does not have BBF_GC_SAFE_POINT any more.
-#define BBF_SPLIT_LOST (BBF_GC_SAFE_POINT | BBF_HAS_JMP | BBF_KEEP_BBJ_ALWAYS)
+#define BBF_SPLIT_LOST (BBF_GC_SAFE_POINT | BBF_HAS_JMP | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END)
// Flags gained by the bottom block when a block is split.
// Note, this is a conservative guess.
#define BBF_SPLIT_GAINED \
(BBF_DONT_REMOVE | BBF_HAS_LABEL | BBF_HAS_JMP | BBF_BACKWARD_JUMP | BBF_HAS_IDX_LEN | BBF_HAS_NEWARRAY | \
- BBF_PROF_WEIGHT | BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS)
+ BBF_PROF_WEIGHT | BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END)
#ifndef __GNUC__ // GCC doesn't like C_ASSERT at global scope
static_assert_no_msg((BBF_SPLIT_NONEXIST & BBF_SPLIT_LOST) == 0);
// lclVar, and thus has no local #, we can't use a GenTreePhiArg. Instead, we use this struct.
struct HeapPhiArg
{
- bool m_isSsaNum; // If true, the phi arg is an SSA # for an internal try block heap state, being
- // added to the phi of a catch block. If false, it's a pred block.
- union {
- BasicBlock* m_predBB; // Predecessor block from which the SSA # flows.
- unsigned m_ssaNum; // SSA# for internal block heap state.
- };
+ unsigned m_ssaNum; // SSA# for incoming value.
HeapPhiArg* m_nextArg; // Next arg in the list, else NULL.
unsigned GetSsaNum()
{
- if (m_isSsaNum)
- {
- return m_ssaNum;
- }
- else
- {
- assert(m_predBB != nullptr);
- return m_predBB->bbHeapSsaNumOut;
- }
+ return m_ssaNum;
}
- HeapPhiArg(BasicBlock* predBB, HeapPhiArg* nextArg = nullptr)
- : m_isSsaNum(false), m_predBB(predBB), m_nextArg(nextArg)
- {
- }
- HeapPhiArg(unsigned ssaNum, HeapPhiArg* nextArg = nullptr)
- : m_isSsaNum(true), m_ssaNum(ssaNum), m_nextArg(nextArg)
+ HeapPhiArg(unsigned ssaNum, HeapPhiArg* nextArg = nullptr) : m_ssaNum(ssaNum), m_nextArg(nextArg)
{
}
return bbNum - 1;
}
- GenTreeStmt* firstStmt();
- GenTreeStmt* lastStmt();
+ GenTreeStmt* firstStmt() const;
+ GenTreeStmt* lastStmt() const;
GenTreeStmt* lastTopLevelStmt();
GenTree* firstNode();
assert(rmwSrc == data->gtGetOp2());
genCodeForShiftRMW(storeInd);
}
- else if (!compiler->opts.compDbgCode && data->OperGet() == GT_ADD &&
- (rmwSrc->IsIntegralConst(1) || rmwSrc->IsIntegralConst(-1)))
+ else if (data->OperGet() == GT_ADD && (rmwSrc->IsIntegralConst(1) || rmwSrc->IsIntegralConst(-1)))
{
// Generate "inc/dec [mem]" instead of "add/sub [mem], 1".
//
if (arg->OperGet() != GT_ARGPLACE && !(arg->gtFlags & GTF_LATE_ARG))
{
#if defined(_TARGET_X86_)
- assert((arg->OperGet() == GT_PUTARG_STK) || (arg->OperGet() == GT_LONG));
- if (arg->OperGet() == GT_LONG)
- {
- assert((arg->gtGetOp1()->OperGet() == GT_PUTARG_STK) && (arg->gtGetOp2()->OperGet() == GT_PUTARG_STK));
- }
if ((arg->OperGet() == GT_PUTARG_STK) && (arg->gtGetOp1()->OperGet() == GT_FIELD_LIST))
{
fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
GenTreePtr data = putArgStk->gtOp1;
- // On a 32-bit target, all of the long arguments have been decomposed into
- // a separate putarg_stk for each of the upper and lower halves.
- noway_assert(targetType != TYP_LONG);
+ // On a 32-bit target, all of the long arguments are handled with GT_FIELD_LIST,
+ // and the type of the putArgStk is TYP_VOID.
+ assert(targetType != TYP_LONG);
const unsigned argSize = putArgStk->getArgSize();
assert((argSize % TARGET_POINTER_SIZE) == 0);
gcInfoEncoder->SetSizeOfEditAndContinuePreservedArea(preservedAreaSize);
}
+ if (compiler->opts.IsReversePInvoke())
+ {
+ unsigned reversePInvokeFrameVarNumber = compiler->lvaReversePInvokeFrameVar;
+ assert(reversePInvokeFrameVarNumber != BAD_VAR_NUM && reversePInvokeFrameVarNumber < compiler->lvaRefCount);
+ LclVarDsc& reversePInvokeFrameVar = compiler->lvaTable[reversePInvokeFrameVarNumber];
+ gcInfoEncoder->SetReversePInvokeFrameSlot(reversePInvokeFrameVar.lvStkOffs);
+ }
+
gcInfoEncoder->Build();
// GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t)
}
#endif
- opts.compMustInlinePInvokeCalli = jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB);
-
opts.compScopeInfo = opts.compDbgInfo;
#ifdef LATE_DISASM
void impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
- bool impCanPInvokeInline(BasicBlock* block);
+ bool impCanPInvokeInline();
bool impCanPInvokeInlineCallSite(BasicBlock* block);
void impCheckForPInvokeCall(
GenTreePtr call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
void impImportLeave(BasicBlock* block);
void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
- GenTreePtr impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
+ GenTreePtr impIntrinsic(GenTreePtr newobjThis,
+ CORINFO_CLASS_HANDLE clsHnd,
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
int memberRef,
void fgInline();
+ void fgRemoveEmptyFinally();
+
+ void fgCloneFinally();
+
GenTreePtr fgGetCritSectOfStaticMethod();
#if !defined(_TARGET_X86_)
void fgDebugCheckNodeLinks(BasicBlock* block, GenTreePtr stmt);
void fgDebugCheckFlags(GenTreePtr tree);
void fgDebugCheckFlagsHelper(GenTreePtr tree, unsigned treeFlags, unsigned chkFlags);
+ void fgDebugCheckTryFinallyExits();
#endif
#ifdef LEGACY_BACKEND
static const bool compNoPInvokeInlineCB;
#endif
- bool compMustInlinePInvokeCalli; // Unmanaged CALLI in IL stubs must be inlined
-
#ifdef DEBUG
bool compGcChecks; // Check arguments and return values to ensure they are sane
bool compStackCheckOnRet; // Check ESP on return to ensure it is correct
// corresponding array of string names of those phases. This include file undefines CompPhaseNameMacro
// after the last use.
// The arguments are:
-// CompPhaseNameMacro(enumName, stringName, hasChildren, parent)
+// CompPhaseNameMacro(enumName, stringName, shortName, hasChildren, parent)
// "enumName" is an Enumeration-style all-caps name.
// "stringName" is a self-explanatory.
+// "shortName" is an abbreviated form for stringName
// "hasChildren" is true if this phase is broken out into subphases.
// (We should never do EndPhase on a phase that has children, only on 'leaf phases.')
// "parent" is -1 for leaf phases, otherwise it is the "enumName" of the parent phase.
// for calls through ICorJitInfo across all "real" phases.
CompPhaseNameMacro(PHASE_CLR_API, "CLR API calls", "CLR-API", false, -1)
#endif
+
+CompPhaseNameMacro(PHASE_EMPTY_FINALLY, "Remove empty finally", "EMPTYFIN", false, -1)
+CompPhaseNameMacro(PHASE_CLONE_FINALLY, "Clone finally", "CLONEFIN", false, -1)
// clang-format on
#undef CompPhaseNameMacro
// The following SSE2 instructions write to a general purpose integer register.
if (!IsSSEOrAVXInstruction(ins) || ins == INS_mov_xmm2i || ins == INS_cvttsd2si
#ifndef LEGACY_BACKEND
- || ins == INS_cvttss2si || ins == INS_cvtsd2si || ins == INS_cvtss2si
+ || ins == INS_cvttss2si || ins == INS_cvtsd2si || ins == INS_cvtss2si || ins == INS_pmovmskb ||
+ ins == INS_pextrw
#endif // !LEGACY_BACKEND
)
{
}
else
{
- if (emitInsCanOnlyWriteSSE2OrAVXReg(id))
- {
- }
- else
+ if (!emitInsCanOnlyWriteSSE2OrAVXReg(id))
{
switch (id->idInsFmt())
{
}
else
{
- if (emitInsCanOnlyWriteSSE2OrAVXReg(id))
- {
- }
- else
+ if (!emitInsCanOnlyWriteSSE2OrAVXReg(id))
{
switch (id->idInsFmt())
{
}
else
{
- if (emitInsCanOnlyWriteSSE2OrAVXReg(id))
- {
- }
- else
+ if (!emitInsCanOnlyWriteSSE2OrAVXReg(id))
{
switch (id->idInsFmt())
{
}
else
{
- if (emitInsCanOnlyWriteSSE2OrAVXReg(id))
- {
- }
- else
+ if (!emitInsCanOnlyWriteSSE2OrAVXReg(id))
{
switch (id->idInsFmt())
{
dst += emitOutputByte(dst, emitGetInsSC(id));
sz = emitSizeOfInsDsc(id);
+
+ // Kill any GC ref in the destination register if necessary.
+ if (!emitInsCanOnlyWriteSSE2OrAVXReg(id))
+ {
+ emitGCregDeadUpd(id->idReg1(), dst);
+ }
break;
/********************************************************************/
GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block, IL_OFFSETX offs)
{
GenTreeStmt* stmt = gtNewStmt(tree, offs);
- gtSetStmtInfo(stmt);
- fgSetStmtSeq(stmt);
+
+ if (fgStmtListThreaded)
+ {
+ gtSetStmtInfo(stmt);
+ fgSetStmtSeq(stmt);
+ }
#if DEBUG
if (block != nullptr)
optimizeJump = false;
}
+ // Don't optimize a jump to a cloned finally
+ if (bDest->bbFlags & BBF_CLONED_FINALLY_BEGIN)
+ {
+ optimizeJump = false;
+ }
+
#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
// Don't optimize a jump to a finally target. For BB1->BB2->BB3, where
// BB2 is a finally target, if we changed BB1 to jump directly to BB3,
lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
}
}
+
+//------------------------------------------------------------------------
+// fgRemoveEmptyFinally: Remove try/finallys where the finally is empty
+//
+// Notes:
+// Removes all try/finallys in the method with empty finallys.
+// These typically arise from inlining empty Dispose methods.
+//
+// Converts callfinally to a jump to the finally continuation.
+// Removes the finally, and reparents all blocks in the try to the
+// enclosing try or method region.
+//
+// Currently limited to trivially empty finallys: those with one basic
+// block containing only single RETFILT statement. It is possible but
+// not likely that more complex-looking finallys will eventually become
+// empty (from say subsequent optimization). An SPMI run with
+// just the "detection" part of this phase run after optimization
+// found only one example where a new empty finally was detected.
+
+void Compiler::fgRemoveEmptyFinally()
+{
+ JITDUMP("\n*************** In fgRemoveEmptyFinally()\n");
+
+ if (compHndBBtabCount == 0)
+ {
+ JITDUMP("No EH in this method, nothing to remove.\n");
+ return;
+ }
+
+ if (opts.MinOpts())
+ {
+ JITDUMP("Method compiled with minOpts, no removal.\n");
+ return;
+ }
+
+ if (opts.compDbgCode)
+ {
+ JITDUMP("Method compiled with debug codegen, no removal.\n");
+ return;
+ }
+
+#ifdef DEBUG
+ if (verbose)
+ {
+ printf("\n*************** Before fgRemoveEmptyFinally()\n");
+ fgDispBasicBlocks();
+ fgDispHandlerTab();
+ printf("\n");
+ }
+#endif // DEBUG
+
+ // Look for finallys or faults that are empty.
+ unsigned finallyCount = 0;
+ unsigned emptyCount = 0;
+ unsigned XTnum = 0;
+ while (XTnum < compHndBBtabCount)
+ {
+ EHblkDsc* const HBtab = &compHndBBtab[XTnum];
+
+ // Check if this is a try/finally. We could also look for empty
+ // try/fault but presumably those are rare.
+ if (!HBtab->HasFinallyHandler())
+ {
+ JITDUMP("EH#%u is not a try-finally; skipping.\n", XTnum);
+ XTnum++;
+ continue;
+ }
+
+ finallyCount++;
+
+ // Look at blocks involved.
+ BasicBlock* const firstBlock = HBtab->ebdHndBeg;
+ BasicBlock* const lastBlock = HBtab->ebdHndLast;
+
+ // Limit for now to finallys that are single blocks.
+ if (firstBlock != lastBlock)
+ {
+ JITDUMP("EH#%u finally has multiple basic blocks; skipping.\n", XTnum);
+ XTnum++;
+ continue;
+ }
+
+ // Limit for now to finallys that contain only a GT_RETFILT.
+ bool isEmpty = true;
+
+ for (GenTreeStmt* stmt = firstBlock->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
+ {
+ GenTreePtr stmtExpr = stmt->gtStmtExpr;
+
+ if (stmtExpr->gtOper != GT_RETFILT)
+ {
+ isEmpty = false;
+ break;
+ }
+ }
+
+ if (!isEmpty)
+ {
+ JITDUMP("EH#%u finally is not empty; skipping.\n", XTnum);
+ XTnum++;
+ continue;
+ }
+
+ JITDUMP("EH#%u has empty finally, removing the region.\n", XTnum);
+
+ // Find all the call finallys that invoke this finally,
+ // and modify them to jump to the return point.
+ BasicBlock* firstCallFinallyRangeBlock = nullptr;
+ BasicBlock* endCallFinallyRangeBlock = nullptr;
+ ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
+
+ BasicBlock* currentBlock = firstCallFinallyRangeBlock;
+
+ while (currentBlock != endCallFinallyRangeBlock)
+ {
+ BasicBlock* nextBlock = currentBlock->bbNext;
+
+ if ((currentBlock->bbJumpKind == BBJ_CALLFINALLY) && (currentBlock->bbJumpDest == firstBlock))
+ {
+ // Retarget the call finally to jump to the return
+ // point.
+ //
+ // We don't expect to see retless finallys here, since
+ // the finally is empty.
+ noway_assert(currentBlock->isBBCallAlwaysPair());
+
+ BasicBlock* const leaveBlock = currentBlock->bbNext;
+ BasicBlock* const postTryFinallyBlock = leaveBlock->bbJumpDest;
+
+ noway_assert(leaveBlock->bbJumpKind == BBJ_ALWAYS);
+
+ currentBlock->bbJumpDest = postTryFinallyBlock;
+ currentBlock->bbJumpKind = BBJ_ALWAYS;
+
+ // Ref count updates.
+ fgAddRefPred(postTryFinallyBlock, currentBlock);
+ // fgRemoveRefPred(firstBlock, currentBlock);
+
+ // Delete the leave block, which should be marked as
+ // keep always.
+ assert((leaveBlock->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0);
+ nextBlock = leaveBlock->bbNext;
+
+ leaveBlock->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
+ fgRemoveBlock(leaveBlock, true);
+
+ // The postTryFinallyBlock may be a finalStep block.
+ // It is now a normal block, so clear the special keep
+ // always flag.
+ postTryFinallyBlock->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
+
+#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+ // Also, clear the finally target bit for arm
+ fgClearFinallyTargetBit(postTryFinallyBlock);
+#endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+
+#if !FEATURE_EH_FUNCLETS
+ // Remove the GT_END_LFIN from the post-try-finally block.
+ // remove it since there is no finally anymore.
+ GenTreeStmt* endFinallyStmt = postTryFinallyBlock->lastStmt();
+ GenTreePtr endFinallyExpr = endFinallyStmt->gtStmtExpr;
+ assert(endFinallyExpr->gtOper == GT_END_LFIN);
+ fgRemoveStmt(postTryFinallyBlock, endFinallyStmt);
+#endif // !FEATURE_EH_FUNCLETS
+
+ // Make sure iteration isn't going off the deep end.
+ assert(leaveBlock != endCallFinallyRangeBlock);
+ }
+
+ currentBlock = nextBlock;
+ }
+
+ // Handler block should now be unreferenced, since the only
+ // explicit references to it were in call finallys.
+ firstBlock->bbRefs = 0;
+
+ // Remove the handler block.
+ const bool unreachable = true;
+ firstBlock->bbFlags &= ~BBF_DONT_REMOVE;
+ fgRemoveBlock(firstBlock, unreachable);
+
+ // Find enclosing try region for the try, if any, and update
+ // the try region. Note the handler region (if any) won't
+ // change.
+ BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
+ BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
+ assert(firstTryBlock->getTryIndex() == XTnum);
+
+ for (BasicBlock* block = firstTryBlock; block != nullptr; block = block->bbNext)
+ {
+ // Look for blocks directly contained in this try, and
+ // update the try region appropriately.
+ //
+ // Try region for blocks transitively contained (say in a
+ // child try) will get updated by the subsequent call to
+ // fgRemoveEHTableEntry.
+ if (block->getTryIndex() == XTnum)
+ {
+ if (firstBlock->hasTryIndex())
+ {
+ block->setTryIndex(firstBlock->getTryIndex());
+ }
+ else
+ {
+ block->clearTryIndex();
+ }
+ }
+
+ if (block == firstTryBlock)
+ {
+ assert((block->bbFlags & BBF_TRY_BEG) != 0);
+ block->bbFlags &= ~BBF_TRY_BEG;
+ }
+
+ if (block == lastTryBlock)
+ {
+ break;
+ }
+ }
+
+ // Remove the try-finally EH region. This will compact the EH table
+ // so XTnum now points at the next entry.
+ fgRemoveEHTableEntry(XTnum);
+
+ emptyCount++;
+ }
+
+ if (emptyCount > 0)
+ {
+ JITDUMP("fgRemoveEmptyFinally() removed %u try-finally clauses from %u finallys\n", emptyCount, finallyCount);
+
+#ifdef DEBUG
+ if (verbose)
+ {
+ printf("\n*************** After fgRemoveEmptyFinally()\n");
+ fgDispBasicBlocks();
+ fgDispHandlerTab();
+ printf("\n");
+ }
+
+ fgVerifyHandlerTab();
+ fgDebugCheckBBlist(false, false);
+
+#endif // DEBUG
+ }
+}
+
+//------------------------------------------------------------------------
+// fgCloneFinally: Optimize normal exit path from a try/finally
+//
+// Notes:
+// Handles finallys that are not enclosed by or enclosing other
+// handler regions.
+//
+// Converts the "normal exit" callfinally to a jump to a cloned copy
+// of the finally, which in turn jumps to the finally continuation.
+//
+// If all callfinallys for a given finally are converted to jump to
+// the clone, the try-finally is modified into a try-fault,
+// distingushable from organic try-faults by handler type
+// EH_HANDLER_FAULT_WAS_FINALLY vs the organic EH_HANDLER_FAULT.
+//
+// Does not yet handle thread abort. The open issues here are how
+// to maintain the proper description of the cloned finally blocks
+// as a handler (for thread abort purposes), how to prevent code
+// motion in or out of these blocks, and how to report this cloned
+// handler to the runtime. Some building blocks for thread abort
+// exist (see below) but more work needed.
+//
+// The first and last blocks of the cloned finally are marked with
+// BBF_CLONED_FINALLY_BEGIN and BBF_CLONED_FINALLY_END. However
+// these markers currently can get lost during subsequent
+// optimizations.
+
+void Compiler::fgCloneFinally()
+{
+ JITDUMP("\n*************** In fgCloneFinally()\n");
+
+#if FEATURE_CORECLR
+ bool enableCloning = true;
+#else
+ // Finally cloning currently doesn't provide sufficient protection
+ // for the cloned code in the presence of thread abort.
+ bool enableCloning = false;
+#endif // FEATURE_CORECLR
+
+#if DEBUG
+ // Allow override to enable/disable.
+ enableCloning = (JitConfig.JitEnableFinallyCloning() == 1);
+#endif // DEBUG
+
+ if (!enableCloning)
+ {
+ JITDUMP("Finally cloning disabled.\n");
+ return;
+ }
+
+ if (compHndBBtabCount == 0)
+ {
+ JITDUMP("No EH in this method, no cloning.\n");
+ return;
+ }
+
+ if (opts.MinOpts())
+ {
+ JITDUMP("Method compiled with minOpts, no cloning.\n");
+ return;
+ }
+
+ if (opts.compDbgCode)
+ {
+ JITDUMP("Method compiled with debug codegen, no cloning.\n");
+ return;
+ }
+
+#ifdef DEBUG
+ if (verbose)
+ {
+ printf("\n*************** Before fgCloneFinally()\n");
+ fgDispBasicBlocks();
+ fgDispHandlerTab();
+ printf("\n");
+ }
+
+ // Verify try-finally exits look good before we start.
+ fgDebugCheckTryFinallyExits();
+
+#endif // DEBUG
+
+ // Look for finallys that are not contained within other handlers,
+ // and which do not themselves contain EH.
+ //
+ // Note these cases potentially could be handled, but are less
+ // obviously profitable and require modification of the handler
+ // table.
+ unsigned XTnum = 0;
+ EHblkDsc* HBtab = compHndBBtab;
+ unsigned cloneCount = 0;
+ for (; XTnum < compHndBBtabCount; XTnum++, HBtab++)
+ {
+ // Check if this is a try/finally
+ if (!HBtab->HasFinallyHandler())
+ {
+ JITDUMP("EH#%u is not a try-finally; skipping.\n", XTnum);
+ continue;
+ }
+
+ // Check if enclosed by another handler.
+ const unsigned enclosingHandlerRegion = ehGetEnclosingHndIndex(XTnum);
+
+ if (enclosingHandlerRegion != EHblkDsc::NO_ENCLOSING_INDEX)
+ {
+ JITDUMP("EH#%u is enclosed by handler EH#%u; skipping.\n", XTnum, enclosingHandlerRegion);
+ continue;
+ }
+
+ bool containsEH = false;
+ unsigned exampleEnclosedHandlerRegion = 0;
+
+ // Only need to look at lower numbered regions because the
+ // handler table is ordered by nesting.
+ for (unsigned i = 0; i < XTnum; i++)
+ {
+ if (ehGetEnclosingHndIndex(i) == XTnum)
+ {
+ exampleEnclosedHandlerRegion = i;
+ containsEH = true;
+ break;
+ }
+ }
+
+ if (containsEH)
+ {
+ JITDUMP("Finally for EH#%u encloses handler EH#%u; skipping.\n", XTnum, exampleEnclosedHandlerRegion);
+ continue;
+ }
+
+ // Look at blocks involved.
+ BasicBlock* const firstBlock = HBtab->ebdHndBeg;
+ BasicBlock* const lastBlock = HBtab->ebdHndLast;
+ assert(firstBlock != nullptr);
+ assert(lastBlock != nullptr);
+ BasicBlock* nextBlock = lastBlock->bbNext;
+ unsigned regionBBCount = 0;
+ unsigned regionStmtCount = 0;
+ bool hasFinallyRet = false;
+ bool isAllRare = true;
+ bool hasSwitch = false;
+
+ for (const BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
+ {
+ if (block->bbJumpKind == BBJ_SWITCH)
+ {
+ hasSwitch = true;
+ break;
+ }
+
+ regionBBCount++;
+
+ // Should we compute statement cost here, or is it
+ // premature...? For now just count statements I guess.
+ for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
+ {
+ regionStmtCount++;
+ }
+
+ hasFinallyRet = hasFinallyRet || (block->bbJumpKind == BBJ_EHFINALLYRET);
+ isAllRare = isAllRare && block->isRunRarely();
+ }
+
+ // Skip cloning if the finally has a switch.
+ if (hasSwitch)
+ {
+ JITDUMP("Finally in EH#%u has a switch; skipping.\n", XTnum);
+ continue;
+ }
+
+ // Skip cloning if the finally must throw.
+ if (!hasFinallyRet)
+ {
+ JITDUMP("Finally in EH#%u does not return; skipping.\n", XTnum);
+ continue;
+ }
+
+ // Skip cloning if the finally is rarely run code.
+ if (isAllRare)
+ {
+ JITDUMP("Finally in EH#%u is run rarely; skipping.\n", XTnum);
+ continue;
+ }
+
+ // Empirical studies from CoreCLR and CoreFX show that less
+ // that 1% of finally regions have more than 15
+ // statements. So, to avoid potentially excessive code growth,
+ // only clone finallys that have 15 or fewer statements.
+ const unsigned stmtCountLimit = 15;
+ if (regionStmtCount > stmtCountLimit)
+ {
+ JITDUMP("Finally in EH#%u has %u statements, limit is %u; skipping.\n", XTnum, regionStmtCount,
+ stmtCountLimit);
+ continue;
+ }
+
+ JITDUMP("EH#%u is a candidate for finally cloning:"
+ " %u blocks, %u statements\n",
+ XTnum, regionBBCount, regionStmtCount);
+
+ // Walk the try region backwards looking for the last block
+ // that transfers control to a callfinally.
+ BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
+ BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
+ assert(firstTryBlock->getTryIndex() == XTnum);
+ assert(lastTryBlock->getTryIndex() == XTnum);
+ BasicBlock* const beforeTryBlock = firstTryBlock->bbPrev;
+
+ BasicBlock* normalCallFinallyBlock = nullptr;
+ BasicBlock* normalCallFinallyReturn = nullptr;
+ BasicBlock* cloneInsertAfter = HBtab->ebdTryLast;
+ bool tryToRelocateCallFinally = false;
+
+ for (BasicBlock* block = lastTryBlock; block != beforeTryBlock; block = block->bbPrev)
+ {
+#if FEATURE_EH_CALLFINALLY_THUNKS
+ // Look for blocks that are always jumps to a call finally
+ // pair that targets our finally.
+ if (block->bbJumpKind != BBJ_ALWAYS)
+ {
+ continue;
+ }
+
+ BasicBlock* const jumpDest = block->bbJumpDest;
+
+ if (!jumpDest->isBBCallAlwaysPair() || (jumpDest->bbJumpDest != firstBlock))
+ {
+ continue;
+ }
+#else
+ // Look for call finally pair directly within the try
+ if (!block->isBBCallAlwaysPair() || (block->bbJumpDest != firstBlock))
+ {
+ continue;
+ }
+
+ BasicBlock* const jumpDest = block;
+#endif // FEATURE_EH_CALLFINALLY_THUNKS
+
+ // Found our block.
+ BasicBlock* const finallyReturnBlock = jumpDest->bbNext;
+ BasicBlock* const postTryFinallyBlock = finallyReturnBlock->bbJumpDest;
+
+ normalCallFinallyBlock = jumpDest;
+ normalCallFinallyReturn = postTryFinallyBlock;
+
+#if FEATURE_EH_CALLFINALLY_THUNKS
+ // When there are callfinally thunks, we don't expect to see the
+ // callfinally within a handler region either.
+ assert(!jumpDest->hasHndIndex());
+
+ // Update the clone insertion point to just after the
+ // call always pair.
+ cloneInsertAfter = finallyReturnBlock;
+
+ // We will consider moving the callfinally so we can fall
+ // through from the try into the clone.
+ tryToRelocateCallFinally = true;
+
+ JITDUMP("Chose path to clone: try block BB%02u jumps to callfinally at BB%02u;"
+ " the call returns to BB%02u which jumps to BB%02u\n",
+ block->bbNum, jumpDest->bbNum, finallyReturnBlock->bbNum, postTryFinallyBlock->bbNum);
+#else
+ JITDUMP("Chose path to clone: try block BB%02u is a callfinally;"
+ " the call returns to BB%02u which jumps to BB%02u\n",
+ block->bbNum, finallyReturnBlock->bbNum, postTryFinallyBlock->bbNum);
+#endif // FEATURE_EH_CALLFINALLY_THUNKS
+
+ break;
+ }
+
+ // If there is no call to the finally, don't clone.
+ if (normalCallFinallyBlock == nullptr)
+ {
+ JITDUMP("EH#%u: no calls from the try to the finally, skipping.\n", XTnum);
+ continue;
+ }
+
+ JITDUMP("Will update callfinally block BB%02u to jump to the clone;"
+ " clone will jump to BB%02u\n",
+ normalCallFinallyBlock->bbNum, normalCallFinallyReturn->bbNum);
+
+ // If there are multiple callfinallys and we're in the
+ // callfinally thunk model, all the callfinallys are placed
+ // just outside the try region. We'd like our chosen
+ // callfinally to come first after the try, so we can fall out of the try
+ // into the clone.
+ BasicBlock* firstCallFinallyRangeBlock = nullptr;
+ BasicBlock* endCallFinallyRangeBlock = nullptr;
+ ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
+
+ if (tryToRelocateCallFinally)
+ {
+ BasicBlock* firstCallFinallyBlock = nullptr;
+
+ for (BasicBlock* block = firstCallFinallyRangeBlock; block != endCallFinallyRangeBlock;
+ block = block->bbNext)
+ {
+ if (block->isBBCallAlwaysPair())
+ {
+ if (block->bbJumpDest == firstBlock)
+ {
+ firstCallFinallyBlock = block;
+ break;
+ }
+ }
+ }
+
+ // We better have found at least one call finally.
+ assert(firstCallFinallyBlock != nullptr);
+
+ // If there is more than one callfinally, move the one we are
+ // going to retarget to be first in the callfinally range.
+ if (firstCallFinallyBlock != normalCallFinallyBlock)
+ {
+ JITDUMP("Moving callfinally BB%02u to be first in line, before BB%02u\n", normalCallFinallyBlock->bbNum,
+ firstCallFinallyBlock->bbNum);
+
+ BasicBlock* const firstToMove = normalCallFinallyBlock;
+ BasicBlock* const lastToMove = normalCallFinallyBlock->bbNext;
+ BasicBlock* const placeToMoveAfter = firstCallFinallyBlock->bbPrev;
+
+ fgUnlinkRange(firstToMove, lastToMove);
+ fgMoveBlocksAfter(firstToMove, lastToMove, placeToMoveAfter);
+
+#ifdef DEBUG
+ // Sanity checks
+ fgDebugCheckBBlist(false, false);
+ fgVerifyHandlerTab();
+#endif // DEBUG
+
+ assert(nextBlock == lastBlock->bbNext);
+
+ // Update where the callfinally range begins, since we might
+ // have altered this with callfinally rearrangement, and/or
+ // the range begin might have been pretty loose to begin with.
+ firstCallFinallyRangeBlock = normalCallFinallyBlock;
+ }
+ }
+
+ // Clone the finally and retarget the normal return path and
+ // any other path that happens to share that same return
+ // point. For instance a construct like:
+ //
+ // try { } catch { } finally { }
+ //
+ // will have two call finally blocks, one for the normal exit
+ // from the try, and the the other for the exit from the
+ // catch. They'll both pass the same return point which is the
+ // statement after the finally, so they can share the clone.
+ //
+ // Clone the finally body, and splice it into the flow graph
+ // within in the parent region of the try.
+ const unsigned finallyTryIndex = firstBlock->bbTryIndex;
+ BasicBlock* insertAfter = nullptr;
+ BlockToBlockMap blockMap(getAllocator());
+ bool clonedOk = true;
+ unsigned cloneBBCount = 0;
+
+ for (BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
+ {
+ BasicBlock* newBlock;
+
+ if (block == firstBlock)
+ {
+ // Put first cloned finally block into the approprate
+ // region, somewhere within or after the range of
+ // callfinallys, depending on the EH implementation.
+ const unsigned hndIndex = 0;
+ BasicBlock* const nearBlk = cloneInsertAfter;
+ newBlock = fgNewBBinRegion(block->bbJumpKind, finallyTryIndex, hndIndex, nearBlk);
+
+ // If the clone ends up just after the finally, adjust
+ // the stopping point for finally traversal.
+ if (newBlock->bbNext == nextBlock)
+ {
+ assert(newBlock->bbPrev == lastBlock);
+ nextBlock = newBlock;
+ }
+ }
+ else
+ {
+ // Put subsequent blocks in the same region...
+ const bool extendRegion = true;
+ newBlock = fgNewBBafter(block->bbJumpKind, insertAfter, extendRegion);
+ }
+
+ cloneBBCount++;
+ assert(cloneBBCount <= regionBBCount);
+
+ insertAfter = newBlock;
+ blockMap.Set(block, newBlock);
+
+ clonedOk = BasicBlock::CloneBlockState(this, newBlock, block);
+
+ if (!clonedOk)
+ {
+ break;
+ }
+
+ // Update block flags. Note a block can be both first and last.
+ if (block == firstBlock)
+ {
+ // Mark the block as the start of the cloned finally.
+ newBlock->bbFlags |= BBF_CLONED_FINALLY_BEGIN;
+ }
+
+ if (block == lastBlock)
+ {
+ // Mark the block as the end of the cloned finally.
+ newBlock->bbFlags |= BBF_CLONED_FINALLY_END;
+ }
+
+ // Make sure clone block state hasn't munged the try region.
+ assert(newBlock->bbTryIndex == finallyTryIndex);
+
+ // Cloned handler block is no longer within the handler.
+ newBlock->clearHndIndex();
+
+ // Jump dests are set in a post-pass; make sure CloneBlockState hasn't tried to set them.
+ assert(newBlock->bbJumpDest == nullptr);
+ }
+
+ if (!clonedOk)
+ {
+ // TODO: cleanup the partial clone?
+ JITDUMP("Unable to clone the finally; skipping.\n");
+ continue;
+ }
+
+ // We should have cloned all the finally region blocks.
+ assert(cloneBBCount == regionBBCount);
+
+ JITDUMP("Cloned finally blocks are: BB%2u ... BB%2u\n", blockMap[firstBlock]->bbNum,
+ blockMap[lastBlock]->bbNum);
+
+ // Redirect redirect any branches within the newly-cloned
+ // finally, and any finally returns to jump to the return
+ // point.
+ for (BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
+ {
+ BasicBlock* newBlock = blockMap[block];
+
+ if (block->bbJumpKind == BBJ_EHFINALLYRET)
+ {
+ GenTreeStmt* finallyRet = newBlock->lastStmt();
+ GenTreePtr finallyRetExpr = finallyRet->gtStmtExpr;
+ assert(finallyRetExpr->gtOper == GT_RETFILT);
+ fgRemoveStmt(newBlock, finallyRet);
+ newBlock->bbJumpKind = BBJ_ALWAYS;
+ newBlock->bbJumpDest = normalCallFinallyReturn;
+
+ fgAddRefPred(normalCallFinallyReturn, newBlock);
+ }
+ else
+ {
+ optCopyBlkDest(block, newBlock);
+ optRedirectBlock(newBlock, &blockMap);
+ }
+ }
+
+ // Modify the targeting call finallys to branch to the cloned
+ // finally. Make a note if we see some calls that can't be
+ // retargeted (since they want to return to other places).
+ BasicBlock* const firstCloneBlock = blockMap[firstBlock];
+ bool retargetedAllCalls = true;
+ BasicBlock* currentBlock = firstCallFinallyRangeBlock;
+
+ while (currentBlock != endCallFinallyRangeBlock)
+ {
+ BasicBlock* nextBlockToScan = currentBlock->bbNext;
+
+ if (currentBlock->isBBCallAlwaysPair())
+ {
+ if (currentBlock->bbJumpDest == firstBlock)
+ {
+ BasicBlock* const leaveBlock = currentBlock->bbNext;
+ BasicBlock* const postTryFinallyBlock = leaveBlock->bbJumpDest;
+
+ // Note we must retarget all callfinallies that have this
+ // continuation, or we can't clean up the continuation
+ // block properly below, since it will be reachable both
+ // by the cloned finally and by the called finally.
+ if (postTryFinallyBlock == normalCallFinallyReturn)
+ {
+ // This call returns to the expected spot, so
+ // retarget it to branch to the clone.
+ currentBlock->bbJumpDest = firstCloneBlock;
+ currentBlock->bbJumpKind = BBJ_ALWAYS;
+
+ // Ref count updates.
+ fgAddRefPred(firstCloneBlock, currentBlock);
+ // fgRemoveRefPred(firstBlock, currentBlock);
+
+ // Delete the leave block, which should be marked as
+ // keep always.
+ assert((leaveBlock->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0);
+ nextBlock = leaveBlock->bbNext;
+
+ leaveBlock->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
+ fgRemoveBlock(leaveBlock, true);
+
+ // Make sure iteration isn't going off the deep end.
+ assert(leaveBlock != endCallFinallyRangeBlock);
+ }
+ else
+ {
+ // We can't retarget this call since it
+ // returns somewhere else.
+ retargetedAllCalls = false;
+ }
+ }
+ }
+
+ currentBlock = nextBlockToScan;
+ }
+
+ // If we retargeted all calls, modify EH descriptor to be
+ // try-fault instead of try-finally, and then non-cloned
+ // finally catch type to be fault.
+ if (retargetedAllCalls)
+ {
+ JITDUMP("All callfinallys retargeted; changing finally to fault.\n");
+ HBtab->ebdHandlerType = EH_HANDLER_FAULT_WAS_FINALLY;
+ firstBlock->bbCatchTyp = BBCT_FAULT;
+ }
+ else
+ {
+ JITDUMP("Some callfinallys *not* retargeted, so region must remain as a finally.\n");
+ }
+
+ // Modify first block of cloned finally to be a "normal" block.
+ BasicBlock* firstClonedBlock = blockMap[firstBlock];
+ firstClonedBlock->bbCatchTyp = BBCT_NONE;
+
+ // The normalCallFinallyReturn may be a finalStep block. It
+ // is now a normal block, since all the callfinallies that
+ // return to it are now going via the clone, so clear the
+ // special keep always flag.
+ normalCallFinallyReturn->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
+
+#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+ // Also, clear the finally target bit for arm
+ fgClearFinallyTargetBit(normalCallFinallyReturn);
+#endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
+
+#if !FEATURE_EH_FUNCLETS
+ // Remove the GT_END_LFIN from the normalCallFinallyReturn
+ // since no callfinally returns there anymore.
+ GenTreeStmt* endFinallyStmt = normalCallFinallyReturn->lastStmt();
+ GenTreePtr endFinallyExpr = endFinallyStmt->gtStmtExpr;
+ assert(endFinallyExpr->gtOper == GT_END_LFIN);
+ fgRemoveStmt(normalCallFinallyReturn, endFinallyStmt);
+#endif
+
+ // Todo -- mark cloned blocks as a cloned finally....
+
+ // Done!
+ JITDUMP("\nDone with EH#%u\n\n", XTnum);
+ cloneCount++;
+ }
+
+ if (cloneCount > 0)
+ {
+ JITDUMP("fgCloneFinally() cloned %u finally handlers\n", cloneCount);
+
+#ifdef DEBUG
+ if (verbose)
+ {
+ printf("\n*************** After fgCloneFinally()\n");
+ fgDispBasicBlocks();
+ fgDispHandlerTab();
+ printf("\n");
+ }
+
+ fgVerifyHandlerTab();
+ fgDebugCheckBBlist(false, false);
+ fgDebugCheckTryFinallyExits();
+
+#endif // DEBUG
+ }
+}
+
+#ifdef DEBUG
+
+//------------------------------------------------------------------------
+// fgDebugCheckTryFinallyExits: validate normal flow from try-finally
+// or try-fault-was-finally.
+//
+// Notes:
+//
+// Normal control flow exiting the try block of a try-finally must
+// pass through the finally. This checker attempts to verify that by
+// looking at the control flow graph.
+//
+// Each path that exits the try of a try-finally (including try-faults
+// that were optimized into try-finallys by fgCloneFinally) should
+// thus either execute a callfinally to the associated finally or else
+// jump to a block with the BBF_CLONED_FINALLY_BEGIN flag set.
+//
+// Depending on when this check is done, there may also be an empty
+// block along the path.
+//
+// Depending on the model for invoking finallys, the callfinallies may
+// lie within the try region (callfinally thunks) or in the enclosing
+// region.
+
+void Compiler::fgDebugCheckTryFinallyExits()
+{
+ unsigned XTnum = 0;
+ EHblkDsc* HBtab = compHndBBtab;
+ unsigned cloneCount = 0;
+ bool allTryExitsValid = true;
+ for (; XTnum < compHndBBtabCount; XTnum++, HBtab++)
+ {
+ const EHHandlerType handlerType = HBtab->ebdHandlerType;
+ const bool isFinally = (handlerType == EH_HANDLER_FINALLY);
+ const bool wasFinally = (handlerType == EH_HANDLER_FAULT_WAS_FINALLY);
+
+ // Screen out regions that are or were not finallys.
+ if (!isFinally && !wasFinally)
+ {
+ continue;
+ }
+
+ // Walk blocks of the try, looking for normal control flow to
+ // an ancestor region.
+
+ BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
+ BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
+ assert(firstTryBlock->getTryIndex() <= XTnum);
+ assert(lastTryBlock->getTryIndex() <= XTnum);
+ BasicBlock* const afterTryBlock = lastTryBlock->bbNext;
+ BasicBlock* const finallyBlock = isFinally ? HBtab->ebdHndBeg : nullptr;
+
+ for (BasicBlock* block = firstTryBlock; block != afterTryBlock; block = block->bbNext)
+ {
+ // Only check the directly contained blocks.
+ assert(block->hasTryIndex());
+
+ if (block->getTryIndex() != XTnum)
+ {
+ continue;
+ }
+
+ // Look at each of the normal control flow possibilities.
+ const unsigned numSuccs = block->NumSucc();
+
+ for (unsigned i = 0; i < numSuccs; i++)
+ {
+ BasicBlock* const succBlock = block->GetSucc(i);
+
+ if (succBlock->hasTryIndex() && succBlock->getTryIndex() <= XTnum)
+ {
+ // Successor does not exit this try region.
+ continue;
+ }
+
+#if FEATURE_EH_CALLFINALLY_THUNKS
+
+ // When there are callfinally thunks, callfinallies
+ // logically "belong" to a child region and the exit
+ // path validity will be checked when looking at the
+ // try blocks in that region.
+ if (block->bbJumpKind == BBJ_CALLFINALLY)
+ {
+ continue;
+ }
+
+#endif // FEATURE_EH_CALLFINALLY_THUNKS
+
+ // Now we know block lies directly within the try of a
+ // try-finally, and succBlock is in an enclosing
+ // region (possibly the method region). So this path
+ // represents flow out of the try and should be
+ // checked.
+ //
+ // There are various ways control can properly leave a
+ // try-finally (or try-fault-was-finally):
+ //
+ // (a1) via a jump to a callfinally (only for finallys, only for call finally thunks)
+ // (a2) via a callfinally (only for finallys, only for !call finally thunks)
+ // (b) via a jump to a begin finally clone block
+ // (c) via a jump to an empty block to (b)
+ // (d) via a fallthrough to an empty block to (b)
+ // (e) via the always half of a callfinally pair
+ // (f) via an always jump clonefinally exit
+ bool isCallToFinally = false;
+
+#if FEATURE_EH_CALLFINALLY_THUNKS
+ if (succBlock->bbJumpKind == BBJ_CALLFINALLY)
+ {
+ // case (a1)
+ isCallToFinally = isFinally && (succBlock->bbJumpDest == finallyBlock);
+ }
+#else
+ if (block->bbJumpKind == BBJ_CALLFINALLY)
+ {
+ // case (a2)
+ isCallToFinally = isFinally && (block->bbJumpDest == finallyBlock);
+ }
+#endif // FEATURE_EH_CALLFINALLY_THUNKS
+
+ bool isJumpToClonedFinally = false;
+
+ if (succBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
+ {
+ // case (b)
+ isJumpToClonedFinally = true;
+ }
+ else if (succBlock->bbJumpKind == BBJ_ALWAYS)
+ {
+ if (succBlock->isEmpty())
+ {
+ // case (c)
+ BasicBlock* const succSuccBlock = succBlock->bbJumpDest;
+
+ if (succSuccBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
+ {
+ isJumpToClonedFinally = true;
+ }
+ }
+ }
+ else if (succBlock->bbJumpKind == BBJ_NONE)
+ {
+ if (succBlock->isEmpty())
+ {
+ BasicBlock* const succSuccBlock = succBlock->bbNext;
+
+ // case (d)
+ if (succSuccBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
+ {
+ isJumpToClonedFinally = true;
+ }
+ }
+ }
+
+ bool isReturnFromFinally = false;
+
+ // Case (e). Ideally we'd have something stronger to
+ // check here -- eg that we are returning from a call
+ // to the right finally -- but there are odd cases
+ // like orphaned second halves of callfinally pairs
+ // that we need to tolerate.
+ if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
+ {
+ isReturnFromFinally = true;
+ }
+
+ // Case (f)
+ if (block->bbFlags & BBF_CLONED_FINALLY_END)
+ {
+ isReturnFromFinally = true;
+ }
+
+ const bool thisExitValid = isCallToFinally || isJumpToClonedFinally || isReturnFromFinally;
+
+ if (!thisExitValid)
+ {
+ JITDUMP("fgCheckTryFinallyExitS: EH#%u exit via BB%02u -> BB%02u is invalid\n", XTnum, block->bbNum,
+ succBlock->bbNum);
+ }
+
+ allTryExitsValid = allTryExitsValid & thisExitValid;
+ }
+ }
+ }
+
+ if (!allTryExitsValid)
+ {
+ JITDUMP("fgCheckTryFinallyExits: method contains invalid try exit paths\n");
+ assert(allTryExitsValid);
+ }
+}
+
+#endif // DEBUG
noway_assert(!isflt);
break;
-#ifdef DEBUG
default:
+#ifdef DEBUG
noway_assert(!"Unhandled special operator in gtComputeFPlvls()");
- break;
#endif
+ break;
}
DONE:
#ifdef FEATURE_SIMD
lvaTable[shadowVar].lvSIMDType = varDsc->lvSIMDType;
+ lvaTable[shadowVar].lvExactSize = varDsc->lvExactSize;
lvaTable[shadowVar].lvUsedInSIMDIntrinsic = varDsc->lvUsedInSIMDIntrinsic;
if (varDsc->lvSIMDType)
{
GTNODE(PINVOKE_PROLOG ,"pinvoke_prolog",GenTree ,0,GTK_LEAF|GTK_NOVALUE) // pinvoke prolog seq
GTNODE(PINVOKE_EPILOG ,"pinvoke_epilog",GenTree ,0,GTK_LEAF|GTK_NOVALUE) // pinvoke epilog seq
GTNODE(PUTARG_REG , "putarg_reg" ,GenTreeOp ,0,GTK_UNOP) // operator that places outgoing arg in register
-GTNODE(PUTARG_STK , "putarg_stk" ,GenTreePutArgStk ,0,GTK_UNOP) // operator that places outgoing arg in stack
+GTNODE(PUTARG_STK , "putarg_stk" ,GenTreePutArgStk ,0,GTK_UNOP|GTK_NOVALUE) // operator that places outgoing arg in stack
GTNODE(RETURNTRAP , "returnTrap" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // a conditional call to wait on gc
GTNODE(SWAP , "swap" ,GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) // op1 and op2 swap (registers)
GTNODE(IL_OFFSET , "il_offset" ,GenTreeStmt ,0,GTK_LEAF|GTK_NOVALUE) // marks an IL offset for debugging purposes
const DWORD structFlags = info.compCompHnd->getClassAttribs(structHnd);
var_types structType = TYP_STRUCT;
-#ifdef FEATURE_CORECLR
- const bool hasGCPtrs = (structFlags & CORINFO_FLG_CONTAINS_GC_PTR) != 0;
-#else
- // Desktop CLR won't report FLG_CONTAINS_GC_PTR for RefAnyClass - need to check explicitly.
- const bool isRefAny = (structHnd == impGetRefAnyClass());
- const bool hasGCPtrs = isRefAny || ((structFlags & CORINFO_FLG_CONTAINS_GC_PTR) != 0);
-#endif
+ // On coreclr the check for GC includes a "may" to account for the special
+ // ByRef like span structs. The added check for "CONTAINS_STACK_PTR" is the particular bit.
+ // When this is set the struct will contain a ByRef that could be a GC pointer or a native
+ // pointer.
+ const bool mayContainGCPtrs =
+ ((structFlags & CORINFO_FLG_CONTAINS_STACK_PTR) != 0 || ((structFlags & CORINFO_FLG_CONTAINS_GC_PTR) != 0));
#ifdef FEATURE_SIMD
// Check to see if this is a SIMD type.
- if (featureSIMD && !hasGCPtrs)
+ if (featureSIMD && !mayContainGCPtrs)
{
unsigned originalSize = info.compCompHnd->getClassSize(structHnd);
// Verify that the quick test up above via the class attributes gave a
// safe view of the type's GCness.
//
- // Note there are cases where hasGCPtrs is true but getClassGClayout
+ // Note there are cases where mayContainGCPtrs is true but getClassGClayout
// does not report any gc fields.
- assert(hasGCPtrs || (numGCVars == 0));
+
+ assert(mayContainGCPtrs || (numGCVars == 0));
if (pNumGCVars != nullptr)
{
// Returns the GenTree that should be used to do the intrinsic instead of the call.
// Returns NULL if an intrinsic cannot be used
-GenTreePtr Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
+GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
+ CORINFO_CLASS_HANDLE clsHnd,
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
int memberRef,
#if COR_JIT_EE_VERSION > 460
CorInfoIntrinsics intrinsicID = info.compCompHnd->getIntrinsicID(method, &mustExpand);
#else
- CorInfoIntrinsics intrinsicID = info.compCompHnd->getIntrinsicID(method);
+ CorInfoIntrinsics intrinsicID = info.compCompHnd->getIntrinsicID(method);
#endif
*pIntrinsicID = intrinsicID;
retNode = op1;
break;
#endif
-
+ // Implement ByReference Ctor. This wraps the assignment of the ref into a byref-like field
+ // in a value type. The canonical example of this is Span<T>. In effect this is just a
+ // substitution. The parameter byref will be assigned into the newly allocated object.
+ case CORINFO_INTRINSIC_ByReference_Ctor:
+ {
+ // Remove call to constructor and directly assign the byref passed
+ // to the call to the first slot of the ByReference struct.
+ op1 = impPopStack().val;
+ GenTreePtr thisptr = newobjThis;
+ CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
+ GenTreePtr field = gtNewFieldRef(TYP_BYREF, fldHnd, thisptr, 0, false);
+ GenTreePtr assign = gtNewAssignNode(field, op1);
+ GenTreePtr byReferenceStruct = gtCloneExpr(thisptr->gtGetOp1());
+ assert(byReferenceStruct != nullptr);
+ impPushOnStack(byReferenceStruct, typeInfo(TI_STRUCT, clsHnd));
+ retNode = assign;
+ break;
+ }
+ // Implement ptr value getter for ByReference struct.
+ case CORINFO_INTRINSIC_ByReference_Value:
+ {
+ op1 = impPopStack().val;
+ CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
+ GenTreePtr field = gtNewFieldRef(TYP_BYREF, fldHnd, op1, 0, false);
+ retNode = field;
+ break;
+ }
default:
/* Unknown intrinsic */
break;
}
//------------------------------------------------------------------------
-// impCanPInvokeInline: examine information from a call to see if the call
-// qualifies as an inline pinvoke.
-//
-// Arguments:
-// block - block contaning the call, or for inlinees, block
-// containing the call being inlined
+// impCanPInvokeInline: check whether PInvoke inlining should enabled in current method.
//
// Return Value:
-// true if this call qualifies as an inline pinvoke, false otherwise
+// true if PInvoke inlining should be enabled in current method, false otherwise
//
// Notes:
-// Checks basic legality and then a number of ambient conditions
-// where we could pinvoke but choose not to
+// Checks a number of ambient conditions where we could pinvoke but choose not to
-bool Compiler::impCanPInvokeInline(BasicBlock* block)
+bool Compiler::impCanPInvokeInline()
{
- return impCanPInvokeInlineCallSite(block) && getInlinePInvokeEnabled() && (!opts.compDbgCode) &&
- (compCodeOpt() != SMALL_CODE) && (!opts.compNoPInvokeInlineCB) // profiler is preventing inline pinvoke
+ return getInlinePInvokeEnabled() && (!opts.compDbgCode) && (compCodeOpt() != SMALL_CODE) &&
+ (!opts.compNoPInvokeInlineCB) // profiler is preventing inline pinvoke
;
}
//------------------------------------------------------------------------
-// impCanPInvokeInlineSallSite: basic legality checks using information
+// impCanPInvokeInlineCallSite: basic legality checks using information
// from a call to see if the call qualifies as an inline pinvoke.
//
// Arguments:
bool Compiler::impCanPInvokeInlineCallSite(BasicBlock* block)
{
+ if (block->hasHndIndex())
+ {
+ return false;
+ }
+
+ // The remaining limitations do not apply to CoreRT
+ if (IsTargetAbi(CORINFO_CORERT_ABI))
+ {
+ return true;
+ }
+
#ifdef _TARGET_AMD64_
// On x64, we disable pinvoke inlining inside of try regions.
// Here is the comment from JIT64 explaining why:
//
// A desktop test case where this seems to matter is
// jit\jit64\ebvts\mcpp\sources2\ijw\__clrcall\vector_ctor_dtor.02\deldtor_clr.exe
- const bool inX64Try = block->hasTryIndex();
-#else
- const bool inX64Try = false;
+ if (block->hasTryIndex())
+ {
+ return false;
+ }
#endif // _TARGET_AMD64_
- return !inX64Try && !block->hasHndIndex();
+ return true;
}
//------------------------------------------------------------------------
}
optNativeCallCount++;
- if (opts.compMustInlinePInvokeCalli && methHnd == nullptr)
+ if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB) && methHnd == nullptr)
{
- // Always inline pinvoke.
+ // PInvoke CALLI in IL stubs must be inlined
}
else
{
- // Check legality and profitability.
- if (!impCanPInvokeInline(block))
+ // Check legality
+ if (!impCanPInvokeInlineCallSite(block))
{
return;
}
- if (info.compCompHnd->pInvokeMarshalingRequired(methHnd, sig))
+ // PInvoke CALL in IL stubs must be inlined on CoreRT. Skip the ambient conditions checks and
+ // profitability checks
+ if (!(opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB) && IsTargetAbi(CORINFO_CORERT_ABI)))
{
- return;
+ if (impCanPInvokeInline())
+ {
+ return;
+ }
+
+ // Size-speed tradeoff: don't use inline pinvoke at rarely
+ // executed call sites. The non-inline version is more
+ // compact.
+ if (block->isRunRarely())
+ {
+ return;
+ }
}
- // Size-speed tradeoff: don't use inline pinvoke at rarely
- // executed call sites. The non-inline version is more
- // compact.
- if (block->isRunRarely())
+ // The expensive check should be last
+ if (info.compCompHnd->pInvokeMarshalingRequired(methHnd, sig))
{
return;
}
((nextOpcode == CEE_NOP) || ((nextOpcode == CEE_POP) && (++cntPop == 1)))); // Next opcode = nop or exactly
// one pop seen so far.
#else
- nextOpcode = (OPCODE)getU1LittleEndian(codeAddrOfNextOpcode);
+ nextOpcode = (OPCODE)getU1LittleEndian(codeAddrOfNextOpcode);
#endif
if (isCallPopAndRet)
// <NICE> Factor this into getCallInfo </NICE>
if ((mflags & CORINFO_FLG_INTRINSIC) && !pConstrainedResolvedToken)
{
- call = impIntrinsic(clsHnd, methHnd, sig, pResolvedToken->token, readonlyCall,
+ call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, pResolvedToken->token, readonlyCall,
(canTailCall && (tailCall != 0)), &intrinsicID);
if (call != nullptr)
CONFIG_INTEGER(JitEECallTimingInfo, W("JitEECallTimingInfo"), 0)
+#if defined(DEBUG)
+#if defined(FEATURE_CORECLR)
+CONFIG_INTEGER(JitEnableFinallyCloning, W("JitEnableFinallyCloning"), 1)
+#else
+CONFIG_INTEGER(JitEnableFinallyCloning, W("JitEnableFinallyCloning"), 0)
+#endif // defined(FEATURE_CORECLR)
+#endif // DEBUG
+
#undef CONFIG_INTEGER
#undef CONFIG_STRING
#undef CONFIG_METHODSET
bool EHblkDsc::HasFaultHandler()
{
- return ebdHandlerType == EH_HANDLER_FAULT;
+ return (ebdHandlerType == EH_HANDLER_FAULT) || (ebdHandlerType == EH_HANDLER_FAULT_WAS_FINALLY);
}
bool EHblkDsc::HasFinallyOrFaultHandler()
EH_HANDLER_CATCH = 0x1, // Don't use zero (to aid debugging uninitialized memory)
EH_HANDLER_FILTER,
EH_HANDLER_FAULT,
- EH_HANDLER_FINALLY
+ EH_HANDLER_FINALLY,
+ EH_HANDLER_FAULT_WAS_FINALLY
};
// ToCORINFO_EH_CLAUSE_FLAGS: Convert an internal EHHandlerType to a CORINFO_EH_CLAUSE_FLAGS value
case EH_HANDLER_FILTER:
return CORINFO_EH_CLAUSE_FILTER;
case EH_HANDLER_FAULT:
+ case EH_HANDLER_FAULT_WAS_FINALLY:
return CORINFO_EH_CLAUSE_FAULT;
case EH_HANDLER_FINALLY:
return CORINFO_EH_CLAUSE_FINALLY;
}
else if (!def->IsValue())
{
- // Calls may contain "uses" of nodes that do not produce a value. This is an artifact of
- // the HIR and should probably be fixed, but doing so is an unknown amount of work.
- assert(node->OperGet() == GT_CALL);
+ // Stack arguments do not produce a value, but they are considered children of the call.
+ // It may be useful to remove these from being call operands, but that may also impact
+ // other code that relies on being able to reach all the operands from a call node.
+ // The GT_NOP case is because sometimes we eliminate stack argument stores as dead, but
+ // instead of removing them we replace with a NOP.
+ assert((node->OperGet() == GT_CALL) &&
+ (def->OperIsStore() || (def->OperGet() == GT_PUTARG_STK) || (def->OperGet() == GT_NOP)));
continue;
}
GenTreePtr addrArg = tree->gtOp.gtOp1->gtEffectiveVal(/*commaOnly*/ true);
if (!addrArg->DefinesLocalAddr(this, /*width doesn't matter*/ 0, &dummyLclVarTree, &dummyIsEntire))
{
- if (!fgCurHeapDef)
- {
- fgCurHeapUse = true;
- }
+ fgCurHeapUse = true;
}
else
{
return liveVars;
}
-/*****************************************************************************
- *
- * This is the classic algorithm for Live Variable Analysis.
- * If updateInternalOnly==true, only update BBF_INTERNAL blocks.
- */
-
-void Compiler::fgLiveVarAnalysis(bool updateInternalOnly)
+class LiveVarAnalysis
{
- BasicBlock* block;
- bool change;
-#ifdef DEBUG
- VARSET_TP VARSET_INIT_NOCOPY(extraLiveOutFromFinally, VarSetOps::MakeEmpty(this));
-#endif // DEBUG
- bool keepAliveThis = lvaKeepAliveAndReportThis() && lvaTable[info.compThisArg].lvTracked;
+ Compiler* m_compiler;
- /* Live Variable Analysis - Backward dataflow */
+ bool m_hasPossibleBackEdge;
- bool hasPossibleBackEdge = false;
+ bool m_heapLiveIn;
+ bool m_heapLiveOut;
+ VARSET_TP m_liveIn;
+ VARSET_TP m_liveOut;
- do
+ LiveVarAnalysis(Compiler* compiler)
+ : m_compiler(compiler)
+ , m_hasPossibleBackEdge(false)
+ , m_heapLiveIn(false)
+ , m_heapLiveOut(false)
+ , m_liveIn(VarSetOps::MakeEmpty(compiler))
+ , m_liveOut(VarSetOps::MakeEmpty(compiler))
{
- change = false;
-
- /* Visit all blocks and compute new data flow values */
-
- VARSET_TP VARSET_INIT_NOCOPY(liveIn, VarSetOps::MakeEmpty(this));
- VARSET_TP VARSET_INIT_NOCOPY(liveOut, VarSetOps::MakeEmpty(this));
-
- bool heapLiveIn = false;
- bool heapLiveOut = false;
+ }
- for (block = fgLastBB; block; block = block->bbPrev)
+ bool PerBlockAnalysis(BasicBlock* block, bool updateInternalOnly, bool keepAliveThis)
+ {
+ /* Compute the 'liveOut' set */
+ VarSetOps::ClearD(m_compiler, m_liveOut);
+ m_heapLiveOut = false;
+ if (block->endsWithJmpMethod(m_compiler))
{
- // sometimes block numbers are not monotonically increasing which
- // would cause us not to identify backedges
- if (block->bbNext && block->bbNext->bbNum <= block->bbNum)
+ // A JMP uses all the arguments, so mark them all
+ // as live at the JMP instruction
+ //
+ const LclVarDsc* varDscEndParams = m_compiler->lvaTable + m_compiler->info.compArgsCount;
+ for (LclVarDsc* varDsc = m_compiler->lvaTable; varDsc < varDscEndParams; varDsc++)
{
- hasPossibleBackEdge = true;
+ noway_assert(!varDsc->lvPromoted);
+ if (varDsc->lvTracked)
+ {
+ VarSetOps::AddElemD(m_compiler, m_liveOut, varDsc->lvVarIndex);
+ }
}
+ }
- if (updateInternalOnly)
+ // Additionally, union in all the live-in tracked vars of successors.
+ AllSuccessorIter succsEnd = block->GetAllSuccs(m_compiler).end();
+ for (AllSuccessorIter succs = block->GetAllSuccs(m_compiler).begin(); succs != succsEnd; ++succs)
+ {
+ BasicBlock* succ = (*succs);
+ VarSetOps::UnionD(m_compiler, m_liveOut, succ->bbLiveIn);
+ m_heapLiveOut = m_heapLiveOut || (*succs)->bbHeapLiveIn;
+ if (succ->bbNum <= block->bbNum)
{
- /* Only update BBF_INTERNAL blocks as they may be
- syntactically out of sequence. */
+ m_hasPossibleBackEdge = true;
+ }
+ }
- noway_assert(opts.compDbgCode && (info.compVarScopesCount > 0));
+ /* For lvaKeepAliveAndReportThis methods, "this" has to be kept alive everywhere
+ Note that a function may end in a throw on an infinite loop (as opposed to a return).
+ "this" has to be alive everywhere even in such methods. */
- if (!(block->bbFlags & BBF_INTERNAL))
- {
- continue;
- }
- }
+ if (keepAliveThis)
+ {
+ VarSetOps::AddElemD(m_compiler, m_liveOut, m_compiler->lvaTable[m_compiler->info.compThisArg].lvVarIndex);
+ }
+
+ /* Compute the 'm_liveIn' set */
+ VarSetOps::Assign(m_compiler, m_liveIn, m_liveOut);
+ VarSetOps::DiffD(m_compiler, m_liveIn, block->bbVarDef);
+ VarSetOps::UnionD(m_compiler, m_liveIn, block->bbVarUse);
- /* Compute the 'liveOut' set */
+ m_heapLiveIn = (m_heapLiveOut && !block->bbHeapDef) || block->bbHeapUse;
+
+ /* Can exceptions from this block be handled (in this function)? */
+
+ if (m_compiler->ehBlockHasExnFlowDsc(block))
+ {
+ VARSET_TP VARSET_INIT_NOCOPY(liveVars, m_compiler->fgGetHandlerLiveVars(block));
- VarSetOps::ClearD(this, liveOut);
- heapLiveOut = false;
- if (block->endsWithJmpMethod(this))
+ VarSetOps::UnionD(m_compiler, m_liveIn, liveVars);
+ VarSetOps::UnionD(m_compiler, m_liveOut, liveVars);
+ }
+
+ /* Has there been any change in either live set? */
+
+ bool liveInChanged = !VarSetOps::Equal(m_compiler, block->bbLiveIn, m_liveIn);
+ if (liveInChanged || !VarSetOps::Equal(m_compiler, block->bbLiveOut, m_liveOut))
+ {
+ if (updateInternalOnly)
{
- // A JMP uses all the arguments, so mark them all
- // as live at the JMP instruction
- //
- const LclVarDsc* varDscEndParams = lvaTable + info.compArgsCount;
- for (LclVarDsc* varDsc = lvaTable; varDsc < varDscEndParams; varDsc++)
+ // Only "extend" liveness over BBF_INTERNAL blocks
+
+ noway_assert(block->bbFlags & BBF_INTERNAL);
+
+ liveInChanged =
+ !VarSetOps::Equal(m_compiler, VarSetOps::Intersection(m_compiler, block->bbLiveIn, m_liveIn),
+ m_liveIn);
+ if (liveInChanged ||
+ !VarSetOps::Equal(m_compiler, VarSetOps::Intersection(m_compiler, block->bbLiveOut, m_liveOut),
+ m_liveOut))
{
- noway_assert(!varDsc->lvPromoted);
- if (varDsc->lvTracked)
+#ifdef DEBUG
+ if (m_compiler->verbose)
{
- VarSetOps::AddElemD(this, liveOut, varDsc->lvVarIndex);
+ printf("Scope info: block BB%02u LiveIn+ ", block->bbNum);
+ dumpConvertedVarSet(m_compiler, VarSetOps::Diff(m_compiler, m_liveIn, block->bbLiveIn));
+ printf(", LiveOut+ ");
+ dumpConvertedVarSet(m_compiler, VarSetOps::Diff(m_compiler, m_liveOut, block->bbLiveOut));
+ printf("\n");
}
- }
- }
+#endif // DEBUG
- // Additionally, union in all the live-in tracked vars of successors.
- AllSuccessorIter succsEnd = block->GetAllSuccs(this).end();
- for (AllSuccessorIter succs = block->GetAllSuccs(this).begin(); succs != succsEnd; ++succs)
- {
- BasicBlock* succ = (*succs);
- VarSetOps::UnionD(this, liveOut, succ->bbLiveIn);
- heapLiveOut = heapLiveOut || (*succs)->bbHeapLiveIn;
- if (succ->bbNum <= block->bbNum)
- {
- hasPossibleBackEdge = true;
+ VarSetOps::UnionD(m_compiler, block->bbLiveIn, m_liveIn);
+ VarSetOps::UnionD(m_compiler, block->bbLiveOut, m_liveOut);
}
}
-
- /* For lvaKeepAliveAndReportThis methods, "this" has to be kept alive everywhere
- Note that a function may end in a throw on an infinite loop (as opposed to a return).
- "this" has to be alive everywhere even in such methods. */
-
- if (keepAliveThis)
+ else
{
- VarSetOps::AddElemD(this, liveOut, lvaTable[info.compThisArg].lvVarIndex);
+ VarSetOps::Assign(m_compiler, block->bbLiveIn, m_liveIn);
+ VarSetOps::Assign(m_compiler, block->bbLiveOut, m_liveOut);
}
+ }
- /* Compute the 'liveIn' set */
+ const bool heapLiveInChanged = (block->bbHeapLiveIn == 1) != m_heapLiveIn;
+ if (heapLiveInChanged || (block->bbHeapLiveOut == 1) != m_heapLiveOut)
+ {
+ block->bbHeapLiveIn = m_heapLiveIn;
+ block->bbHeapLiveOut = m_heapLiveOut;
+ }
- VarSetOps::Assign(this, liveIn, liveOut);
- VarSetOps::DiffD(this, liveIn, block->bbVarDef);
- VarSetOps::UnionD(this, liveIn, block->bbVarUse);
+ return liveInChanged || heapLiveInChanged;
+ }
- heapLiveIn = (heapLiveOut && !block->bbHeapDef) || block->bbHeapUse;
+ void Run(bool updateInternalOnly)
+ {
+ const bool keepAliveThis =
+ m_compiler->lvaKeepAliveAndReportThis() && m_compiler->lvaTable[m_compiler->info.compThisArg].lvTracked;
- /* Can exceptions from this block be handled (in this function)? */
+ /* Live Variable Analysis - Backward dataflow */
+ bool changed;
+ do
+ {
+ changed = false;
- if (ehBlockHasExnFlowDsc(block))
- {
- VARSET_TP VARSET_INIT_NOCOPY(liveVars, fgGetHandlerLiveVars(block));
+ /* Visit all blocks and compute new data flow values */
- VarSetOps::UnionD(this, liveIn, liveVars);
- VarSetOps::UnionD(this, liveOut, liveVars);
- }
+ VarSetOps::ClearD(m_compiler, m_liveIn);
+ VarSetOps::ClearD(m_compiler, m_liveOut);
- /* Has there been any change in either live set? */
+ m_heapLiveIn = false;
+ m_heapLiveOut = false;
- if (!VarSetOps::Equal(this, block->bbLiveIn, liveIn) || !VarSetOps::Equal(this, block->bbLiveOut, liveOut))
+ for (BasicBlock* block = m_compiler->fgLastBB; block; block = block->bbPrev)
{
+ // sometimes block numbers are not monotonically increasing which
+ // would cause us not to identify backedges
+ if (block->bbNext && block->bbNext->bbNum <= block->bbNum)
+ {
+ m_hasPossibleBackEdge = true;
+ }
+
if (updateInternalOnly)
{
- // Only "extend" liveness over BBF_INTERNAL blocks
+ /* Only update BBF_INTERNAL blocks as they may be
+ syntactically out of sequence. */
- noway_assert(block->bbFlags & BBF_INTERNAL);
+ noway_assert(m_compiler->opts.compDbgCode && (m_compiler->info.compVarScopesCount > 0));
- if (!VarSetOps::Equal(this, VarSetOps::Intersection(this, block->bbLiveIn, liveIn), liveIn) ||
- !VarSetOps::Equal(this, VarSetOps::Intersection(this, block->bbLiveOut, liveOut), liveOut))
+ if (!(block->bbFlags & BBF_INTERNAL))
{
-#ifdef DEBUG
- if (verbose)
- {
- printf("Scope info: block BB%02u LiveIn+ ", block->bbNum);
- dumpConvertedVarSet(this, VarSetOps::Diff(this, liveIn, block->bbLiveIn));
- printf(", LiveOut+ ");
- dumpConvertedVarSet(this, VarSetOps::Diff(this, liveOut, block->bbLiveOut));
- printf("\n");
- }
-#endif // DEBUG
-
- VarSetOps::UnionD(this, block->bbLiveIn, liveIn);
- VarSetOps::UnionD(this, block->bbLiveOut, liveOut);
- change = true;
+ continue;
}
}
- else
+
+ if (PerBlockAnalysis(block, updateInternalOnly, keepAliveThis))
{
- VarSetOps::Assign(this, block->bbLiveIn, liveIn);
- VarSetOps::Assign(this, block->bbLiveOut, liveOut);
- change = true;
+ changed = true;
}
}
-
- if ((block->bbHeapLiveIn == 1) != heapLiveIn || (block->bbHeapLiveOut == 1) != heapLiveOut)
+ // if there is no way we could have processed a block without seeing all of its predecessors
+ // then there is no need to iterate
+ if (!m_hasPossibleBackEdge)
{
- block->bbHeapLiveIn = heapLiveIn;
- block->bbHeapLiveOut = heapLiveOut;
- change = true;
+ break;
}
- }
- // if there is no way we could have processed a block without seeing all of its predecessors
- // then there is no need to iterate
- if (!hasPossibleBackEdge)
- {
- break;
- }
- } while (change);
+ } while (changed);
+ }
-//-------------------------------------------------------------------------
+public:
+ static void Run(Compiler* compiler, bool updateInternalOnly)
+ {
+ LiveVarAnalysis analysis(compiler);
+ analysis.Run(updateInternalOnly);
+ }
+};
-#ifdef DEBUG
+/*****************************************************************************
+ *
+ * This is the classic algorithm for Live Variable Analysis.
+ * If updateInternalOnly==true, only update BBF_INTERNAL blocks.
+ */
+void Compiler::fgLiveVarAnalysis(bool updateInternalOnly)
+{
+ LiveVarAnalysis::Run(this, updateInternalOnly);
+
+#ifdef DEBUG
if (verbose && !updateInternalOnly)
{
printf("\nBB liveness after fgLiveVarAnalysis():\n\n");
fgDispBBLiveness();
}
-
#endif // DEBUG
}
GenTreePtr putArg = nullptr;
bool updateArgTable = true;
-#if !defined(_TARGET_64BIT_)
- if (varTypeIsLong(type))
- {
- // For TYP_LONG, we leave the GT_LONG as the arg, and put the putArg below it.
- // Therefore, we don't update the arg table entry.
- updateArgTable = false;
- type = TYP_INT;
- }
-#endif // !defined(_TARGET_64BIT_)
-
bool isOnStack = true;
#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
if (varTypeIsStruct(type))
NYI("Lowering of long register argument");
}
- // For longs, we will create two PUTARG_STKs below the GT_LONG. The hi argument needs to
- // be pushed first, so the hi PUTARG_STK will precede the lo PUTARG_STK in execution order.
+ // For longs, we will replace the GT_LONG with a GT_FIELD_LIST, and put that under a PUTARG_STK.
+ // Although the hi argument needs to be pushed first, that will be handled by the general case,
+ // in which the fields will be reversed.
noway_assert(arg->OperGet() == GT_LONG);
- GenTreePtr argLo = arg->gtGetOp1();
- GenTreePtr argHi = arg->gtGetOp2();
-
- GenTreePtr putArgLo = NewPutArg(call, argLo, info, type);
- GenTreePtr putArgHi = NewPutArg(call, argHi, info, type);
-
- arg->gtOp.gtOp1 = putArgLo;
- arg->gtOp.gtOp2 = putArgHi;
-
- BlockRange().InsertBefore(arg, putArgHi, putArgLo);
-
- // The execution order now looks like this:
- // argLoPrev <-> argLoFirst ... argLo <-> argHiFirst ... argHi <-> putArgHi <-> putArgLo <-> arg(GT_LONG)
-
- assert((arg->gtFlags & GTF_REVERSE_OPS) == 0);
- arg->gtFlags |= GTF_REVERSE_OPS; // We consume the high arg (op2) first.
+ assert(info->numSlots == 2);
+ GenTreePtr argLo = arg->gtGetOp1();
+ GenTreePtr argHi = arg->gtGetOp2();
+ GenTreeFieldList* fieldList = new (comp, GT_FIELD_LIST) GenTreeFieldList(argLo, 0, TYP_INT, nullptr);
+ // Only the first fieldList node (GTF_FIELD_LIST_HEAD) is in the instruction sequence.
+ (void)new (comp, GT_FIELD_LIST) GenTreeFieldList(argHi, 4, TYP_INT, fieldList);
+ putArg = NewPutArg(call, fieldList, info, TYP_VOID);
+
+ // We can't call ReplaceArgWithPutArgOrCopy here because it presumes that we are keeping the original arg.
+ BlockRange().InsertBefore(arg, fieldList, putArg);
+ BlockRange().Remove(arg);
+ *ppArg = putArg;
}
else
#endif // !defined(_TARGET_64BIT_)
{
TreeNodeInfo* info = &(tree->gtLsraInfo);
unsigned kind = tree->OperKind();
- info->dstCount = (tree->TypeGet() == TYP_VOID) ? 0 : 1;
+ info->dstCount = tree->IsValue() ? 1 : 0;
if (kind & (GTK_CONST | GTK_LEAF))
{
info->srcCount = 0;
if (!(args->gtFlags & GTF_LATE_ARG))
{
TreeNodeInfo* argInfo = &(arg->gtLsraInfo);
-#if !defined(_TARGET_64BIT_)
- if (arg->TypeGet() == TYP_LONG)
+ if (argInfo->dstCount != 0)
{
- assert(arg->OperGet() == GT_LONG);
- GenTreePtr loArg = arg->gtGetOp1();
- GenTreePtr hiArg = arg->gtGetOp2();
- assert((loArg->OperGet() == GT_PUTARG_STK) && (hiArg->OperGet() == GT_PUTARG_STK));
- assert((loArg->gtLsraInfo.dstCount == 1) && (hiArg->gtLsraInfo.dstCount == 1));
- loArg->gtLsraInfo.isLocalDefUse = true;
- hiArg->gtLsraInfo.isLocalDefUse = true;
+ argInfo->isLocalDefUse = true;
}
- else
-#endif // !defined(_TARGET_64BIT_)
- {
- if (argInfo->dstCount != 0)
- {
- argInfo->isLocalDefUse = true;
- }
- // If the child of GT_PUTARG_STK is a constant, we don't need a register to
- // move it to memory (stack location).
- //
- // On AMD64, we don't want to make 0 contained, because we can generate smaller code
- // by zeroing a register and then storing it. E.g.:
- // xor rdx, rdx
- // mov gword ptr [rsp+28H], rdx
- // is 2 bytes smaller than:
- // mov gword ptr [rsp+28H], 0
- //
- // On x86, we push stack arguments; we don't use 'mov'. So:
- // push 0
- // is 1 byte smaller than:
- // xor rdx, rdx
- // push rdx
-
- argInfo->dstCount = 0;
- if (arg->gtOper == GT_PUTARG_STK)
- {
- GenTree* op1 = arg->gtOp.gtOp1;
- if (IsContainableImmed(arg, op1)
+ // If the child of GT_PUTARG_STK is a constant, we don't need a register to
+ // move it to memory (stack location).
+ //
+ // On AMD64, we don't want to make 0 contained, because we can generate smaller code
+ // by zeroing a register and then storing it. E.g.:
+ // xor rdx, rdx
+ // mov gword ptr [rsp+28H], rdx
+ // is 2 bytes smaller than:
+ // mov gword ptr [rsp+28H], 0
+ //
+ // On x86, we push stack arguments; we don't use 'mov'. So:
+ // push 0
+ // is 1 byte smaller than:
+ // xor rdx, rdx
+ // push rdx
+
+ argInfo->dstCount = 0;
+ if (arg->gtOper == GT_PUTARG_STK)
+ {
+ GenTree* op1 = arg->gtOp.gtOp1;
+ if (IsContainableImmed(arg, op1)
#if defined(_TARGET_AMD64_)
- && !op1->IsIntegralConst(0)
+ && !op1->IsIntegralConst(0)
#endif // _TARGET_AMD64_
- )
- {
- MakeSrcContained(arg, op1);
- }
+ )
+ {
+ MakeSrcContained(arg, op1);
}
}
}
fgDebugCheckBBlist(false, false);
#endif // DEBUG
+ fgRemoveEmptyFinally();
+
+ EndPhase(PHASE_EMPTY_FINALLY);
+
+ fgCloneFinally();
+
+ EndPhase(PHASE_CLONE_FINALLY);
+
/* For x64 and ARM64 we need to mark irregular parameters early so that they don't get promoted */
fgMarkImplicitByRefArgs();
#pragma hdrstop
#endif
+#ifndef LEGACY_BACKEND
// state carried over the tree walk, to be used in making
// a splitting decision.
struct SplitData
comp->compRationalIRForm = true;
}
+#endif // LEGACY_BACKEND
{
if (succ->bbHeapSsaPhiFunc == BasicBlock::EmptyHeapPhiDef)
{
- succ->bbHeapSsaPhiFunc = new (m_pCompiler) BasicBlock::HeapPhiArg(block);
+ succ->bbHeapSsaPhiFunc = new (m_pCompiler) BasicBlock::HeapPhiArg(block->bbHeapSsaNumOut);
}
else
{
BasicBlock::HeapPhiArg* curArg = succ->bbHeapSsaPhiFunc;
+ unsigned ssaNum = block->bbHeapSsaNumOut;
bool found = false;
// This is a quadratic algorithm. We might need to consider some switch over to a hash table
// representation for the arguments of a phi node, to make this linear.
while (curArg != nullptr)
{
- if (curArg->m_predBB == block)
+ if (curArg->m_ssaNum == ssaNum)
{
found = true;
break;
}
if (!found)
{
- succ->bbHeapSsaPhiFunc = new (m_pCompiler) BasicBlock::HeapPhiArg(block, succ->bbHeapSsaPhiFunc);
+ succ->bbHeapSsaPhiFunc = new (m_pCompiler) BasicBlock::HeapPhiArg(ssaNum, succ->bbHeapSsaPhiFunc);
}
}
DBG_SSA_JITDUMP(" Added phi arg for Heap from BB%02u in BB%02u.\n", block->bbNum, succ->bbNum);
{
if (handlerStart->bbHeapSsaPhiFunc == BasicBlock::EmptyHeapPhiDef)
{
- handlerStart->bbHeapSsaPhiFunc = new (m_pCompiler) BasicBlock::HeapPhiArg(block);
+ handlerStart->bbHeapSsaPhiFunc =
+ new (m_pCompiler) BasicBlock::HeapPhiArg(block->bbHeapSsaNumOut);
}
else
{
-#ifdef DEBUG
- BasicBlock::HeapPhiArg* curArg = handlerStart->bbHeapSsaPhiFunc;
- while (curArg != nullptr)
- {
- assert(curArg->m_predBB != block);
- curArg = curArg->m_nextArg;
- }
-#endif // DEBUG
- handlerStart->bbHeapSsaPhiFunc =
- new (m_pCompiler) BasicBlock::HeapPhiArg(block, handlerStart->bbHeapSsaPhiFunc);
+ // This path has a potential to introduce redundant phi args, due to multiple
+ // preds of the same try-begin block having the same live-out heap def, and/or
+ // due to nested try-begins each having preds with the same live-out heap def.
+ // Avoid doing quadratic processing on handler phis, and instead live with the
+ // occasional redundancy.
+ handlerStart->bbHeapSsaPhiFunc = new (m_pCompiler)
+ BasicBlock::HeapPhiArg(block->bbHeapSsaNumOut, handlerStart->bbHeapSsaPhiFunc);
}
DBG_SSA_JITDUMP(" Added phi arg for Heap from BB%02u in BB%02u.\n", block->bbNum,
handlerStart->bbNum);
#endif
#endif
+// If the UNIX_X86_ABI is defined make sure that _TARGET_X86_ is also defined.
+#if defined(UNIX_X86_ABI)
+#if !defined(_TARGET_X86_)
+#error When UNIX_X86_ABI is defined you must define _TARGET_X86_ defined as well.
+#endif
+#endif
+
#if (defined(FEATURE_CORECLR) && defined(PLATFORM_UNIX))
#define FEATURE_VARARG 0
#else // !(defined(FEATURE_CORECLR) && defined(PLATFORM_UNIX))
</EmbeddedResource>
</ItemGroup>
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.Targets" />
+ <PropertyGroup Condition="'$(BuildOS)' == 'Windows_NT'">
+ <EnableDotnetAnalyzers Condition="'$(EnableDotnetAnalyzers)'==''">true</EnableDotnetAnalyzers>
+ <UseWin32Apis>true</UseWin32Apis>
+ <OSGroup>Windows_NT</OSGroup>
+ </PropertyGroup>
+ <Import Project="$(ToolsDir)\codeAnalysis.targets" />
+
+ <Import Project="$(ToolsDir)\Microsoft.CSharp.Targets" />
<PropertyGroup>
<StrongNameSig>Silverlight</StrongNameSig>
--- /dev/null
+// 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.
+
+internal partial class Interop
+{
+ internal partial class Errors
+ {
+ internal const int ERROR_SUCCESS = 0x0;
+ internal const int ERROR_INVALID_FUNCTION = 0x1;
+ internal const int ERROR_FILE_NOT_FOUND = 0x2;
+ internal const int ERROR_PATH_NOT_FOUND = 0x3;
+ internal const int ERROR_ACCESS_DENIED = 0x5;
+ internal const int ERROR_INVALID_HANDLE = 0x6;
+ internal const int ERROR_NOT_ENOUGH_MEMORY = 0x8;
+ internal const int ERROR_INVALID_DATA = 0xD;
+ internal const int ERROR_INVALID_DRIVE = 0xF;
+ internal const int ERROR_NO_MORE_FILES = 0x12;
+ internal const int ERROR_NOT_READY = 0x15;
+ internal const int ERROR_BAD_LENGTH = 0x18;
+ internal const int ERROR_SHARING_VIOLATION = 0x20;
+ internal const int ERROR_LOCK_VIOLATION = 0x21;
+ internal const int ERROR_HANDLE_EOF = 0x26;
+ internal const int ERROR_FILE_EXISTS = 0x50;
+ internal const int ERROR_INVALID_PARAMETER = 0x57;
+ internal const int ERROR_BROKEN_PIPE = 0x6D;
+ internal const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
+ internal const int ERROR_INVALID_NAME = 0x7B;
+ internal const int ERROR_NEGATIVE_SEEK = 0x83;
+ internal const int ERROR_DIR_NOT_EMPTY = 0x91;
+ internal const int ERROR_BAD_PATHNAME = 0xA1;
+ internal const int ERROR_LOCK_FAILED = 0xA7;
+ internal const int ERROR_BUSY = 0xAA;
+ internal const int ERROR_ALREADY_EXISTS = 0xB7;
+ internal const int ERROR_BAD_EXE_FORMAT = 0xC1;
+ internal const int ERROR_ENVVAR_NOT_FOUND = 0xCB;
+ internal const int ERROR_FILENAME_EXCED_RANGE = 0xCE;
+ internal const int ERROR_EXE_MACHINE_TYPE_MISMATCH = 0xD8;
+ internal const int ERROR_PIPE_BUSY = 0xE7;
+ internal const int ERROR_NO_DATA = 0xE8;
+ internal const int ERROR_PIPE_NOT_CONNECTED = 0xE9;
+ internal const int ERROR_MORE_DATA = 0xEA;
+ internal const int ERROR_NO_MORE_ITEMS = 0x103;
+ internal const int ERROR_PARTIAL_COPY = 0x12B;
+ internal const int ERROR_ARITHMETIC_OVERFLOW = 0x216;
+ internal const int ERROR_PIPE_CONNECTED = 0x217;
+ internal const int ERROR_PIPE_LISTENING = 0x218;
+ internal const int ERROR_OPERATION_ABORTED = 0x3E3;
+ internal const int ERROR_IO_PENDING = 0x3E5;
+ internal const int ERROR_NO_TOKEN = 0x3f0;
+ internal const int ERROR_DLL_INIT_FAILED = 0x45A;
+ internal const int ERROR_NOT_FOUND = 0x490;
+ internal const int ERROR_NON_ACCOUNT_SID = 0x4E9;
+ internal const int ERROR_NOT_ALL_ASSIGNED = 0x514;
+ internal const int ERROR_UNKNOWN_REVISION = 0x519;
+ internal const int ERROR_INVALID_OWNER = 0x51B;
+ internal const int ERROR_INVALID_PRIMARY_GROUP = 0x51C;
+ internal const int ERROR_NO_SUCH_PRIVILEGE = 0x521;
+ internal const int ERROR_PRIVILEGE_NOT_HELD = 0x522;
+ internal const int ERROR_INVALID_ACL = 0x538;
+ internal const int ERROR_INVALID_SECURITY_DESCR = 0x53A;
+ internal const int ERROR_INVALID_SID = 0x539;
+ internal const int ERROR_BAD_IMPERSONATION_LEVEL = 0x542;
+ internal const int ERROR_CANT_OPEN_ANONYMOUS = 0x543;
+ internal const int ERROR_NO_SECURITY_ON_OBJECT = 0x546;
+ internal const int ERROR_TRUSTED_RELATIONSHIP_FAILURE = 0x6FD;
+ internal const int ERROR_RESOURCE_LANG_NOT_FOUND = 0x717;
+ internal const int EFail = unchecked((int)0x80004005);
+ internal const int E_FILENOTFOUND = unchecked((int)0x80070002);
+ }
+}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.IO, SetLastError = true)]
- internal static unsafe extern bool CancelIoEx(SafeHandle handle, NativeOverlapped* lpOverlapped);
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
+ internal static extern unsafe bool CancelIoEx(SafeHandle handle, NativeOverlapped* lpOverlapped);
}
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.Handle, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(IntPtr handle);
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use CreateFile.
/// </summary>
- [DllImport(Libraries.CoreFile_L1, EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
+ [DllImport(Libraries.Kernel32, EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern SafeFileHandle CreateFilePrivate(
string lpFileName,
int dwDesiredAccess,
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
internal partial class IOReparseOptions
{
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
internal partial class FileTypes
{
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool FlushFileBuffers(SafeHandle hHandle);
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
private const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
private const int FORMAT_MESSAGE_FROM_HMODULE = 0x00000800;
private const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
- [DllImport(Libraries.Localization, CharSet = CharSet.Unicode, EntryPoint = "FormatMessageW", SetLastError = true, BestFitMapping = true)]
+ [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "FormatMessageW", SetLastError = true, BestFitMapping = true)]
private static extern int FormatMessage(
int dwFlags,
IntPtr lpSource,
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L2, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool GetFileInformationByHandleEx(SafeFileHandle hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, out FILE_STANDARD_INFO lpFileInformation, uint dwBufferSize);
internal partial struct FILE_STANDARD_INFO
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
internal extern static int GetFileType(SafeHandle hFile);
}
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use GetFullPathName or PathHelper.
/// </summary>
- [DllImport(Libraries.CoreFile_L1, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
unsafe internal static extern uint GetFullPathNameW(char* path, uint numBufferChars, char[] buffer, IntPtr mustBeZero);
}
}
partial class Interop
{
- partial class mincore
+ partial class Kernel32
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use GetFullPath/PathHelper.
/// </summary>
- [DllImport(Libraries.CoreFile_L1, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
internal static extern uint GetLongPathNameW(char[] lpszShortPath, char[] lpszLongPath, uint cchBuffer);
}
}
partial class Interop
{
- partial class mincore
+ partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)]
+ [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)]
internal static extern uint GetTempFileNameW(string tmpPath, string prefix, uint uniqueIdOrZero, [Out]StringBuilder tmpFileName);
}
}
partial class Interop
{
- partial class mincore
+ partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1_2, CharSet = CharSet.Unicode, BestFitMapping = false)]
+ [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, BestFitMapping = false)]
internal static extern uint GetTempPathW(int bufferLen, [Out]StringBuilder buffer);
}
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool LockFile(SafeFileHandle handle, int offsetLow, int offsetHigh, int countLow, int countHigh);
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool UnlockFile(SafeFileHandle handle, int offsetLow, int offsetHigh, int countLow, int countHigh);
}
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
- unsafe internal static extern int ReadFile(
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
+ internal static extern unsafe int ReadFile(
SafeHandle handle,
byte* bytes,
int numBytesToRead,
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
- unsafe internal static extern int ReadFile(
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
+ internal static extern unsafe int ReadFile(
SafeHandle handle,
byte* bytes,
int numBytesToRead,
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
[StructLayout(LayoutKind.Sequential)]
internal struct SECURITY_ATTRIBUTES
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); // WinBase.h
String lpFileName,
int dwDesiredAccess,
System.IO.FileShare dwShareMode,
- ref Interop.mincore.SECURITY_ATTRIBUTES securityAttrs,
+ ref Interop.Kernel32.SECURITY_ATTRIBUTES securityAttrs,
FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile)
if (!handle.IsInvalid)
{
- int fileType = Interop.mincore.GetFileType(handle);
- if (fileType != Interop.mincore.FileTypes.FILE_TYPE_DISK)
+ int fileType = Interop.Kernel32.GetFileType(handle);
+ if (fileType != Interop.Kernel32.FileTypes.FILE_TYPE_DISK)
{
handle.Dispose();
throw new NotSupportedException(SR.NotSupported_FileStreamOnNonFiles);
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
internal partial class SecurityOptions
{
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool SetEndOfFile(SafeFileHandle hFile);
}
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.ErrorHandling, SetLastError = false, EntryPoint = "SetErrorMode", ExactSpelling = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = false, EntryPoint = "SetErrorMode", ExactSpelling = true)]
internal static extern uint SetErrorMode(uint newMode);
}
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool SetFileInformationByHandle(SafeFileHandle hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, ref FILE_BASIC_INFO lpFileInformation, uint dwBufferSize);
// Default values indicate "no change". Use defaults so that we don't force callsites to be aware of the default values
- internal unsafe static bool SetFileTime(
+ internal static unsafe bool SetFileTime(
SafeFileHandle hFile,
long creationTime = -1,
long lastAccessTime = -1,
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool SetFilePointerEx(SafeFileHandle hFile, long liDistanceToMove, out long lpNewFilePointer, uint dwMoveMethod);
}
}
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
internal static SafeFileHandle UnsafeCreateFile(
string lpFileName,
int dwDesiredAccess,
FileShare dwShareMode,
- ref Interop.mincore.SECURITY_ATTRIBUTES securityAttrs,
+ ref Interop.Kernel32.SECURITY_ATTRIBUTES securityAttrs,
FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile)
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
- [DllImport(Libraries.String_L1)]
+ [DllImport(Libraries.Kernel32)]
internal static extern unsafe int WideCharToMultiByte(
uint CodePage, uint dwFlags,
char* lpWideCharStr, int cchWideChar,
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
// Note there are two different WriteFile prototypes - this is to use
// the type system to force you to not trip across a "feature" in
// struct in a callback (or an EndWrite method called by that callback),
// and pass in an address for the numBytesRead parameter.
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
- internal static unsafe extern int WriteFile(SafeHandle handle, byte* bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero);
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
+ internal static extern unsafe int WriteFile(SafeHandle handle, byte* bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero);
}
}
using System.Threading;
internal partial class Interop
{
- internal partial class mincore
+ internal partial class Kernel32
{
// Note there are two different WriteFile prototypes - this is to use
// the type system to force you to not trip across a "feature" in
// simultaneously: overlapped IO, free the memory for the overlapped
// struct in a callback (or an EndWrite method called by that callback),
// and pass in an address for the numBytesRead parameter.
- [DllImport(Libraries.CoreFile_L1, SetLastError = true)]
- internal static unsafe extern int WriteFile(SafeHandle handle, byte* bytes, int numBytesToWrite, IntPtr numBytesWritten_mustBeZero, NativeOverlapped* lpOverlapped);
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
+ internal static extern unsafe int WriteFile(SafeHandle handle, byte* bytes, int numBytesToWrite, IntPtr numBytesWritten_mustBeZero, NativeOverlapped* lpOverlapped);
}
}
+++ /dev/null
-// 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.
-
-internal partial class Interop
-{
- internal partial class mincore
- {
- internal partial class Errors
- {
- internal const int ERROR_SUCCESS = 0x0;
- internal const int ERROR_INVALID_FUNCTION = 0x1;
- internal const int ERROR_FILE_NOT_FOUND = 0x2;
- internal const int ERROR_PATH_NOT_FOUND = 0x3;
- internal const int ERROR_ACCESS_DENIED = 0x5;
- internal const int ERROR_INVALID_HANDLE = 0x6;
- internal const int ERROR_NOT_ENOUGH_MEMORY = 0x8;
- internal const int ERROR_INVALID_DATA = 0xD;
- internal const int ERROR_INVALID_DRIVE = 0xF;
- internal const int ERROR_NO_MORE_FILES = 0x12;
- internal const int ERROR_NOT_READY = 0x15;
- internal const int ERROR_BAD_LENGTH = 0x18;
- internal const int ERROR_SHARING_VIOLATION = 0x20;
- internal const int ERROR_LOCK_VIOLATION = 0x21;
- internal const int ERROR_HANDLE_EOF = 0x26;
- internal const int ERROR_FILE_EXISTS = 0x50;
- internal const int ERROR_INVALID_PARAMETER = 0x57;
- internal const int ERROR_BROKEN_PIPE = 0x6D;
- internal const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
- internal const int ERROR_INVALID_NAME = 0x7B;
- internal const int ERROR_NEGATIVE_SEEK = 0x83;
- internal const int ERROR_DIR_NOT_EMPTY = 0x91;
- internal const int ERROR_BAD_PATHNAME = 0xA1;
- internal const int ERROR_LOCK_FAILED = 0xA7;
- internal const int ERROR_BUSY = 0xAA;
- internal const int ERROR_ALREADY_EXISTS = 0xB7;
- internal const int ERROR_BAD_EXE_FORMAT = 0xC1;
- internal const int ERROR_ENVVAR_NOT_FOUND = 0xCB;
- internal const int ERROR_FILENAME_EXCED_RANGE = 0xCE;
- internal const int ERROR_EXE_MACHINE_TYPE_MISMATCH = 0xD8;
- internal const int ERROR_PIPE_BUSY = 0xE7;
- internal const int ERROR_NO_DATA = 0xE8;
- internal const int ERROR_PIPE_NOT_CONNECTED = 0xE9;
- internal const int ERROR_MORE_DATA = 0xEA;
- internal const int ERROR_NO_MORE_ITEMS = 0x103;
- internal const int ERROR_PARTIAL_COPY = 0x12B;
- internal const int ERROR_ARITHMETIC_OVERFLOW = 0x216;
- internal const int ERROR_PIPE_CONNECTED = 0x217;
- internal const int ERROR_PIPE_LISTENING = 0x218;
- internal const int ERROR_OPERATION_ABORTED = 0x3E3;
- internal const int ERROR_IO_PENDING = 0x3E5;
- internal const int ERROR_NO_TOKEN = 0x3f0;
- internal const int ERROR_DLL_INIT_FAILED = 0x45A;
- internal const int ERROR_NOT_FOUND = 0x490;
- internal const int ERROR_NON_ACCOUNT_SID = 0x4E9;
- internal const int ERROR_NOT_ALL_ASSIGNED = 0x514;
- internal const int ERROR_UNKNOWN_REVISION = 0x519;
- internal const int ERROR_INVALID_OWNER = 0x51B;
- internal const int ERROR_INVALID_PRIMARY_GROUP = 0x51C;
- internal const int ERROR_NO_SUCH_PRIVILEGE = 0x521;
- internal const int ERROR_PRIVILEGE_NOT_HELD = 0x522;
- internal const int ERROR_INVALID_ACL = 0x538;
- internal const int ERROR_INVALID_SECURITY_DESCR = 0x53A;
- internal const int ERROR_INVALID_SID = 0x539;
- internal const int ERROR_BAD_IMPERSONATION_LEVEL = 0x542;
- internal const int ERROR_CANT_OPEN_ANONYMOUS = 0x543;
- internal const int ERROR_NO_SECURITY_ON_OBJECT = 0x546;
- internal const int ERROR_TRUSTED_RELATIONSHIP_FAILURE = 0x6FD;
- internal const int ERROR_RESOURCE_LANG_NOT_FOUND = 0x717;
- internal const int EFail = unchecked((int)0x80004005);
- internal const int E_FILENOTFOUND = unchecked((int)0x80070002);
- }
- }
-}
+++ /dev/null
-// 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.InteropServices;
-
-internal partial class Interop
-{
- internal partial class mincore
- {
- //
- // Idn APIs
- //
-
- [DllImport("api-ms-win-core-localization-l1-2-0.dll", CharSet = CharSet.Unicode, SetLastError = true)]
- internal static extern int IdnToAscii(
- uint dwFlags,
- IntPtr lpUnicodeCharStr,
- int cchUnicodeChar,
- [System.Runtime.InteropServices.OutAttribute()]
- IntPtr lpASCIICharStr,
- int cchASCIIChar);
-
- [DllImport("api-ms-win-core-localization-l1-2-0.dll", CharSet = CharSet.Unicode, SetLastError = true)]
- internal static extern int IdnToUnicode(
- uint dwFlags,
- IntPtr lpASCIICharStr,
- int cchASCIIChar,
- [System.Runtime.InteropServices.OutAttribute()]
- IntPtr lpUnicodeCharStr,
- int cchUnicodeChar);
-
- internal const int IDN_ALLOW_UNASSIGNED = 0x1;
- internal const int IDN_USE_STD3_ASCII_RULES = 0x2;
- }
-}
+++ /dev/null
-// 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.InteropServices;
-using Microsoft.Win32.SafeHandles;
-
-internal static partial class Interop
-{
- internal static partial class mincore
- {
- [DllImport(Libraries.ThreadPool, SetLastError = true)]
- internal static unsafe extern SafeThreadPoolIOHandle CreateThreadpoolIo(SafeHandle fl, [MarshalAs(UnmanagedType.FunctionPtr)] NativeIoCompletionCallback pfnio, IntPtr context, IntPtr pcbe);
-
- [DllImport(Libraries.ThreadPool)]
- internal static unsafe extern void CloseThreadpoolIo(IntPtr pio);
-
- [DllImport(Libraries.ThreadPool)]
- internal static unsafe extern void StartThreadpoolIo(SafeThreadPoolIOHandle pio);
-
- [DllImport(Libraries.ThreadPool)]
- internal static unsafe extern void CancelThreadpoolIo(SafeThreadPoolIOHandle pio);
- }
-
- internal delegate void NativeIoCompletionCallback(IntPtr instance, IntPtr context, IntPtr overlapped, uint ioResult, UIntPtr numberOfBytesTransferred, IntPtr io);
-}
override protected bool ReleaseHandle()
{
- return Interop.mincore.CloseHandle(handle);
+ return Interop.Kernel32.CloseHandle(handle);
}
}
}
private SafeFileHandle OpenHandle(FileMode mode, FileShare share, FileOptions options)
{
- Interop.mincore.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
+ Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
int fAccess =
((_access & FileAccess.Read) == FileAccess.Read ? GENERIC_READ : 0) |
// For mitigating local elevation of privilege attack through named pipes
// make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
// named pipe server can't impersonate a high privileged client security context
- flagsAndAttributes |= (Interop.mincore.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.mincore.SecurityOptions.SECURITY_ANONYMOUS);
+ flagsAndAttributes |= (Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.Kernel32.SecurityOptions.SECURITY_ANONYMOUS);
// Don't pop up a dialog for reading from an empty floppy drive
- uint oldMode = Interop.mincore.SetErrorMode(Interop.mincore.SEM_FAILCRITICALERRORS);
+ uint oldMode = Interop.Kernel32.SetErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS);
try
{
- SafeFileHandle fileHandle = Interop.mincore.SafeCreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
+ SafeFileHandle fileHandle = Interop.Kernel32.SafeCreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
fileHandle.IsAsync = _useAsyncIO;
if (fileHandle.IsInvalid)
// probably be consistent w/ every other directory.
int errorCode = Marshal.GetLastWin32Error();
- if (errorCode == Interop.mincore.Errors.ERROR_PATH_NOT_FOUND && _path.Equals(Directory.InternalGetDirectoryRoot(_path)))
- errorCode = Interop.mincore.Errors.ERROR_ACCESS_DENIED;
+ if (errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND && _path.Equals(Directory.InternalGetDirectoryRoot(_path)))
+ errorCode = Interop.Errors.ERROR_ACCESS_DENIED;
throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
}
finally
{
- Interop.mincore.SetErrorMode(oldMode);
+ Interop.Kernel32.SetErrorMode(oldMode);
}
}
// constructors that take a String. Everyone else can call
// CreateFile themselves then use the constructor that takes an
// IntPtr. Disallows "con:", "com1:", "lpt1:", etc.
- int fileType = Interop.mincore.GetFileType(_fileHandle);
- if (fileType != Interop.mincore.FileTypes.FILE_TYPE_DISK)
+ int fileType = Interop.Kernel32.GetFileType(_fileHandle);
+ if (fileType != Interop.Kernel32.FileTypes.FILE_TYPE_DISK)
{
_fileHandle.Dispose();
throw new NotSupportedException(SR.NotSupported_FileStreamOnNonFiles);
private void InitFromHandle(SafeFileHandle handle)
{
- int handleType = Interop.mincore.GetFileType(_fileHandle);
- Debug.Assert(handleType == Interop.mincore.FileTypes.FILE_TYPE_DISK || handleType == Interop.mincore.FileTypes.FILE_TYPE_PIPE || handleType == Interop.mincore.FileTypes.FILE_TYPE_CHAR, "FileStream was passed an unknown file type!");
+ int handleType = Interop.Kernel32.GetFileType(_fileHandle);
+ Debug.Assert(handleType == Interop.Kernel32.FileTypes.FILE_TYPE_DISK || handleType == Interop.Kernel32.FileTypes.FILE_TYPE_PIPE || handleType == Interop.Kernel32.FileTypes.FILE_TYPE_CHAR, "FileStream was passed an unknown file type!");
- _canSeek = handleType == Interop.mincore.FileTypes.FILE_TYPE_DISK;
- _isPipe = handleType == Interop.mincore.FileTypes.FILE_TYPE_PIPE;
+ _canSeek = handleType == Interop.Kernel32.FileTypes.FILE_TYPE_DISK;
+ _isPipe = handleType == Interop.Kernel32.FileTypes.FILE_TYPE_PIPE;
// This is necessary for async IO using IO Completion ports via our
// managed Threadpool API's. This calls the OS's
}
else if (!_useAsyncIO)
{
- if (handleType != Interop.mincore.FileTypes.FILE_TYPE_PIPE)
+ if (handleType != Interop.Kernel32.FileTypes.FILE_TYPE_PIPE)
VerifyHandleIsSync();
}
return handle.IsAsync.HasValue ? handle.IsAsync.Value : false;
}
- private unsafe static Interop.mincore.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
+ private unsafe static Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
{
- Interop.mincore.SECURITY_ATTRIBUTES secAttrs = default(Interop.mincore.SECURITY_ATTRIBUTES);
+ Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default(Interop.Kernel32.SECURITY_ATTRIBUTES);
if ((share & FileShare.Inheritable) != 0)
{
- secAttrs = new Interop.mincore.SECURITY_ATTRIBUTES();
- secAttrs.nLength = (uint)sizeof(Interop.mincore.SECURITY_ATTRIBUTES);
+ secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES();
+ secAttrs.nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES);
secAttrs.bInheritHandle = Interop.BOOL.TRUE;
}
// cause an app to block incorrectly, introducing a deadlock (depending
// on whether a write will wake up an already-blocked thread or this
// Win32FileStream's thread).
- Debug.Assert(Interop.mincore.GetFileType(_fileHandle) != Interop.mincore.FileTypes.FILE_TYPE_PIPE);
+ Debug.Assert(Interop.Kernel32.GetFileType(_fileHandle) != Interop.Kernel32.FileTypes.FILE_TYPE_PIPE);
byte* bytes = stackalloc byte[1];
int numBytesReadWritten;
// accidentally read synchronously from an async pipe.
if ((_access & FileAccess.Read) != 0) // don't use the virtual CanRead or CanWrite, as this may be used in the ctor
{
- r = Interop.mincore.ReadFile(_fileHandle, bytes, 0, out numBytesReadWritten, IntPtr.Zero);
+ r = Interop.Kernel32.ReadFile(_fileHandle, bytes, 0, out numBytesReadWritten, IntPtr.Zero);
}
else if ((_access & FileAccess.Write) != 0) // don't use the virtual CanRead or CanWrite, as this may be used in the ctor
{
- r = Interop.mincore.WriteFile(_fileHandle, bytes, 0, out numBytesReadWritten, IntPtr.Zero);
+ r = Interop.Kernel32.WriteFile(_fileHandle, bytes, 0, out numBytesReadWritten, IntPtr.Zero);
}
if (r == 0)
private long GetLengthInternal()
{
- Interop.mincore.FILE_STANDARD_INFO info = new Interop.mincore.FILE_STANDARD_INFO();
+ Interop.Kernel32.FILE_STANDARD_INFO info = new Interop.Kernel32.FILE_STANDARD_INFO();
- if (!Interop.mincore.GetFileInformationByHandleEx(_fileHandle, Interop.mincore.FILE_INFO_BY_HANDLE_CLASS.FileStandardInfo, out info, (uint)Marshal.SizeOf<Interop.mincore.FILE_STANDARD_INFO>()))
+ if (!Interop.Kernel32.GetFileInformationByHandleEx(_fileHandle, Interop.Kernel32.FILE_INFO_BY_HANDLE_CLASS.FileStandardInfo, out info, (uint)Marshal.SizeOf<Interop.Kernel32.FILE_STANDARD_INFO>()))
throw Win32Marshal.GetExceptionForLastWin32Error();
long len = info.EndOfFile;
// If we're writing near the end of the file, we must include our
private void FlushOSBuffer()
{
- if (!Interop.mincore.FlushFileBuffers(_fileHandle))
+ if (!Interop.Kernel32.FlushFileBuffers(_fileHandle))
{
throw Win32Marshal.GetExceptionForLastWin32Error();
}
VerifyOSHandlePosition();
if (_filePosition != value)
SeekCore(value, SeekOrigin.Begin);
- if (!Interop.mincore.SetEndOfFile(_fileHandle))
+ if (!Interop.Kernel32.SetEndOfFile(_fileHandle))
{
int errorCode = Marshal.GetLastWin32Error();
- if (errorCode == Interop.mincore.Errors.ERROR_INVALID_PARAMETER)
+ if (errorCode == Interop.Errors.ERROR_INVALID_PARAMETER)
throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_FileLengthTooBig);
throw Win32Marshal.GetExceptionForWin32Error(errorCode);
}
Debug.Assert(origin >= SeekOrigin.Begin && origin <= SeekOrigin.End, "origin>=SeekOrigin.Begin && origin<=SeekOrigin.End");
long ret = 0;
- if (!Interop.mincore.SetFilePointerEx(_fileHandle, offset, out ret, (uint)origin))
+ if (!Interop.Kernel32.SetFilePointerEx(_fileHandle, offset, out ret, (uint)origin))
{
int errorCode = GetLastWin32ErrorAndDisposeHandleIfInvalid();
throw Win32Marshal.GetExceptionForWin32Error(errorCode);
fixed (byte* p = bytes)
{
if (_useAsyncIO)
- r = Interop.mincore.ReadFile(handle, p + offset, count, IntPtr.Zero, overlapped);
+ r = Interop.Kernel32.ReadFile(handle, p + offset, count, IntPtr.Zero, overlapped);
else
- r = Interop.mincore.ReadFile(handle, p + offset, count, out numBytesRead, IntPtr.Zero);
+ r = Interop.Kernel32.ReadFile(handle, p + offset, count, out numBytesRead, IntPtr.Zero);
}
if (r == 0)
fixed (byte* p = bytes)
{
if (_useAsyncIO)
- r = Interop.mincore.WriteFile(handle, p + offset, count, IntPtr.Zero, overlapped);
+ r = Interop.Kernel32.WriteFile(handle, p + offset, count, IntPtr.Zero, overlapped);
else
- r = Interop.mincore.WriteFile(handle, p + offset, count, out numBytesWritten, IntPtr.Zero);
+ r = Interop.Kernel32.WriteFile(handle, p + offset, count, out numBytesWritten, IntPtr.Zero);
}
if (r == 0)
// Note that _parent.Dispose doesn't throw so we don't need to special case.
// SetHandleAsInvalid only sets _closed field to true (without
// actually closing handle) so we don't need to call that as well.
- if (errorCode == Interop.mincore.Errors.ERROR_INVALID_HANDLE)
+ if (errorCode == Interop.Errors.ERROR_INVALID_HANDLE)
{
_fileHandle.Dispose();
{
// Try to cancel the I/O. We ignore the return value, as cancellation is opportunistic and we
// don't want to fail the operation because we couldn't cancel it.
- Interop.mincore.CancelIoEx(innerAwaitable._fileStream._fileHandle, innerAwaitable._nativeOverlapped);
+ Interop.Kernel32.CancelIoEx(innerAwaitable._fileStream._fileHandle, innerAwaitable._nativeOverlapped);
}
}
}
case ERROR_HANDLE_EOF: // logically success with 0 bytes read (read at end of file)
Debug.Assert(readAwaitable._numBytes == 0, $"Expected 0 bytes read, got {readAwaitable._numBytes}");
break;
- case Interop.mincore.Errors.ERROR_OPERATION_ABORTED: // canceled
+ case Interop.Errors.ERROR_OPERATION_ABORTED: // canceled
throw new OperationCanceledException(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true));
default: // error
throw Win32Marshal.GetExceptionForWin32Error((int)readAwaitable._errorCode);
int lengthLow = unchecked((int)(length));
int lengthHigh = unchecked((int)(length >> 32));
- if (!Interop.mincore.LockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh))
+ if (!Interop.Kernel32.LockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh))
{
throw Win32Marshal.GetExceptionForLastWin32Error();
}
int lengthLow = unchecked((int)(length));
int lengthHigh = unchecked((int)(length >> 32));
- if (!Interop.mincore.UnlockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh))
+ if (!Interop.Kernel32.UnlockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh))
{
throw Win32Marshal.GetExceptionForLastWin32Error();
}
if (result == ResultError)
{
int errorCode = unchecked((int)(packedResult & uint.MaxValue));
- if (errorCode == Interop.mincore.Errors.ERROR_OPERATION_ABORTED)
+ if (errorCode == Interop.Errors.ERROR_OPERATION_ABORTED)
{
TrySetCanceled(_cancellationToken.IsCancellationRequested ? _cancellationToken : new CancellationToken(true));
}
// If the handle is still valid, attempt to cancel the IO
if (!completionSource._stream._fileHandle.IsInvalid &&
- !Interop.mincore.CancelIoEx(completionSource._stream._fileHandle, completionSource._overlapped))
+ !Interop.Kernel32.CancelIoEx(completionSource._stream._fileHandle, completionSource._overlapped))
{
int errorCode = Marshal.GetLastWin32Error();
// ERROR_NOT_FOUND is returned if CancelIoEx cannot find the request to cancel.
// This probably means that the IO operation has completed.
- if (errorCode != Interop.mincore.Errors.ERROR_NOT_FOUND)
+ if (errorCode != Interop.Errors.ERROR_NOT_FOUND)
{
throw Win32Marshal.GetExceptionForWin32Error(errorCode);
}
public static string GetTempPath()
{
StringBuilder sb = StringBuilderCache.Acquire(MaxPath);
- uint r = Interop.mincore.GetTempPathW(MaxPath, sb);
+ uint r = Interop.Kernel32.GetTempPathW(MaxPath, sb);
if (r == 0)
throw Win32Marshal.GetExceptionForLastWin32Error();
return GetFullPath(StringBuilderCache.GetStringAndRelease(sb));
string path = GetTempPath();
StringBuilder sb = StringBuilderCache.Acquire(MaxPath);
- uint r = Interop.mincore.GetTempFileNameW(path, "tmp", 0, sb);
+ uint r = Interop.Kernel32.GetTempFileNameW(path, "tmp", 0, sb);
if (r == 0)
throw Win32Marshal.GetExceptionForLastWin32Error();
return StringBuilderCache.GetStringAndRelease(sb);
fixed (char* pathStart = path)
{
uint result = 0;
- while ((result = Interop.mincore.GetFullPathNameW(pathStart + startIndex, (uint)fullPath.Capacity, fullPath.UnderlyingArray, IntPtr.Zero)) > fullPath.Capacity)
+ while ((result = Interop.Kernel32.GetFullPathNameW(pathStart + startIndex, (uint)fullPath.Capacity, fullPath.UnderlyingArray, IntPtr.Zero)) > fullPath.Capacity)
{
// Reported size is greater than the buffer size. Increase the capacity.
fullPath.EnsureCapacity(checked((int)result));
// Failure, get the error and throw
int errorCode = Marshal.GetLastWin32Error();
if (errorCode == 0)
- errorCode = Interop.mincore.Errors.ERROR_BAD_PATHNAME;
+ errorCode = Interop.Errors.ERROR_BAD_PATHNAME;
throw Win32Marshal.GetExceptionForWin32Error(errorCode, path);
}
while (!success)
{
- uint result = Interop.mincore.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity);
+ uint result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity);
// Replace any temporary null we added
if (inputBuffer[foundIndex] == '\0') inputBuffer[foundIndex] = '\\';
{
// Look to see if we couldn't find the file
int error = Marshal.GetLastWin32Error();
- if (error != Interop.mincore.Errors.ERROR_FILE_NOT_FOUND && error != Interop.mincore.Errors.ERROR_PATH_NOT_FOUND)
+ if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND)
{
// Some other failure, give up
break;
{
// Not enough space. The result count for this API does not include the null terminator.
outputBuffer.EnsureCapacity(checked((int)result));
- result = Interop.mincore.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity);
+ result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity);
}
else
{
{
switch (errorCode)
{
- case Interop.mincore.Errors.ERROR_FILE_NOT_FOUND:
+ case Interop.Errors.ERROR_FILE_NOT_FOUND:
if (path.Length == 0)
return new FileNotFoundException(SR.IO_FileNotFound);
else
return new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, path), path);
- case Interop.mincore.Errors.ERROR_PATH_NOT_FOUND:
+ case Interop.Errors.ERROR_PATH_NOT_FOUND:
if (path.Length == 0)
return new DirectoryNotFoundException(SR.IO_PathNotFound_NoPathName);
else
return new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, path));
- case Interop.mincore.Errors.ERROR_ACCESS_DENIED:
+ case Interop.Errors.ERROR_ACCESS_DENIED:
if (path.Length == 0)
return new UnauthorizedAccessException(SR.UnauthorizedAccess_IODenied_NoPathName);
else
return new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, path));
- case Interop.mincore.Errors.ERROR_ALREADY_EXISTS:
+ case Interop.Errors.ERROR_ALREADY_EXISTS:
if (path.Length == 0)
goto default;
return new IOException(SR.Format(SR.IO_AlreadyExists_Name, path), MakeHRFromErrorCode(errorCode));
- case Interop.mincore.Errors.ERROR_FILENAME_EXCED_RANGE:
+ case Interop.Errors.ERROR_FILENAME_EXCED_RANGE:
return new PathTooLongException(SR.IO_PathTooLong);
- case Interop.mincore.Errors.ERROR_INVALID_PARAMETER:
+ case Interop.Errors.ERROR_INVALID_PARAMETER:
return new IOException(GetMessage(errorCode), MakeHRFromErrorCode(errorCode));
- case Interop.mincore.Errors.ERROR_SHARING_VIOLATION:
+ case Interop.Errors.ERROR_SHARING_VIOLATION:
if (path.Length == 0)
return new IOException(SR.IO_SharingViolation_NoFileName, MakeHRFromErrorCode(errorCode));
else
return new IOException(SR.Format(SR.IO_SharingViolation_File, path), MakeHRFromErrorCode(errorCode));
- case Interop.mincore.Errors.ERROR_FILE_EXISTS:
+ case Interop.Errors.ERROR_FILE_EXISTS:
if (path.Length == 0)
goto default;
return new IOException(SR.Format(SR.IO_FileExists_Name, path), MakeHRFromErrorCode(errorCode));
- case Interop.mincore.Errors.ERROR_OPERATION_ABORTED:
+ case Interop.Errors.ERROR_OPERATION_ABORTED:
return new OperationCanceledException();
default:
/// </summary>
internal static string GetMessage(int errorCode)
{
- return Interop.mincore.GetMessage(errorCode);
+ return Interop.Kernel32.GetMessage(errorCode);
}
}
}
else
{
uint defaultChar = '?';
- int resultByteLength = 1 + Interop.mincore.WideCharToMultiByte(
- Interop.mincore.CP_ACP, Interop.mincore.WC_NO_BEST_FIT_CHARS, (char*)bufferPtr, length, null, 0, (IntPtr)(&defaultChar), IntPtr.Zero);
+ int resultByteLength = 1 + Interop.Kernel32.WideCharToMultiByte(
+ Interop.Kernel32.CP_ACP, Interop.Kernel32.WC_NO_BEST_FIT_CHARS, (char*)bufferPtr, length, null, 0, (IntPtr)(&defaultChar), IntPtr.Zero);
ptr = globalAlloc ? Marshal.AllocHGlobal(resultByteLength) : Marshal.AllocCoTaskMem(resultByteLength);
- Interop.mincore.WideCharToMultiByte(
- Interop.mincore.CP_ACP, Interop.mincore.WC_NO_BEST_FIT_CHARS, (char*)bufferPtr, length, (byte*)ptr, resultByteLength - 1, (IntPtr)(&defaultChar), IntPtr.Zero);
+ Interop.Kernel32.WideCharToMultiByte(
+ Interop.Kernel32.CP_ACP, Interop.Kernel32.WC_NO_BEST_FIT_CHARS, (char*)bufferPtr, length, (byte*)ptr, resultByteLength - 1, (IntPtr)(&defaultChar), IntPtr.Zero);
*(resultByteLength - 1 + (byte*)ptr) = 0;
}
result = ptr;
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
<OutputType>Library</OutputType>
<ExcludeMscorlibFacade>true</ExcludeMscorlibFacade>
+ <HighEntropyVA>true</HighEntropyVA>
<!-- This prevents the default MsBuild targets from referencing System.Core.dll -->
<AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
<Member Name="GetHashCode(T)" />
<Member MemberType="Property" Name="Default" />
</Type>
+ <Type Name="System.Collections.Generic.EnumEqualityComparer<T>">
+ <Member Name="#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)" />
+ </Type>
<Type Name="System.Collections.Generic.ICollection<T>">
<Member Name="Add(T)" />
<Member Name="Clear" />
<Member Name="Trim" />
<Member Name="Trim(System.Char[])" />
<Member Name="TrimEnd(System.Char[])" />
+ <Member Name="TrimEnd" />
<Member Name="TrimStart(System.Char[])" />
+ <Member Name="TrimStart" />
<Member MemberType="Property" Name="Chars(System.Int32)" />
<Member MemberType="Property" Name="Length" />
<Member Status="ImplRoot" Name="System.Collections.IEnumerable.GetEnumerator" />
<Member MemberType="Field" Name="Never" />
<Member MemberType="Field" Name="Advanced" />
</Type>
+ <Type Status="ImplRoot" Name="System.Runtime.CompilerServices.Unsafe">
+ <Member Status="ImplRoot" Name="AsPointer<T>(T@)" />
+ </Type>
</Assembly>
</ThinModel>
<ItemGroup Condition="'$(TargetsUnix)' != 'true'">
<WindowsInteropSources Include="$(CoreFxSourcesRoot)\System\HResults.cs" />
<WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\Interop.BOOL.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\Interop.Errors.cs" />
<WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\Interop.Libraries.cs" />
<WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\BCrypt\Interop.BCryptGenRandom.cs" />
<WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\BCrypt\Interop.NTSTATUS.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.CancelIoEx.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.CloseHandle.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.CreateFile.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.Errors.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.FileTypes.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.FileOperations.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.FlushFileBuffers.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.FormatMessage.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.GetFileInformationByHandleEx.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.GetFileType_SafeHandle.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.GetFullPathNameW.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.GetLongPathNameW.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.GetTempFileNameW.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.GetTempPathW.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.LockFile.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.ReadFile_SafeHandle_IntPtr.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.ReadFile_SafeHandle_NativeOverlapped.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.SafeCreateFile.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.SECURITY_ATTRIBUTES.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.SecurityOptions.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.SetEndOfFile.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.SetErrorMode.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.SetFileInformationByHandle.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.SetFilePointerEx.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.UnsafeCreateFile.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.WriteFile_SafeHandle_IntPtr.cs" />
- <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.CancelIoEx.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.CloseHandle.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.CreateFile.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.FileTypes.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.FileOperations.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.FlushFileBuffers.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.FormatMessage.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.GetFileInformationByHandleEx.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.GetFileType_SafeHandle.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.GetFullPathNameW.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.GetLongPathNameW.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.GetTempFileNameW.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.GetTempPathW.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.LockFile.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.SafeCreateFile.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.SECURITY_ATTRIBUTES.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.SecurityOptions.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.SetEndOfFile.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.SetErrorMode.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.SetFileInformationByHandle.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.SetFilePointerEx.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.UnsafeCreateFile.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.WriteFile_SafeHandle_IntPtr.cs" />
+ <WindowsInteropSources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" />
</ItemGroup>
<ItemGroup>
<!-- Interop sources -->
<SecuritySources Include="$(CoreFxSourcesRoot)\Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs" />
<SecuritySources Include="$(CoreFxSourcesRoot)\Interop\Windows\NtDll\Interop.ZeroMemory.cs" />
- <SecuritySources Include="$(CoreFxSourcesRoot)\Interop\Windows\mincore\Interop.WideCharToMultiByte.cs" />
+ <SecuritySources Include="$(CoreFxSourcesRoot)\Interop\Windows\kernel32\Interop.WideCharToMultiByte.cs" />
<SecuritySources Include="$(CoreFxSourcesRoot)\Interop\Windows\oleaut32\Interop.SysAllocStringLen.cs" />
<SecuritySources Include="$(CoreFxSourcesRoot)\Interop\Windows\oleaut32\Interop.SysStringLen.cs" />
</ItemGroup>
public System.String Trim() { throw null; }
public System.String Trim(params char[] trimChars) { throw null; }
public System.String TrimEnd(params char[] trimChars) { throw null; }
+ public System.String TrimEnd() { throw null; }
public System.String TrimStart(params char[] trimChars) { throw null; }
+ public System.String TrimStart() { throw null; }
}
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public abstract partial class StringComparer : System.Collections.Generic.IComparer<string>, System.Collections.Generic.IEqualityComparer<string>, System.Collections.IComparer, System.Collections.IEqualityComparer
public ByReference(ref T value)
{
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- unsafe { _value = (IntPtr)Unsafe.AsPointer(ref value); }
+ // Implemented as a JIT intrinsic - This default implementation is for
+ // completeness and to provide a concrete error if called via reflection
+ // or if intrinsic is missed.
+ throw new System.PlatformNotSupportedException();
}
public ref T Value
{
get
{
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- unsafe { return ref Unsafe.As<IntPtr, T>(ref *(IntPtr*)_value); }
+ // Implemented as a JIT intrinsic - This default implementation is for
+ // completeness and to provide a concrete error if called via reflection
+ // or if the intrinsic is missed.
+ throw new System.PlatformNotSupportedException();
}
}
}
internal static class UnsafeNativeMethods
{
- [DllImport("api-ms-win-core-winrt-error-l1-1-1.dll", PreserveSig = false)]
+ [DllImport("api-ms-win-core-winrt-error-l1-1-0.dll", PreserveSig = false)]
[SuppressUnmanagedCodeSecurity]
internal static extern IRestrictedErrorInfo GetRestrictedErrorInfo();
}
return TrimHelper(trimChars,TrimHead);
}
-
-
+
+ // Removes a set of characters from the beginning of this string.
+ public String TrimStart() => TrimHelper(TrimHead);
+
+
// Removes a set of characters from the end of this string.
public String TrimEnd(params char[] trimChars) {
if (null==trimChars || trimChars.Length == 0) {
}
return TrimHelper(trimChars,TrimTail);
}
+
+ // Removes a set of characters from the end of this string.
+ public String TrimEnd()=> TrimHelper(TrimTail);
+
// Trims the whitespace from both ends of the string. Whitespace is defined by
// Char.IsWhiteSpace.
/// <param name="token2">The second <see cref="T:System.Threading.CancellationToken">CancellationToken</see> to observe.</param>
/// <returns>A <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> that is linked
/// to the source tokens.</returns>
- public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2)
- {
- return token1.CanBeCanceled || token2.CanBeCanceled ?
- new LinkedCancellationTokenSource(token1, token2) :
- new CancellationTokenSource();
- }
+ public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2) =>
+ !token1.CanBeCanceled ? CreateLinkedTokenSource(token2) :
+ token2.CanBeCanceled ? new Linked2CancellationTokenSource(token1, token2) :
+ (CancellationTokenSource)new Linked1CancellationTokenSource(token1);
+
+ /// <summary>
+ /// Creates a <see cref="CancellationTokenSource"/> that will be in the canceled state
+ /// when any of the source tokens are in the canceled state.
+ /// </summary>
+ /// <param name="token">The first <see cref="T:System.Threading.CancellationToken">CancellationToken</see> to observe.</param>
+ /// <returns>A <see cref="CancellationTokenSource"/> that is linked to the source tokens.</returns>
+ internal static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token) =>
+ token.CanBeCanceled ? new Linked1CancellationTokenSource(token) : new CancellationTokenSource();
/// <summary>
/// Creates a <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> that will be in the canceled state
if (tokens == null)
throw new ArgumentNullException(nameof(tokens));
- if (tokens.Length == 0)
- throw new ArgumentException(Environment.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty"));
-
- // a defensive copy is not required as the array has value-items that have only a single IntPtr field,
- // hence each item cannot be null itself, and reads of the payloads cannot be torn.
- Contract.EndContractBlock();
-
- return new LinkedCancellationTokenSource(tokens);
+ switch (tokens.Length)
+ {
+ case 0:
+ throw new ArgumentException(Environment.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty"));
+ case 1:
+ return CreateLinkedTokenSource(tokens[0]);
+ case 2:
+ return CreateLinkedTokenSource(tokens[0], tokens[1]);
+ default:
+ // a defensive copy is not required as the array has value-items that have only a single reference field,
+ // hence each item cannot be null itself, and reads of the payloads cannot be torn.
+ return new LinkedNCancellationTokenSource(tokens);
+ }
}
}
}
- private sealed class LinkedCancellationTokenSource : CancellationTokenSource
+ private sealed class Linked1CancellationTokenSource : CancellationTokenSource
{
- private static readonly Action<object> s_linkedTokenCancelDelegate =
- s => ((CancellationTokenSource)s).NotifyCancellation(throwOnFirstException: false); // skip ThrowIfDisposed() check in Cancel()
- private CancellationTokenRegistration[] m_linkingRegistrations;
+ private readonly CancellationTokenRegistration _reg1;
- internal LinkedCancellationTokenSource(CancellationToken token1, CancellationToken token2)
+ internal Linked1CancellationTokenSource(CancellationToken token1)
{
- bool token2CanBeCanceled = token2.CanBeCanceled;
+ _reg1 = token1.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this);
+ }
- if (token1.CanBeCanceled)
- {
- m_linkingRegistrations = new CancellationTokenRegistration[token2CanBeCanceled ? 2 : 1]; // there will be at least 1 and at most 2 linkings
- m_linkingRegistrations[0] = token1.InternalRegisterWithoutEC(s_linkedTokenCancelDelegate, this);
- }
+ protected override void Dispose(bool disposing)
+ {
+ if (!disposing || m_disposed) return;
+ _reg1.Dispose();
+ base.Dispose(disposing);
+ }
+ }
- if (token2CanBeCanceled)
- {
- int index = 1;
- if (m_linkingRegistrations == null)
- {
- m_linkingRegistrations = new CancellationTokenRegistration[1]; // this will be the only linking
- index = 0;
- }
- m_linkingRegistrations[index] = token2.InternalRegisterWithoutEC(s_linkedTokenCancelDelegate, this);
- }
+ private sealed class Linked2CancellationTokenSource : CancellationTokenSource
+ {
+ private readonly CancellationTokenRegistration _reg1;
+ private readonly CancellationTokenRegistration _reg2;
+
+ internal Linked2CancellationTokenSource(CancellationToken token1, CancellationToken token2)
+ {
+ _reg1 = token1.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this);
+ _reg2 = token2.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this);
}
- internal LinkedCancellationTokenSource(params CancellationToken[] tokens)
+ protected override void Dispose(bool disposing)
+ {
+ if (!disposing || m_disposed) return;
+ _reg1.Dispose();
+ _reg2.Dispose();
+ base.Dispose(disposing);
+ }
+ }
+
+ private sealed class LinkedNCancellationTokenSource : CancellationTokenSource
+ {
+ internal static readonly Action<object> s_linkedTokenCancelDelegate =
+ s => ((CancellationTokenSource)s).NotifyCancellation(throwOnFirstException: false); // skip ThrowIfDisposed() check in Cancel()
+ private CancellationTokenRegistration[] m_linkingRegistrations;
+
+ internal LinkedNCancellationTokenSource(params CancellationToken[] tokens)
{
m_linkingRegistrations = new CancellationTokenRegistration[tokens.Length];
base.Dispose(disposing);
}
-
}
}
private static StackGuard t_stackGuard; // The stack guard object for this thread
internal static int s_taskIdCounter; //static counter used to generate unique task IDs
- private readonly static TaskFactory s_factory = new TaskFactory();
private volatile int m_taskId; // this task's unique ID. initialized only if it is ever requested
/// of <see cref="System.Threading.Tasks.TaskFactory"/>, as would result from using
/// the default constructor on TaskFactory.
/// </remarks>
- public static TaskFactory Factory { get { return s_factory; } }
-
- /// <summary>A task that's already been completed successfully.</summary>
- private static Task s_completedTask;
+ public static TaskFactory Factory { get; } = new TaskFactory();
/// <summary>Gets a task that's already been completed successfully.</summary>
- /// <remarks>May not always return the same instance.</remarks>
- public static Task CompletedTask
- {
- get
- {
- var completedTask = s_completedTask;
- if (completedTask == null)
- s_completedTask = completedTask = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); // benign initialization race condition
- return completedTask;
- }
- }
+ public static Task CompletedTask { get; } = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
/// <summary>
/// Provides an event that can be used to wait for completion.
typedef BOOL (PALAPI *PHARDWARE_EXCEPTION_HANDLER)(PAL_SEHException* ex);
typedef BOOL (PALAPI *PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION)(PCONTEXT contextRecord, PEXCEPTION_RECORD exceptionRecord);
-typedef VOID (PALAPI *PTERMINATION_REQUEST_HANDLER)();
-typedef DWORD (PALAPI *PGET_GCMARKER_EXCEPTION_CODE)(LPVOID ip);
+typedef VOID (*PTERMINATION_REQUEST_HANDLER)();
+typedef DWORD (*PGET_GCMARKER_EXCEPTION_CODE)(LPVOID ip);
PALIMPORT
VOID
set(VM_SOURCES_WKS_ARCH
${ARCH_SOURCES_DIR}/jitinterfacex86.cpp
${ARCH_SOURCES_DIR}/profiler.cpp
+ exceptionhandling.cpp
+ gcinfodecoder.cpp
)
elseif(CLR_CMAKE_TARGET_ARCH_ARM)
set(VM_SOURCES_DAC_AND_WKS_ARCH
{
LIMITED_METHOD_CONTRACT;
+ // SPAN-TODO: GC reporting - https://github.com/dotnet/coreclr/issues/8517
+
_ASSERTE(IsStructPassedInRegs());
-
+
TADDR genRegDest = dac_cast<TADDR>(GetStructGenRegDestinationAddress());
INDEBUG(int remainingBytes = fieldBytes;)
.macro DynamicHelper frameFlags, suffix
-__FakePrologName="DelayLoad_Helper\suffix\()_FakeProlog"
-
NESTED_ENTRY DelayLoad_Helper\suffix\()_FakeProlog, _TEXT, NoHandler
// Match what the lazy thunk has pushed. The actual method arguments will be spilled later.
{
CrstHolder ch(&m_CodeHeapCritSec);
- mem = (TADDR) allocCodeRaw(&requestInfo, sizeof(TADDR), blockSize, alignment, &pCodeHeap);
+ mem = (TADDR) allocCodeRaw(&requestInfo, sizeof(CodeHeader), blockSize, alignment, &pCodeHeap);
// CodeHeader comes immediately before the block
CodeHeader * pCodeHdr = (CodeHeader *) (mem - sizeof(CodeHeader));
#include "pedecoder.h"
#include "gcinfo.h"
+#if defined(WIN64EXCEPTIONS) && !defined(USE_INDIRECT_CODEHEADER)
+#error "WIN64EXCEPTIONS requires USE_INDIRECT_CODEHEADER"
+#endif // WIN64EXCEPTIONS && !USE_INDIRECT_CODEHEADER
+
class MethodDesc;
class ICorJitCompiler;
class IJitManager;
#endif // !USE_GC_INFO_DECODER
-#if !defined(_TARGET_X86_) && !defined(CROSSGEN_COMPILE)
+#if defined(WIN64EXCEPTIONS) && !defined(CROSSGEN_COMPILE)
void EECodeManager::EnsureCallerContextIsValid( PREGDISPLAY pRD, StackwalkCacheEntry* pCacheEntry, EECodeInfo * pCodeInfo /*= NULL*/ )
{
return (size_t) (GetSP(pRD->pCallerContext));
}
-#endif // !defined(_TARGET_X86_) && !defined(CROSSGEN_COMPILE)
+#endif // WIN64EXCEPTIONS && !CROSSGEN_COMPILE
/*
* Light unwind the current stack frame, using provided cache entry.
{
LIMITED_METHOD_DAC_CONTRACT;
+#ifdef USE_GC_INFO_DECODER
GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
GcInfoDecoder gcInfoDecoder(
return PTR_VOID(taExactGenericsToken);
}
return NULL;
+#else // USE_GC_INFO_DECODER
+ PORTABILITY_ASSERT("EECodeManager::GetExactGenericsToken");
+ return NULL;
+#endif // USE_GC_INFO_DECODER
}
#ifdef WIN64EXCEPTIONS
+#ifndef _TARGET_X86_
EXTERN_C void JIT_MemSet_End();
EXTERN_C void JIT_MemCpy_End();
EXTERN_C void JIT_WriteBarrier_End();
EXTERN_C void JIT_CheckedWriteBarrier_End();
+#endif // _TARGET_X86_
#if defined(_TARGET_AMD64_) && defined(_DEBUG)
EXTERN_C void JIT_WriteBarrier_Debug();
#define CHECK_RANGE(name) \
if (GetEEFuncEntryPoint(name) <= uControlPc && uControlPc < GetEEFuncEntryPoint(name##_End)) return true;
+#ifndef _TARGET_X86_
CHECK_RANGE(JIT_MemSet)
CHECK_RANGE(JIT_MemCpy)
CHECK_RANGE(JIT_WriteBarrier)
CHECK_RANGE(JIT_CheckedWriteBarrier)
+#endif // _TARGET_X86_
#if defined(_TARGET_AMD64_) && defined(_DEBUG)
CHECK_RANGE(JIT_WriteBarrier_Debug)
{
WRAPPER_NO_CONTRACT;
-#ifdef _TARGET_X86_
-
+#if defined(_TARGET_X86_) && !defined(PLATFORM_UNIX)
void* f_IP = (void *)GetIP(pContext);
if (((f_IP >= (void *) JIT_WriteBarrierStart) && (f_IP <= (void *) JIT_WriteBarrierLast)) ||
// put ESP back to what it was before the call.
SetSP(pContext, PCODE((BYTE*)GetSP(pContext) + sizeof(void*)));
}
-
return FALSE;
-
-#elif defined(WIN64EXCEPTIONS)
-
+#elif defined(WIN64EXCEPTIONS) // _TARGET_X86_ && !PLATFORM_UNIX
void* f_IP = dac_cast<PTR_VOID>(GetIP(pContext));
CONTEXT tempContext;
// Now we save the address back into the context so that it gets used
// as the faulting address.
SetIP(pContext, ControlPCPostAdjustment);
-#endif // _TARGET_ARM_
+#endif // _TARGET_ARM_ || _TARGET_ARM64_
// Unwind the frame chain - On Win64, this is required since we may handle the managed fault and to do so,
// we will replace the exception context with the managed context and "continue execution" there. Thus, we do not
}
return FALSE;
-
-#else // ! _X86_ && !WIN64EXCEPTIONS
-
- PORTABILITY_WARNING("AdjustContextForWriteBarrier() not implemented on this platform");
+#else // WIN64EXCEPTIONS
+ PORTABILITY_ASSERT("AdjustContextForWriteBarrier");
return FALSE;
-
-#endif
+#endif // ELSE
}
struct SavedExceptionInfo
void FaultingExceptionFrame::Init(CONTEXT *pContext)
{
WRAPPER_NO_CONTRACT;
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
+#ifdef _TARGET_X86_
CalleeSavedRegisters *pRegs = GetCalleeSavedRegisters();
- pRegs->ebp = pContext->Ebp;
- pRegs->ebx = pContext->Ebx;
- pRegs->esi = pContext->Esi;
- pRegs->edi = pContext->Edi;
+#define CALLEE_SAVED_REGISTER(regname) pRegs->regname = pContext->regname;
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
m_ReturnAddress = ::GetIP(pContext);
m_Esp = (DWORD)GetSP(pContext);
-#elif defined(WIN64EXCEPTIONS)
+#else // _TARGET_X86_
+ PORTABILITY_ASSERT("FaultingExceptionFrame::Init");
+#endif // _TARGET_???_ (ELSE)
+#else // !WIN64EXCEPTIONS
m_ReturnAddress = ::GetIP(pContext);
CopyOSContext(&m_ctx, pContext);
-#else
- PORTABILITY_ASSERT("FaultingExceptionFrame::InitAndLink");
-#endif
+#endif // !WIN64EXCEPTIONS
}
//
#else // !(_WIN64 || _TARGET_X86_)
#error Unsupported platform
#endif // _WIN64
-
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
if (pEHTracker->GetCorruptionSeverity() == ProcessCorrupting)
{
EEPolicy::HandleFatalError(COR_E_FAILFAST, reinterpret_cast<UINT_PTR>(pExceptionInfo->ExceptionRecord->ExceptionAddress), NULL, pExceptionInfo);
}
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
}
return ret;
// there is no more managed code on the stack.
//
// Note: This function should be invoked ONLY during unwind.
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
void ResetThreadAbortState(PTR_Thread pThread, void *pEstablisherFrame)
-#elif defined(WIN64EXCEPTIONS)
+#else
void ResetThreadAbortState(PTR_Thread pThread, CrawlFrame *pCf, StackFrame sfCurrentStackFrame)
#endif
{
GC_NOTRIGGER;
MODE_ANY;
PRECONDITION(pThread != NULL);
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
PRECONDITION(pEstablisherFrame != NULL);
-#elif defined(WIN64EXCEPTIONS)
+#else
PRECONDITION(pCf != NULL);
PRECONDITION(!sfCurrentStackFrame.IsNull());
#endif
if (pThread->IsAbortRequested())
{
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
if (GetNextCOMPlusSEHRecord(static_cast<EXCEPTION_REGISTRATION_RECORD *>(pEstablisherFrame)) == EXCEPTION_CHAIN_END)
{
// Topmost handler and abort requested.
fResetThreadAbortState = TRUE;
LOG((LF_EH, LL_INFO100, "ResetThreadAbortState: Topmost handler resets abort as no more managed code beyond %p.\n", pEstablisherFrame));
}
-#elif defined(WIN64EXCEPTIONS)
+#else // !WIN64EXCEPTIONS
// Get the active exception tracker
PTR_ExceptionTracker pCurEHTracker = pThread->GetExceptionState()->GetCurrentExceptionTracker();
_ASSERTE(pCurEHTracker != NULL);
LOG((LF_EH, LL_INFO100, "ResetThreadAbortState: Resetting thread abort state since there is no more managed code beyond stack frames:\n"));
LOG((LF_EH, LL_INFO100, "sf.SP = %p ", dataCallback.sfSeedCrawlFrame.SP));
}
-#else // WIN64EXCEPTIONS
-#error Unsupported platform
-#endif // WIN64EXCEPTIONS
+#endif // !WIN64EXCEPTIONS
}
if (fResetThreadAbortState)
VOID DECLSPEC_NORETURN RealCOMPlusThrowInvalidCastException(OBJECTREF *pObj, TypeHandle thCastTo);
-#ifdef _TARGET_X86_
+#ifndef WIN64EXCEPTIONS
#include "eexcp.h"
#include "exinfo.h"
}
};
-#endif // _TARGET_X86_
+#endif // !WIN64EXCEPTIONS
#if defined(ENABLE_CONTRACTS_IMPL)
// The stuff below is what works "behind the scenes" of the public macros.
//==========================================================================
-#ifdef _TARGET_X86_
-LPVOID COMPlusEndCatchWorker(Thread *pCurThread);
-EXTERN_C LPVOID STDCALL COMPlusEndCatch(LPVOID ebp, DWORD ebx, DWORD edi, DWORD esi, LPVOID* pRetAddress);
-#endif
// Specify NULL for uTryCatchResumeAddress when not checking for a InducedThreadRedirectAtEndOfCatch
EXTERN_C LPVOID COMPlusCheckForAbort(UINT_PTR uTryCatchResumeAddress = NULL);
#ifndef DACCESS_COMPILE
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
void ResetThreadAbortState(PTR_Thread pThread, void *pEstablisherFrame);
-#elif defined(WIN64EXCEPTIONS)
+#else
void ResetThreadAbortState(PTR_Thread pThread, CrawlFrame *pCf, StackFrame sfCurrentStackFrame);
#endif
*(pRD->pCallerContext) = *(pDispatcherContext->ContextRecord);
pRD->IsCallerContextValid = TRUE;
+#ifndef _TARGET_X86_
pRD->SP = sfEstablisherFrame.SP;
+#else
+ pRD->Esp = sfEstablisherFrame.SP;
+#endif
pRD->ControlPC = pDispatcherContext->ControlPc;
#if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
ThreadExceptionState * pCurTES = pCurThread->GetExceptionState();
_ASSERTE(pCurTES != NULL);
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
ExceptionTracker* pEHTracker = pCurTES->GetCurrentExceptionTracker();
if (pEHTracker == NULL)
{
pCurTES->SetLastActiveExceptionCorruptionSeverity(severity);
}
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
}
throw std::move(ex);
#include "exinfo.h"
#include "dbginterface.h"
+#ifndef WIN64EXCEPTIONS
#ifndef DACCESS_COMPILE
//
// Destroy the handle within an ExInfo. This respects the fact that we can have preallocated global handles living
DacError(E_UNEXPECTED);
#endif // !DACCESS_COMPILE
}
+#endif // !WIN64EXCEPTIONS
int nestingLevel = 0;
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
//
// Get the SEH frame that covers this location on the stack. Note: we pass a skip count of 1. We know that when
// this is called, there is a nested exception handler on pThread's stack that is only there during exception
nestingLevel = ComputeEnclosingHandlerNestingLevel(pJitManager,
methodToken,
natOffset);
-#elif !defined(WIN64EXCEPTIONS)
- // !_TARGET_X86_ && !WIN64EXCEPTIONS
- PORTABILITY_ASSERT("SetDebuggerInterceptInfo() (ExState.cpp) - continuable exceptions NYI\n");
- return FALSE;
-#endif // !_TARGET_X86_
+#endif // !WIN64EXCEPTIONS
//
// These values will override the normal information used by the EH subsystem to handle the exception.
m_pDebuggerContext = NULL;
m_pDebuggerInterceptNativeOffset = 0;
+ #ifndef WIN64EXCEPTIONS
// x86-specific fields
- #if defined(_TARGET_X86_)
m_pDebuggerInterceptFrame = EXCEPTION_CHAIN_END;
- #endif // defined(_TARGET_X86_)
+ #endif // !WIN64EXCEPTIONS
m_dDebuggerInterceptHandlerDepth = 0;
}
//
void GetDebuggerInterceptInfo(
- #if defined(_TARGET_X86_)
+ #ifndef WIN64EXCEPTIONS
PEXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
- #endif // _TARGET_X86_
+ #endif // !WIN64EXCEPTIONS
MethodDesc **ppFunc,
int *pdHandler,
BYTE **ppStack,
{
LIMITED_METHOD_CONTRACT;
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
if (pEstablisherFrame != NULL)
{
*pEstablisherFrame = m_pDebuggerInterceptFrame;
}
-#endif // _TARGET_X86_
+#endif // !WIN64EXCEPTIONS
if (ppFunc != NULL)
{
ULONG_PTR m_pDebuggerInterceptNativeOffset;
// The remaining fields are only used on x86.
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
// the exception registration record covering the stack range containing the interception point
PEXCEPTION_REGISTRATION_RECORD m_pDebuggerInterceptFrame;
-#endif // defined(_TARGET_X86_)
+#endif // !WIN64EXCEPTIONS
// the nesting level at which we want to resume execution
int m_dDebuggerInterceptHandlerDepth;
{
friend class CheckAsmOffsets;
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
+#ifdef _TARGET_X86_
DWORD m_Esp;
CalleeSavedRegisters m_regs;
TADDR m_ReturnAddress;
-#endif
-
-#ifdef WIN64EXCEPTIONS
+#else // _TARGET_X86_
+ #error "Unsupported architecture"
+#endif // _TARGET_X86_
+#else // WIN64EXCEPTIONS
BOOL m_fFilterExecuted; // Flag for FirstCallToHandler
TADDR m_ReturnAddress;
T_CONTEXT m_ctx;
-#endif // WIN64EXCEPTIONS
+#endif // !WIN64EXCEPTIONS
VPTR_VTABLE_CLASS(FaultingExceptionFrame, Frame)
return FRAME_ATTR_EXCEPTION | FRAME_ATTR_FAULTED;
}
-#if defined(_TARGET_X86_)
+#ifndef WIN64EXCEPTIONS
CalleeSavedRegisters *GetCalleeSavedRegisters()
{
+#ifdef _TARGET_X86_
LIMITED_METHOD_DAC_CONTRACT;
return &m_regs;
+#else
+ PORTABILITY_ASSERT("GetCalleeSavedRegisters");
+#endif // _TARGET_X86_
}
-#endif
+#endif // WIN64EXCEPTIONS
#ifdef WIN64EXCEPTIONS
T_CONTEXT *GetExceptionContext ()
// the end is exclusive). Return -1 if no such point exists.
unsigned FindFirstInterruptiblePoint(CrawlFrame* pCF, unsigned offs, unsigned endOffs)
{
+#ifdef USE_GC_INFO_DECODER
GCInfoToken gcInfoToken = pCF->GetGCInfoToken();
GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_FOR_RANGES_CALLBACK);
gcInfoDecoder.EnumerateInterruptibleRanges(&FindFirstInterruptiblePointStateCB, &state);
return state.returnOffs;
+#else
+ PORTABILITY_ASSERT("FindFirstInterruptiblePoint");
+ return -1;
+#endif // USE_GC_INFO_DECODER
}
#endif // WIN64EXCEPTIONS
#endif // _DEBUG
DWORD relOffsetOverride = NO_OVERRIDE_OFFSET;
-#if defined(WIN64EXCEPTIONS)
+#if defined(WIN64EXCEPTIONS) && defined(USE_GC_INFO_DECODER)
if (pCF->ShouldParentToFuncletUseUnwindTargetLocationForGCReporting())
{
GCInfoToken gcInfoToken = pCF->GetGCInfoToken();
}
}
-#endif // WIN64EXCEPTIONS
+#endif // WIN64EXCEPTIONS && USE_GC_INFO_DECODER
pCM->EnumGcRefs(pCF->GetRegisterSet(),
pCF->GetCodeInfo(),
#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
+#ifdef WIN64EXCEPTIONS
+#define USE_INDIRECT_CODEHEADER
+#endif // WIN64EXCEPTIONS
+
#define HAS_COMPACT_ENTRYPOINTS 1
// Needed for PInvoke inlining in ngened images
// This represents some of the FramedMethodFrame fields that are
// stored at negative offsets.
//--------------------------------------------------------------------
+#define ENUM_CALLEE_SAVED_REGISTERS() \
+ CALLEE_SAVED_REGISTER(Edi) \
+ CALLEE_SAVED_REGISTER(Esi) \
+ CALLEE_SAVED_REGISTER(Ebx) \
+ CALLEE_SAVED_REGISTER(Ebp)
+
typedef DPTR(struct CalleeSavedRegisters) PTR_CalleeSavedRegisters;
struct CalleeSavedRegisters {
- INT32 edi;
- INT32 esi;
- INT32 ebx;
- INT32 ebp;
+#define CALLEE_SAVED_REGISTER(regname) INT32 regname;
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
};
//--------------------------------------------------------------------
pRD->pContext = NULL;
- pRD->pEdi = (DWORD*) ®s->edi;
- pRD->pEsi = (DWORD*) ®s->esi;
- pRD->pEbx = (DWORD*) ®s->ebx;
- pRD->pEbp = (DWORD*) ®s->ebp;
+#define CALLEE_SAVED_REGISTER(regname) pRD->p##regname = (DWORD*) ®s->regname;
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
pRD->PCTAddr = GetReturnAddressPtr();
pRD->ControlPC = *PTR_PCODE(pRD->PCTAddr);
pRD->Esp = (DWORD)(pRD->PCTAddr + sizeof(TADDR) + cbStackPop);
}
CONTRACT_END;
+#ifndef WIN64EXCEPTIONS
CalleeSavedRegisters* regs = GetCalleeSavedRegisters();
// reset pContext; it's only valid for active (top-most) frame
pRD->pContext = NULL;
- pRD->pEdi = (DWORD*) ®s->edi;
- pRD->pEsi = (DWORD*) ®s->esi;
- pRD->pEbx = (DWORD*) ®s->ebx;
- pRD->pEbp = (DWORD*) ®s->ebp;
+#define CALLEE_SAVED_REGISTER(regname) pRD->p##regname = (DWORD*) ®s->regname;
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
+ pRD->Esp = m_Esp;
pRD->PCTAddr = GetReturnAddressPtr();
pRD->ControlPC = *PTR_PCODE(pRD->PCTAddr);
- pRD->Esp = m_Esp;
+#else
+ memcpy(pRD->pCurrentContext, &m_ctx, sizeof(CONTEXT));
+
+ pRD->ControlPC = m_ctx.Eip;
+
+ pRD->Esp = m_ctx.Esp;
+
+ pRD->pCurrentContextPointers->Ebx = &m_ctx.Ebx;
+ pRD->pCurrentContextPointers->Edi = &m_ctx.Edi;
+ pRD->pCurrentContextPointers->Esi = &m_ctx.Esi;
+ pRD->pCurrentContextPointers->Ebp = &m_ctx.Ebp;
+
+ pRD->IsCallerContextValid = FALSE;
+ pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
+#endif // WIN64EXCEPTIONS
RETURN;
}
CONTEXT* pUnwoundContext = m_Regs;
+#ifndef WIN64EXCEPTIONS
#if !defined(DACCESS_COMPILE)
// "pContextForUnwind" field is only used on X86 since not only is it initialized just for it,
// but its used only under the confines of STACKWALKER_MAY_POP_FRAMES preprocessor define,
pUnwoundContext->Eip = m_Regs->Eip;
}
#endif // !defined(DACCESS_COMPILE)
+#endif // !WIN64EXCEPTIONS
pRD->pEax = &pUnwoundContext->Eax;
pRD->pEcx = &pUnwoundContext->Ecx;
// reset pContext; it's only valid for active (top-most) frame
pRD->pContext = NULL;
- pRD->pEdi = (DWORD*)&m_regs.edi;
- pRD->pEsi = (DWORD*)&m_regs.esi;
- pRD->pEbx = (DWORD*)&m_regs.ebx;
- pRD->pEbp = (DWORD*)&m_regs.ebp;
+#define CALLEE_SAVED_REGISTER(regname) pRD->p##regname = (DWORD*) &m_regs.regname;
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
pRD->PCTAddr = GetReturnAddressPtr();
pRD->ControlPC = *PTR_PCODE(pRD->PCTAddr);
{
LIMITED_METHOD_CONTRACT;
return offsetof(StubForHostStackFrame, m_calleeSavedRegisters) +
- offsetof(CalleeSavedRegisters, ebp);
+ offsetof(CalleeSavedRegisters, Ebp);
}
static INT32 GetFPrelOffsOfArgumentRegisters()
#define STATUS_CLR_GCCOVER_CODE STATUS_PRIVILEGED_INSTRUCTION
+#ifndef WIN64EXCEPTIONS
class Thread;
#if defined(_MSC_VER)
// Actually, the handler getting set is properly registered
#endif
-#ifdef FEATURE_PAL
-
-extern VOID SetSEHRecord(PEXCEPTION_REGISTRATION_RECORD record);
-extern VOID ResetSEHRecord(PEXCEPTION_REGISTRATION_RECORD record);
-
-#define INSTALL_SEH_RECORD(record) \
- SetSEHRecord(record); \
-
-#define UNINSTALL_SEH_RECORD(record) \
- ResetSEHRecord(record);
-
-#else // FEATURE_PAL
-
#define INSTALL_SEH_RECORD(record) \
{ \
(record)->Next = (PEXCEPTION_REGISTRATION_RECORD)__readfsdword(0); \
__writefsdword(0, (DWORD) ((record)->Next)); \
}
-#endif // FEATURE_PAL
-
#define INSTALL_EXCEPTION_HANDLING_RECORD(record) \
{ \
PEXCEPTION_REGISTRATION_RECORD __record = (record); \
#endif
+
+PEXCEPTION_REGISTRATION_RECORD GetCurrentSEHRecord();
+PEXCEPTION_REGISTRATION_RECORD GetFirstCOMPlusSEHRecord(Thread*);
+
+LPVOID COMPlusEndCatchWorker(Thread *pCurThread);
+EXTERN_C LPVOID STDCALL COMPlusEndCatch(LPVOID ebp, DWORD ebx, DWORD edi, DWORD esi, LPVOID* pRetAddress);
+
+#else // WIN64EXCEPTIONS
+#define INSTALL_EXCEPTION_HANDLING_RECORD(record)
+#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record)
+#define DECLARE_CPFH_EH_RECORD(pCurThread)
+
+#endif // WIN64EXCEPTIONS
+
//
// Retrieves the redirected CONTEXT* from the stack frame of one of the
// RedirectedHandledJITCaseForXXX_Stub's.
//
PTR_CONTEXT GetCONTEXTFromRedirectedStubStackFrame(CONTEXT * pContext);
+#ifdef WIN64EXCEPTIONS
+PTR_CONTEXT GetCONTEXTFromRedirectedStubStackFrame(T_DISPATCHER_CONTEXT * pDispatcherContext);
-PEXCEPTION_REGISTRATION_RECORD GetCurrentSEHRecord();
-PEXCEPTION_REGISTRATION_RECORD GetFirstCOMPlusSEHRecord(Thread*);
+class FaultingExceptionFrame;
+
+FaultingExceptionFrame *GetFrameFromRedirectedStubStackFrame (DISPATCHER_CONTEXT *pDispatcherContext);
+#endif // WIN64EXCEPTIONS
// Determine the address of the instruction that made the current call.
inline
#include "asmconstants.h"
#include "virtualcallstub.h"
+#ifndef WIN64EXCEPTIONS
MethodDesc * GetUserMethodForILStub(Thread * pThread, UINT_PTR uStubSP, MethodDesc * pILStubMD, Frame ** ppFrameOut);
#if !defined(DACCESS_COMPILE)
return (EXCEPTION_REGISTRATION_RECORD*) fs0;
}
-#ifdef FEATURE_PAL
-VOID SetSEHRecord(PEXCEPTION_REGISTRATION_RECORD record)
-{
- WRAPPER_NO_CONTRACT;
- record->Next = CurrentSEHRecord;
- CurrentSEHRecord = record;
-}
-
-VOID ResetSEHRecord(PEXCEPTION_REGISTRATION_RECORD record)
-{
- CurrentSEHRecord = record->Next;
-}
-#endif // FEATURE_PAL
-
PEXCEPTION_REGISTRATION_RECORD GetFirstCOMPlusSEHRecord(Thread *pThread) {
WRAPPER_NO_CONTRACT;
#ifndef FEATURE_PAL
return retval;
}
-LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv)
-{
- WRAPPER_NO_CONTRACT;
- STATIC_CONTRACT_ENTRY_POINT;
-
- LONG result = EXCEPTION_CONTINUE_SEARCH;
-
- // This function can be called during the handling of a SO
- //BEGIN_ENTRYPOINT_VOIDRET;
-
- result = CLRVectoredExceptionHandler(pExceptionInfo);
-
- if (EXCEPTION_EXECUTE_HANDLER == result)
- {
- result = EXCEPTION_CONTINUE_SEARCH;
- }
-
- //END_ENTRYPOINT_VOIDRET;
-
- return result;
-}
-
#ifdef FEATURE_COMINTEROP
// The reverse COM interop path needs to be sure to pop the ComMethodFrame that is pushed, but we do not want
-// to have an additional FS:0 handler between the COM callsite and the call into managed. So we push this
-// FS:0 handler, which will defer to the usual COMPlusFrameHandler and then perform the cleanup of the
-// ComMethodFrame, if needed.
+// to have an additional FS:0 handler between the COM callsite and the call into managed. So we push this
+// FS:0 handler, which will defer to the usual COMPlusFrameHandler and then perform the cleanup of the
+// ComMethodFrame, if needed.
EXCEPTION_HANDLER_IMPL(COMPlusFrameHandlerRevCom)
{
STATIC_CONTRACT_THROWS;
return result;
}
#endif // FEATURE_COMINTEROP
+#endif // !DACCESS_COMPILE
+#endif // !WIN64EXCEPTIONS
+
+#ifndef DACCESS_COMPILE
+LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv)
+{
+#ifndef WIN64EXCEPTIONS
+ WRAPPER_NO_CONTRACT;
+ STATIC_CONTRACT_ENTRY_POINT;
+
+ LONG result = EXCEPTION_CONTINUE_SEARCH;
+
+ // This function can be called during the handling of a SO
+ //BEGIN_ENTRYPOINT_VOIDRET;
+
+ result = CLRVectoredExceptionHandler(pExceptionInfo);
+
+ if (EXCEPTION_EXECUTE_HANDLER == result)
+ {
+ result = EXCEPTION_CONTINUE_SEARCH;
+ }
+ //END_ENTRYPOINT_VOIDRET;
+
+ return result;
+#else // !WIN64EXCEPTIONS
+ return EXCEPTION_CONTINUE_SEARCH;
+#endif // !WIN64EXCEPTIONS
+}
+#endif // !DACCESS_COMPILE
// Returns TRUE if caller should resume execution.
BOOL
return TRUE;
}
-
-#ifdef FEATURE_PAL
-VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHardwareException)
-{
- UNREACHABLE();
-}
-#endif
-#endif // !DACCESS_COMPILE
// debugger may need additional support.
// void __stdcall JIT_EndCatch();
NESTED_ENTRY JIT_EndCatch, _TEXT, NoHandler
+#ifndef WIN64EXCEPTIONS
// make temp storage for return address, and push the address of that
// as the last arg to COMPlusEndCatch
mov ecx, [esp]
pop edx // edx = new eip
mov esp, eax // esp = new esp
jmp edx // eip = new eip
+#else
+ int3
+#endif
NESTED_END JIT_EndCatch, _TEXT
extern "C"
{
- void ThrowControlForThread()
+ void ThrowControlForThread(FaultingExceptionFrame *pfef)
{
PORTABILITY_ASSERT("Implement for PAL");
}
{
}
- _Unwind_Reason_Code
- UnhandledExceptionHandlerUnix(
- IN int version,
- IN _Unwind_Action action,
- IN uint64_t exceptionClass,
- IN struct _Unwind_Exception *exception,
- IN struct _Unwind_Context *context
- )
- {
- PORTABILITY_ASSERT("UnhandledExceptionHandlerUnix");
- return _URC_FATAL_PHASE1_ERROR;
- }
-
BOOL CallRtlUnwind()
{
PORTABILITY_ASSERT("CallRtlUnwind");
{
PORTABILITY_ASSERT("JIT_TailCallLeave");
}
+
+PTR_CONTEXT GetCONTEXTFromRedirectedStubStackFrame(T_DISPATCHER_CONTEXT * pDispatcherContext)
+{
+ PORTABILITY_ASSERT("GetCONTEXTFromRedirectedStubStackFrame");
+ return NULL;
+}
+
+FaultingExceptionFrame *GetFrameFromRedirectedStubStackFrame(DISPATCHER_CONTEXT *pDispatcherContext)
+{
+ PORTABILITY_ASSERT("GetFrameFromRedirectedStubStackFrame");
+ return NULL;
+}
+
+EXTERN_C ULONG
+RtlpGetFunctionEndAddress (
+ __in PT_RUNTIME_FUNCTION FunctionEntry,
+ __in ULONG ImageBase
+ )
+{
+ PORTABILITY_ASSERT("RtlpGetFunctionEndAddress");
+ return 0;
+}
+
+EXTERN_C
+NTSYSAPI
+PEXCEPTION_ROUTINE
+NTAPI
+RtlVirtualUnwind (
+ __in DWORD HandlerType,
+ __in DWORD ImageBase,
+ __in DWORD ControlPc,
+ __in PRUNTIME_FUNCTION FunctionEntry,
+ __inout PT_CONTEXT ContextRecord,
+ __out PVOID *HandlerData,
+ __out PDWORD EstablisherFrame,
+ __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
+ )
+{
+ PORTABILITY_ASSERT("RtlVirtualUnwind");
+ return NULL;
+}
}
/*********************************************************************/
+static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
+{
+ STANDARD_VM_CONTRACT;
+
+ unsigned result = 0;
+
+ _ASSERTE(pMT->IsValueType());
+
+ ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
+ for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
+ {
+ int fieldStartIndex = pFD->GetOffset() / sizeof(void*);
+
+ if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE)
+ {
+ if (pFD->IsObjRef())
+ {
+ if (gcPtrs[fieldStartIndex] == TYPE_GC_NONE)
+ {
+ gcPtrs[fieldStartIndex] = TYPE_GC_REF;
+ result++;
+ }
+ else if (gcPtrs[fieldStartIndex] != TYPE_GC_REF)
+ {
+ COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+ }
+ }
+ else
+ {
+ MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
+ if (pFieldMT->HasSameTypeDefAs(g_pByReferenceClass))
+ {
+ if (gcPtrs[fieldStartIndex] == TYPE_GC_NONE)
+ {
+ gcPtrs[fieldStartIndex] = TYPE_GC_BYREF;
+ result++;
+ }
+ else if (gcPtrs[fieldStartIndex] != TYPE_GC_BYREF)
+ {
+ COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+ }
+ else
+ {
+ result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
+ }
+ }
+ }
+ return result;
+}
+
unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
{
CONTRACTL {
}
else
{
- // TODO-SPAN: Proper GC reporting
memset(gcPtrs, TYPE_GC_NONE,
- (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
- result = 0;
+ (VMClsHnd.GetSize() + sizeof(void*) - 1) / sizeof(void*));
+ // Note: This case is more complicated than the TypedReference case
+ // due to ByRefLike structs being included as fields in other value
+ // types (TypedReference can not be.)
+ result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
}
}
else if (VMClsHnd.IsNativeValueType())
{
result = ECall::GetIntrinsicID(method);
}
+ else
+ {
+ MethodTable * pMT = method->GetMethodTable();
+ if (pMT->IsByRefLike() && pMT->GetModule()->IsSystem())
+ {
+ if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
+ {
+ // ByReference<T> has just two methods: constructor and Value property
+ if (method->IsCtor())
+ {
+ result = CORINFO_INTRINSIC_ByReference_Ctor;
+ }
+ else
+ {
+ _ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
+ result = CORINFO_INTRINSIC_ByReference_Value;
+ }
+ *pMustExpand = true;
+ }
+
+ // TODO-SPAN: Span<T> intrinsics for optimizations
+ }
+ }
EE_TO_JIT_TRANSITION();
RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
-#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+#if defined(_TARGET_AMD64_)
pRuntimeFunction->EndAddress = currentCodeOffset + endOffset;
#endif
extern "C"
{
+#ifdef _TARGET_X86_
+ // UNIXTODO: Disable JIT_EndCatch after revising the jitter not to use this (for x86/Linux)
void STDCALL JIT_EndCatch(); // JIThelp.asm/JIThelp.s
+#endif // _TARGET_X86_
void STDCALL JIT_ByRefWriteBarrier(); // JIThelp.asm/JIThelp.s
BOOL MethodDesc::IsFCallOrIntrinsic()
{
WRAPPER_NO_CONTRACT;
- return (IsFCall() || IsArray());
+
+ if (IsFCall() || IsArray())
+ return TRUE;
+
+#ifdef FEATURE_SPAN_OF_T
+ // Intrinsic methods on ByReference<T> or Span<T>
+ MethodTable * pMT = GetMethodTable();
+ if (pMT->IsByRefLike() && pMT->GetModule()->IsSystem())
+ return TRUE;
+#endif
+
+ return FALSE;
}
//*******************************************************************************
CreateInstantiatingILStubTargetSig(pTargetMD, typeContext, &stubSigBuilder);
// 2. Emit the method body
+ unsigned int numArgs = msig.NumFixedArgs();
if (msig.HasThis())
{
// 2.1 Push the thisptr
pCode->EmitLoadThis();
+ numArgs++;
}
- // 2.2 Push the hidden context param
- // InstantiatingStub
- pCode->EmitLDC((TADDR)pHiddenArg);
+#if defined(_TARGET_X86_)
+ if (numArgs < NUM_ARGUMENT_REGISTERS)
+ {
+#endif // _TARGET_X86_
+ // 2.2 Push the hidden context param
+ // InstantiatingStub
+ pCode->EmitLDC((TADDR)pHiddenArg);
+#if defined(_TARGET_X86_)
+ }
+#endif // _TARGET_X86_
// 2.3 Push the rest of the arguments
for (unsigned i = 0; i < msig.NumFixedArgs();i++)
pCode->EmitLDARG(i);
}
- // 2.4 Push the target address
+#if defined(_TARGET_X86_)
+ if (numArgs >= NUM_ARGUMENT_REGISTERS)
+ {
+ // 2.4 Push the hidden context param
+ // InstantiatingStub
+ pCode->EmitLDC((TADDR)pHiddenArg);
+ }
+#endif // _TARGET_X86_
+
+ // 2.5 Push the target address
pCode->EmitLDC((TADDR)pTargetMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY));
- // 2.5 Do the calli
+ // 2.6 Do the calli
pCode->EmitCALLI(TOKEN_ILSTUB_TARGET_SIG, msig.NumFixedArgs() + 1, msig.IsReturnTypeVoid() ? 0 : 1);
pCode->EmitRET();
void ReportPointersFromValueType(promote_func *fn, ScanContext *sc, PTR_MethodTable pMT, PTR_VOID pSrc)
{
WRAPPER_NO_CONTRACT;
-
+
+ // SPAN-TODO: GC reporting - https://github.com/dotnet/coreclr/issues/8517
+
if (!pMT->ContainsPointers())
return;
pRD->pCurrentContext = pRD->pCallerContext;
pRD->pCallerContext = temp;
-#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
PT_KNONVOLATILE_CONTEXT_POINTERS tempPtrs = pRD->pCurrentContextPointers;
pRD->pCurrentContextPointers = pRD->pCallerContextPointers;
pRD->pCallerContextPointers = tempPtrs;
-#endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
}
else
{
CONTRACTL_END;
PCODE uControlPc = GetIP(pContext);
-#if defined(_WIN64)
+#ifdef BIT64
UINT64 EstablisherFrame;
- PVOID HandlerData;
-#elif defined(_TARGET_ARM_)
+#else // BIT64
DWORD EstablisherFrame;
+#endif // BIT64
PVOID HandlerData;
-#else
- _ASSERTE(!"nyi platform stackwalking");
-#endif
if (NULL == pFunctionEntry)
{
}
-#if !defined(DACCESS_COMPILE) && defined(_TARGET_X86_)
+#if !defined(DACCESS_COMPILE) && defined(_TARGET_X86_) && !defined(WIN64EXCEPTIONS)
#define STACKWALKER_MAY_POP_FRAMES
#endif
// We are transitioning from unmanaged code to managed code... lets do some validation of our
// EH mechanism on platforms that we can.
-#if defined(_DEBUG) && !defined(DACCESS_COMPILE) && (defined(_TARGET_X86_) && !defined(FEATURE_STUBS_AS_IL))
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE) && (defined(_TARGET_X86_) && !defined(FEATURE_PAL)) && !defined(WIN64EXCEPTIONS)
+ // TODO: Revise this once we enable WIN64EXCEPTIONS for x86/Linux
VerifyValidTransitionFromManagedCode(m_crawl.pThread, &m_crawl);
-#endif // _DEBUG && !DACCESS_COMPILE && _TARGET_X86_
+#endif // _DEBUG && !DACCESS_COMPILE && _TARGET_X86_ && !WIN64EXCEPTIONS
}
}
#ifndef DACCESS_COMPILE
virtual BOOL TraceManager(Thread *thread,
TraceDestination *trace,
- CONTEXT *pContext,
+ T_CONTEXT *pContext,
BYTE **pRetAddr);
#endif
#ifndef DACCESS_COMPILE
virtual BOOL TraceManager(Thread *thread,
TraceDestination *trace,
- CONTEXT *pContext,
+ T_CONTEXT *pContext,
BYTE **pRetAddr);
#endif
#ifndef DACCESS_COMPILE
virtual BOOL TraceManager(Thread *thread,
TraceDestination *trace,
- CONTEXT *pContext,
+ T_CONTEXT *pContext,
BYTE **pRetAddr);
#endif
virtual BOOL TraceManager(Thread *thread,
TraceDestination *trace,
- CONTEXT *pContext,
+ T_CONTEXT *pContext,
BYTE **pRetAddr);
#endif
#ifndef DACCESS_COMPILE
virtual BOOL TraceManager(Thread *thread,
TraceDestination *trace,
- CONTEXT *pContext,
+ T_CONTEXT *pContext,
BYTE **pRetAddr);
#endif
virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
#if !defined(DACCESS_COMPILE)
- virtual BOOL TraceManager(Thread *thread, TraceDestination *trace, CONTEXT *pContext, BYTE **pRetAddr);
+ virtual BOOL TraceManager(Thread *thread, TraceDestination *trace, T_CONTEXT *pContext, BYTE **pRetAddr);
static BOOL TraceDelegateObject(BYTE *orDel, TraceDestination *trace);
#endif // DACCESS_COMPILE
TailCallStubManager() : StubManager() {WRAPPER_NO_CONTRACT;}
~TailCallStubManager() {WRAPPER_NO_CONTRACT;}
- virtual BOOL TraceManager(Thread * pThread, TraceDestination * pTrace, CONTEXT * pContext, BYTE ** ppRetAddr);
+ virtual BOOL TraceManager(Thread * pThread, TraceDestination * pTrace, T_CONTEXT * pContext, BYTE ** ppRetAddr);
static bool IsTailCallStubHelper(PCODE code);
#endif // DACCESS_COMPILE
m_singleStepper.Disable();
}
- void ApplySingleStep(CONTEXT *pCtx)
+ void ApplySingleStep(T_CONTEXT *pCtx)
{
m_singleStepper.Apply(pCtx);
}
// Fixup code called by our vectored exception handler to complete the emulation of single stepping
// initiated by EnableSingleStep above. Returns true if the exception was indeed encountered during
// stepping.
- bool HandleSingleStep(CONTEXT *pCtx, DWORD dwExceptionCode)
+ bool HandleSingleStep(T_CONTEXT *pCtx, DWORD dwExceptionCode)
{
return m_singleStepper.Fixup(pCtx, dwExceptionCode);
}
| TS_Detached
| TS_Unstarted)));
-#ifdef _TARGET_X86_
+#if defined(_TARGET_X86_) && !defined(WIN64EXCEPTIONS)
// TODO WIN64: consider this if there is a way to detect of managed code on stack.
if ((m_pFrame == FRAME_TOP)
&& (GetFirstCOMPlusSEHRecord(this) == EXCEPTION_CHAIN_END)
if (!m_fPreemptiveGCDisabled)
{
if ((m_pFrame != FRAME_TOP) && m_pFrame->IsTransitionToNativeFrame()
-#ifdef _TARGET_X86_
+#if defined(_TARGET_X86_) && !defined(WIN64EXCEPTIONS)
&& ((size_t) GetFirstCOMPlusSEHRecord(this) > ((size_t) m_pFrame) - 20)
#endif // _TARGET_X86_
)
#include <float.h>
#include <limits.h>
-#if !defined(_TARGET_X86_)
+#if !defined(_TARGET_X86_) || defined(FEATURE_PAL)
#ifndef WIN64EXCEPTIONS
#define WIN64EXCEPTIONS
#endif
-#endif // !_TARGET_X86_
+#endif // !_TARGET_X86_ || FEATURE_PAL
#include "utilcode.h"
#include "corjit.h"
pZapWriter->Write(&runtimeFunction, sizeof(runtimeFunction));
}
-#if defined(WIN64EXCEPTIONS) && !defined(_TARGET_X86_)
+#if defined(WIN64EXCEPTIONS)
// Compare the unwind infos by their offset
int __cdecl ZapUnwindInfo::CompareUnwindInfo(const void* a_, const void* b_)
{
<PropertyGroup>
<InputAssemblyName Condition="'$(CLRTestKind)' == 'RunOnly'">$([MSBuild]::MakeRelative($(OutputPath), $(_CLRTestToRunFileFullPath)).Replace("\","/"))</InputAssemblyName>
<InputAssemblyName Condition="'$(CLRTestKind)' == 'BuildAndRun'">$(MSBuildProjectName).exe</InputAssemblyName>
- <JitDisasmOut>$(BaseOutputPathWithConfig.Replace("\","/"))dasm/$(BuildProjectRelativeDir.Replace("\","/"))</JitDisasmOut>
+ <JitDisasmOut>$([MSBuild]::MakeRelative($(OutputPath), $(BaseOutputPathWithConfig)dasm\$(BuildProjectRelativeDir)).Replace("\","/"))</JitDisasmOut>
<JitDisasmBashScript>
<![CDATA[
# JitDisasm Script
if [ ! -z $RunningJitDisasm ]
then
- echo $CORE_ROOT/corerun "$CORE_ROOT/jit-dasm.dll" --crossgen $CORE_ROOT/crossgen.exe --platform $CORE_ROOT --output $(JitDisasmOut) $(InputAssemblyName)
- "$CORE_ROOT/corerun" "$CORE_ROOT/jit-dasm" --crossgen $CORE_ROOT/crossgen.exe --platform $CORE_ROOT --output $(JitDisasmOut) $(InputAssemblyName)
- if [ $ERRORLEVEL -ne 0 ]
+ echo $CORE_ROOT/corerun "$CORE_ROOT/jit-dasm.dll" --crossgen $CORE_ROOT/crossgen --platform $CORE_ROOT --output $(JitDisasmOut) $(InputAssemblyName)
+ "$CORE_ROOT/corerun" "$CORE_ROOT/jit-dasm.dll" --crossgen $CORE_ROOT/crossgen --platform $CORE_ROOT --output $(JitDisasmOut) $(InputAssemblyName)
+ _jdExitCode=$?
+ if [ $_jdExitCode -ne 0 ]
then
- echo EXECUTION OF JIT-DASM - FAILED $ERRORLEVEL
+ echo EXECUTION OF JIT-DASM - FAILED $_jdExitCode
exit 1
fi
fi
<PropertyGroup>
<InputAssemblyName Condition="'$(CLRTestKind)' == 'RunOnly'">$([MSBuild]::MakeRelative($(OutputPath), $(_CLRTestToRunFileFullPath)))</InputAssemblyName>
<InputAssemblyName Condition="'$(CLRTestKind)' == 'BuildAndRun'">$(MSBuildProjectName).exe</InputAssemblyName>
- <JitDisasmOut>$(BaseOutputPathWithConfig)dasm\$(BuildProjectRelativeDir)</JitDisasmOut>
+ <JitDisasmOut>$([MSBuild]::MakeRelative($(OutputPath), $(BaseOutputPathWithConfig)dasm\$(BuildProjectRelativeDir)))</JitDisasmOut>
<JitDisasmBatchScript>
<![CDATA[
REM JitDisasm Script
{
"dependencies": {
- "Microsoft.NETCore.ILAsm": "1.2.0-beta-24906-01",
- "Microsoft.NETCore.ILDAsm": "1.2.0-beta-24906-01",
- "Microsoft.NETCore.Jit": "1.2.0-beta-24906-01",
- "Microsoft.NETCore.Runtime.CoreCLR": "1.2.0-beta-24906-01",
- "Microsoft.NETCore.TestHost": "1.2.0-beta-24906-01"
+ "Microsoft.NETCore.ILAsm": "1.2.0-beta-24911-02",
+ "Microsoft.NETCore.ILDAsm": "1.2.0-beta-24911-02",
+ "Microsoft.NETCore.Jit": "1.2.0-beta-24911-02",
+ "Microsoft.NETCore.Runtime.CoreCLR": "1.2.0-beta-24911-02",
+ "Microsoft.NETCore.TestHost": "1.2.0-beta-24911-02"
},
"frameworks": {
"netcoreapp1.1": {
"emitEntryPoint": true
},
"dependencies": {
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "Microsoft.NETCore.Targets": "1.2.0-beta-24906-02",
- "System.Threading.Thread": "4.4.0-beta-24906-02",
- "System.Collections": "4.4.0-beta-24906-02",
- "System.Xml.XmlSerializer": "4.4.0-beta-24906-02",
- "System.Collections.Concurrent": "4.4.0-beta-24906-02",
- "System.ObjectModel": "4.4.0-beta-24906-02",
- "System.Runtime.Numerics": "4.4.0-beta-24906-02",
- "System.Collections.NonGeneric": "4.4.0-beta-24906-02",
- "System.Collections.Specialized": "4.4.0-beta-24906-02",
- "System.ComponentModel": "4.4.0-beta-24906-02",
- "System.Reflection.Emit.Lightweight": "4.4.0-beta-24906-02",
- "System.Reflection.TypeExtensions": "4.4.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.Diagnostics.Contracts": "4.4.0-beta-24906-02",
- "System.Diagnostics.Debug": "4.4.0-beta-24906-02",
- "System.Diagnostics.Process": "4.4.0-beta-24906-02",
- "System.Diagnostics.Tools": "4.4.0-beta-24906-02",
- "System.Diagnostics.Tracing": "4.4.0-beta-24906-02",
- "System.Dynamic.Runtime": "4.4.0-beta-24906-02",
- "System.Globalization": "4.4.0-beta-24906-02",
- "System.Globalization.Calendars": "4.4.0-beta-24906-02",
- "System.IO": "4.4.0-beta-24906-02",
- "System.IO.FileSystem": "4.4.0-beta-24906-02",
- "System.IO.FileSystem.Primitives": "4.4.0-beta-24906-02",
- "System.Linq": "4.4.0-beta-24906-02",
- "System.Linq.Queryable": "4.4.0-beta-24906-02",
- "System.Linq.Expressions": "4.4.0-beta-24906-02",
- "System.Reflection": "4.4.0-beta-24906-02",
- "System.Reflection.Extensions": "4.4.0-beta-24906-02",
- "System.Resources.ResourceManager": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.CompilerServices.Unsafe": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Runtime.Handles": "4.4.0-beta-24906-02",
- "System.Runtime.InteropServices": "4.4.0-beta-24906-02",
- "System.Runtime.InteropServices.RuntimeInformation": "4.4.0-beta-24906-02",
- "System.Runtime.Loader": "4.4.0-beta-24906-02",
- "System.Security.Cryptography.Algorithms": "4.4.0-beta-24906-02",
- "System.Text.Encoding": "4.4.0-beta-24906-02",
- "System.Text.Encoding.Extensions": "4.4.0-beta-24906-02",
- "System.Text.RegularExpressions": "4.4.0-beta-24906-02",
- "System.Threading": "4.4.0-beta-24906-02",
- "System.Threading.AccessControl": "4.4.0-beta-24906-02",
- "System.Threading.Overlapped": "4.4.0-beta-24906-02",
- "System.Threading.Tasks": "4.4.0-beta-24906-02",
- "System.Threading.Tasks.Parallel": "4.4.0-beta-24906-02",
- "System.Threading.ThreadPool": "4.4.0-beta-24906-02",
- "System.Threading.Timer": "4.4.0-beta-24906-02",
- "System.Xml.ReaderWriter": "4.4.0-beta-24906-02",
- "System.Xml.XDocument": "4.4.0-beta-24906-02",
- "System.Xml.XmlDocument": "4.4.0-beta-24906-02",
- "System.Xml.XPath": "4.4.0-beta-24906-02",
- "System.Xml.XPath.XmlDocument": "4.4.0-beta-24906-02",
- "System.Numerics.Vectors": "4.4.0-beta-24906-02"
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "Microsoft.NETCore.Targets": "1.2.0-beta-24911-08",
+ "System.Threading.Thread": "4.4.0-beta-24911-08",
+ "System.Collections": "4.4.0-beta-24911-08",
+ "System.Xml.XmlSerializer": "4.4.0-beta-24911-08",
+ "System.Collections.Concurrent": "4.4.0-beta-24911-08",
+ "System.ObjectModel": "4.4.0-beta-24911-08",
+ "System.Runtime.Numerics": "4.4.0-beta-24911-08",
+ "System.Collections.NonGeneric": "4.4.0-beta-24911-08",
+ "System.Collections.Specialized": "4.4.0-beta-24911-08",
+ "System.ComponentModel": "4.4.0-beta-24911-08",
+ "System.Reflection.Emit.Lightweight": "4.4.0-beta-24911-08",
+ "System.Reflection.TypeExtensions": "4.4.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Contracts": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Debug": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Process": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Tools": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Tracing": "4.4.0-beta-24911-08",
+ "System.Dynamic.Runtime": "4.4.0-beta-24911-08",
+ "System.Globalization": "4.4.0-beta-24911-08",
+ "System.Globalization.Calendars": "4.4.0-beta-24911-08",
+ "System.IO": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem.Primitives": "4.4.0-beta-24911-08",
+ "System.Linq": "4.4.0-beta-24911-08",
+ "System.Linq.Queryable": "4.4.0-beta-24911-08",
+ "System.Linq.Expressions": "4.4.0-beta-24911-08",
+ "System.Reflection": "4.4.0-beta-24911-08",
+ "System.Reflection.Extensions": "4.4.0-beta-24911-08",
+ "System.Resources.ResourceManager": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.CompilerServices.Unsafe": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Runtime.Handles": "4.4.0-beta-24911-08",
+ "System.Runtime.InteropServices": "4.4.0-beta-24911-08",
+ "System.Runtime.InteropServices.RuntimeInformation": "4.4.0-beta-24911-08",
+ "System.Runtime.Loader": "4.4.0-beta-24911-08",
+ "System.Security.Cryptography.Algorithms": "4.4.0-beta-24911-08",
+ "System.Text.Encoding": "4.4.0-beta-24911-08",
+ "System.Text.Encoding.Extensions": "4.4.0-beta-24911-08",
+ "System.Text.RegularExpressions": "4.4.0-beta-24911-08",
+ "System.Threading": "4.4.0-beta-24911-08",
+ "System.Threading.AccessControl": "4.4.0-beta-24911-08",
+ "System.Threading.Overlapped": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks.Parallel": "4.4.0-beta-24911-08",
+ "System.Threading.ThreadPool": "4.4.0-beta-24911-08",
+ "System.Threading.Timer": "4.4.0-beta-24911-08",
+ "System.Xml.ReaderWriter": "4.4.0-beta-24911-08",
+ "System.Xml.XDocument": "4.4.0-beta-24911-08",
+ "System.Xml.XmlDocument": "4.4.0-beta-24911-08",
+ "System.Xml.XPath": "4.4.0-beta-24911-08",
+ "System.Xml.XPath.XmlDocument": "4.4.0-beta-24911-08",
+ "System.Numerics.Vectors": "4.4.0-beta-24911-08"
},
"frameworks": {
"netcoreapp1.1": {
"dependencies": {
- "Microsoft.NETCore.Runtime.CoreCLR": "1.2.0-beta-24906-01"
+ "Microsoft.NETCore.Runtime.CoreCLR": "1.2.0-beta-24911-02"
}
}
},
{
"dependencies": {
- "Microsoft.TargetingPack.Private.CoreCLR": "1.2.0-beta-24906-01"
+ "Microsoft.TargetingPack.Private.CoreCLR": "1.2.0-beta-24911-02"
},
"frameworks": {
"netcoreapp1.1": {
"Microsoft.DotNet.xunit.performance": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.analysis": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.runner.Windows": "1.0.0-alpha-build0040",
- "Microsoft.Win32.Primitives": "4.4.0-beta-24906-02",
+ "Microsoft.Win32.Primitives": "4.4.0-beta-24911-08",
"Newtonsoft.Json": "8.0.3",
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "Microsoft.NETCore.Targets": "1.2.0-beta-24906-02",
- "System.Collections.Immutable": "1.4.0-beta-24906-02",
- "System.Threading.Thread": "4.4.0-beta-24906-02",
- "System.Collections": "4.4.0-beta-24906-02",
- "System.Xml.XmlSerializer": "4.4.0-beta-24906-02",
- "System.Collections.Concurrent": "4.4.0-beta-24906-02",
- "System.ObjectModel": "4.4.0-beta-24906-02",
- "System.Runtime.Numerics": "4.4.0-beta-24906-02",
- "System.Collections.NonGeneric": "4.4.0-beta-24906-02",
- "System.Collections.Specialized": "4.4.0-beta-24906-02",
- "System.ComponentModel": "4.4.0-beta-24906-02",
- "System.Reflection.Emit.Lightweight": "4.4.0-beta-24906-02",
- "System.Reflection.TypeExtensions": "4.4.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.Diagnostics.Contracts": "4.4.0-beta-24906-02",
- "System.Diagnostics.Debug": "4.4.0-beta-24906-02",
- "System.Diagnostics.Process": "4.4.0-beta-24906-02",
- "System.Diagnostics.Tools": "4.4.0-beta-24906-02",
- "System.Diagnostics.Tracing": "4.4.0-beta-24906-02",
- "System.Dynamic.Runtime": "4.4.0-beta-24906-02",
- "System.Globalization": "4.4.0-beta-24906-02",
- "System.Globalization.Calendars": "4.4.0-beta-24906-02",
- "System.IO": "4.4.0-beta-24906-02",
- "System.IO.FileSystem": "4.4.0-beta-24906-02",
- "System.IO.FileSystem.Primitives": "4.4.0-beta-24906-02",
- "System.Linq": "4.4.0-beta-24906-02",
- "System.Linq.Queryable": "4.4.0-beta-24906-02",
- "System.Linq.Expressions": "4.4.0-beta-24906-02",
- "System.Reflection": "4.4.0-beta-24906-02",
- "System.Reflection.Extensions": "4.4.0-beta-24906-02",
- "System.Resources.ResourceManager": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.CompilerServices.Unsafe": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Runtime.Handles": "4.4.0-beta-24906-02",
- "System.Runtime.InteropServices": "4.4.0-beta-24906-02",
- "System.Runtime.InteropServices.RuntimeInformation": "4.4.0-beta-24906-02",
- "System.Runtime.Loader": "4.4.0-beta-24906-02",
- "System.Runtime.Serialization.Json": "4.4.0-beta-24906-02",
- "System.Runtime.Serialization.Primitives": "4.4.0-beta-24906-02",
- "System.Runtime.Serialization.Xml": "4.4.0-beta-24906-02",
- "System.Security.Cryptography.Algorithms": "4.4.0-beta-24906-02",
- "System.Text.Encoding": "4.4.0-beta-24906-02",
- "System.Text.Encoding.Extensions": "4.4.0-beta-24906-02",
- "System.Text.RegularExpressions": "4.4.0-beta-24906-02",
- "System.Threading": "4.4.0-beta-24906-02",
- "System.Threading.AccessControl": "4.4.0-beta-24906-02",
- "System.Threading.Overlapped": "4.4.0-beta-24906-02",
- "System.Threading.Tasks": "4.4.0-beta-24906-02",
- "System.Threading.Tasks.Parallel": "4.4.0-beta-24906-02",
- "System.Threading.ThreadPool": "4.4.0-beta-24906-02",
- "System.Threading.Timer": "4.4.0-beta-24906-02",
- "System.Xml.ReaderWriter": "4.4.0-beta-24906-02",
- "System.Xml.XDocument": "4.4.0-beta-24906-02",
- "System.Xml.XmlDocument": "4.4.0-beta-24906-02",
- "System.Xml.XPath": "4.4.0-beta-24906-02",
- "System.Xml.XPath.XmlDocument": "4.4.0-beta-24906-02",
- "System.Numerics.Vectors": "4.4.0-beta-24906-02"
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "Microsoft.NETCore.Targets": "1.2.0-beta-24911-08",
+ "System.Collections.Immutable": "1.4.0-beta-24911-08",
+ "System.Threading.Thread": "4.4.0-beta-24911-08",
+ "System.Collections": "4.4.0-beta-24911-08",
+ "System.Xml.XmlSerializer": "4.4.0-beta-24911-08",
+ "System.Collections.Concurrent": "4.4.0-beta-24911-08",
+ "System.ObjectModel": "4.4.0-beta-24911-08",
+ "System.Runtime.Numerics": "4.4.0-beta-24911-08",
+ "System.Collections.NonGeneric": "4.4.0-beta-24911-08",
+ "System.Collections.Specialized": "4.4.0-beta-24911-08",
+ "System.ComponentModel": "4.4.0-beta-24911-08",
+ "System.Reflection.Emit.Lightweight": "4.4.0-beta-24911-08",
+ "System.Reflection.TypeExtensions": "4.4.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Contracts": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Debug": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Process": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Tools": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Tracing": "4.4.0-beta-24911-08",
+ "System.Dynamic.Runtime": "4.4.0-beta-24911-08",
+ "System.Globalization": "4.4.0-beta-24911-08",
+ "System.Globalization.Calendars": "4.4.0-beta-24911-08",
+ "System.IO": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem.Primitives": "4.4.0-beta-24911-08",
+ "System.Linq": "4.4.0-beta-24911-08",
+ "System.Linq.Queryable": "4.4.0-beta-24911-08",
+ "System.Linq.Expressions": "4.4.0-beta-24911-08",
+ "System.Reflection": "4.4.0-beta-24911-08",
+ "System.Reflection.Extensions": "4.4.0-beta-24911-08",
+ "System.Resources.ResourceManager": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.CompilerServices.Unsafe": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Runtime.Handles": "4.4.0-beta-24911-08",
+ "System.Runtime.InteropServices": "4.4.0-beta-24911-08",
+ "System.Runtime.InteropServices.RuntimeInformation": "4.4.0-beta-24911-08",
+ "System.Runtime.Loader": "4.4.0-beta-24911-08",
+ "System.Runtime.Serialization.Json": "4.4.0-beta-24911-08",
+ "System.Runtime.Serialization.Primitives": "4.4.0-beta-24911-08",
+ "System.Runtime.Serialization.Xml": "4.4.0-beta-24911-08",
+ "System.Security.Cryptography.Algorithms": "4.4.0-beta-24911-08",
+ "System.Text.Encoding": "4.4.0-beta-24911-08",
+ "System.Text.Encoding.Extensions": "4.4.0-beta-24911-08",
+ "System.Text.RegularExpressions": "4.4.0-beta-24911-08",
+ "System.Threading": "4.4.0-beta-24911-08",
+ "System.Threading.AccessControl": "4.4.0-beta-24911-08",
+ "System.Threading.Overlapped": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks.Parallel": "4.4.0-beta-24911-08",
+ "System.Threading.ThreadPool": "4.4.0-beta-24911-08",
+ "System.Threading.Timer": "4.4.0-beta-24911-08",
+ "System.Xml.ReaderWriter": "4.4.0-beta-24911-08",
+ "System.Xml.XDocument": "4.4.0-beta-24911-08",
+ "System.Xml.XmlDocument": "4.4.0-beta-24911-08",
+ "System.Xml.XPath": "4.4.0-beta-24911-08",
+ "System.Xml.XPath.XmlDocument": "4.4.0-beta-24911-08",
+ "System.Numerics.Vectors": "4.4.0-beta-24911-08"
},
"frameworks": {
"netcoreapp1.1": {
{
"dependencies": {
"Microsoft.DotNet.CoreCLR.TestDependencies": "1.0.0-prerelease",
- "jit-dasm": "0.0.1.1",
+ "jit-dasm": "0.0.1.4",
"cijobs": "0.0.1.2",
- "jit-analyze": "0.0.1.0"
+ "jit-analyze": "0.0.1.1"
},
"frameworks": {
"netcoreapp1.1": {
int[] array2 = new int[40000];
int memnew = (int) GC.GetTotalMemory(false);
Console.WriteLine("Total Memory: " + memnew);
+ GC.KeepAlive(array2);
if(memnew >= memold) {
Console.WriteLine("Test for GC.TotalMemory passed!");
[assembly: OptimizeForBenchmarks]
[assembly: MeasureInstructionsRetired]
+[assembly: MeasureGCCounts]
namespace BenchmarksGame
{
--- /dev/null
+// 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.
+/* The Computer Language Benchmarks Game
+ http://benchmarksgame.alioth.debian.org/
+
+ Based on code originally contributed by Marek Safar
+ and optimized by kasthack
+
+ modified for use with xunit-performance
+*/
+
+using Microsoft.Xunit.Performance;
+using System;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+[assembly: OptimizeForBenchmarks]
+[assembly: MeasureInstructionsRetired]
+[assembly: MeasureGCCounts]
+
+namespace BenchmarksGame
+{
+public class BinaryTrees3
+{
+ private const int minDepth = 4;
+ private const int Iterations = 1;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static bool Bench(bool verbose = false)
+ {
+ int n = 16;
+ int maxDepth = Math.Max(minDepth + 2, n);
+ int stretchDepth = maxDepth + 1;
+ int t = 0;
+
+ int check = (TreeNode.bottomUpTree(0, stretchDepth)).itemCheck();
+ if (verbose)
+ {
+ Console.WriteLine("stretch tree of depth {0}\t check: {1}", stretchDepth, check);
+ }
+ t += check;
+
+ TreeNode longLivedTree = TreeNode.bottomUpTree(0, maxDepth);
+
+ for (int depth = minDepth; depth <= maxDepth; depth += 2)
+ {
+ int iterations = 1 << (maxDepth - depth + minDepth);
+
+ check = 0;
+ for (int i = 1; i <= iterations; i++)
+ {
+ check += (TreeNode.bottomUpTree(i, depth)).itemCheck();
+ check += (TreeNode.bottomUpTree(-i, depth)).itemCheck();
+ }
+
+ if (verbose)
+ {
+ Console.WriteLine("{0}\t trees of depth {1}\t check: {2}",
+ iterations * 2, depth, check);
+ }
+
+ t += check;
+ }
+
+ if (verbose)
+ {
+ Console.WriteLine("long lived tree of depth {0}\t check: {1}",
+ maxDepth, longLivedTree.itemCheck());
+ }
+
+ t += check;
+
+ return (t == -174785);
+ }
+
+ private class TreeNode
+ {
+ private TreeNode left, right;
+ private int item;
+
+ private TreeNode(int item)
+ {
+ this.item = item;
+ }
+
+ internal static TreeNode bottomUpTree(int item, int depth)
+ {
+ TreeNode t;
+ ChildTreeNodes(out t, item, depth - 1);
+ return t;
+ }
+
+ static void ChildTreeNodes(out TreeNode node, int item, int depth)
+ {
+ node = new TreeNode(item);
+ if ( depth > 0 )
+ {
+ ChildTreeNodes(out node.left, 2 * item - 1, depth - 1);
+ ChildTreeNodes(out node.right, 2 * item, depth - 1);
+ }
+ }
+
+ internal int itemCheck()
+ {
+ if (right == null) return item;
+ else return item + left.itemCheck() - right.itemCheck();
+ }
+ }
+
+ [Benchmark]
+ public static void Test()
+ {
+ foreach (var iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Iterations; i++)
+ {
+ Bench();
+ }
+ }
+ }
+ }
+
+ private static bool TestBase()
+ {
+ bool result = true;
+ for (int i = 0; i < Iterations; i++)
+ {
+ result &= Bench(true);
+ }
+ return result;
+ }
+
+ public static int Main()
+ {
+ bool result = TestBase();
+ return (result ? 100 : -1);
+ }
+}
+}
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
</PropertyGroup>
--- /dev/null
+<?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>
+ <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>
+ <NuGetTargetMoniker>.NETStandard,Version=v1.4</NuGetTargetMoniker>
+ <GCStressIncompatible>true</GCStressIncompatible>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="binarytrees.csharp3.cs" />
+ </ItemGroup>
+ <PropertyGroup>
+ <ProjectJson>$(JitPackagesConfigFileDirectory)benchmark\project.json</ProjectJson>
+ <ProjectLockJson>$(JitPackagesConfigFileDirectory)benchmark\project.lock.json</ProjectLockJson>
+ </PropertyGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>
// Iteration counts for inner loop set to have each call take 1 or
// 2 seconds or so in release, finish quickly in debug.
#if DEBUG
- const int InnerIterations = 1;
+ static int InnerIterations = 1;
#else
- const int InnerIterations = 1000000000;
+ static int InnerIterations = 1000000000;
#endif
// Function to meaure InnerLoop using the xunit-perf benchmark measurement facilities
public static int Main()
{
int failures = 0;
+
+ // On non-hardware accelerated platforms, the test times out because it runs for too long.
+ // In those cases, we decrease InnerIterations so the test doesn't time out.
+ if (!Vector.IsHardwareAccelerated)
+ {
+ InnerIterations = 100000;
+ }
+
foreach(int index in IndicesToTest)
{
ManualLoopTimes = new long[10];
do
{
bool[, , , ,][,] local8 = (new bool[81u, 98u, ((uint)(58.0f)), ((uint)(36.0f)),
- 74u][,]);
+ 74u*4u][,]);
while ((((uint)(local5)) != 4u))
{
if (Convert.ToBoolean((local5 + local5)))
"Microsoft.DotNet.xunit.performance": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.analysis": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.runner.Windows": "1.0.0-alpha-build0040",
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.Dynamic.Runtime": "4.4.0-beta-24906-02",
- "System.Linq": "4.4.0-beta-24906-02",
- "System.IO.FileSystem": "4.4.0-beta-24906-02",
- "System.Numerics.Vectors": "4.4.0-beta-24906-02",
- "System.Reflection": "4.4.0-beta-24906-02",
- "System.Reflection.Extensions": "4.4.0-beta-24906-02",
- "System.Reflection.TypeExtensions": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Runtime.Numerics": "4.4.0-beta-24906-02",
- "System.Text.RegularExpressions": "4.4.0-beta-24906-02",
- "System.Threading": "4.4.0-beta-24906-02",
- "System.Threading.Tasks": "4.4.0-beta-24906-02",
- "System.Threading.Tasks.Parallel": "4.4.0-beta-24906-02",
- "System.Security.Cryptography.Algorithms": "4.4.0-beta-24906-02",
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.Dynamic.Runtime": "4.4.0-beta-24911-08",
+ "System.Linq": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem": "4.4.0-beta-24911-08",
+ "System.Numerics.Vectors": "4.4.0-beta-24911-08",
+ "System.Reflection": "4.4.0-beta-24911-08",
+ "System.Reflection.Extensions": "4.4.0-beta-24911-08",
+ "System.Reflection.TypeExtensions": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Runtime.Numerics": "4.4.0-beta-24911-08",
+ "System.Text.RegularExpressions": "4.4.0-beta-24911-08",
+ "System.Threading": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks.Parallel": "4.4.0-beta-24911-08",
+ "System.Security.Cryptography.Algorithms": "4.4.0-beta-24911-08",
"xunit": "2.2.0-beta2-build3300",
"xunit.console.netcore": "1.0.2-prerelease-00177",
"xunit.runner.utility": "2.2.0-beta2-build3300"
"Microsoft.DotNet.xunit.performance": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.analysis": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.runner.Windows": "1.0.0-alpha-build0040",
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
"Newtonsoft.Json": "7.0.1",
- "System.Console": "4.4.0-beta-24906-02",
- "System.IO": "4.4.0-beta-24906-02",
- "System.IO.FileSystem": "4.4.0-beta-24906-02",
- "System.Linq": "4.4.0-beta-24906-02",
- "System.ObjectModel": "4.4.0-beta-24906-02",
- "System.Dynamic.Runtime": "4.4.0-beta-24906-02",
- "System.Reflection": "4.4.0-beta-24906-02",
- "System.Reflection.Extensions": "4.4.0-beta-24906-02",
- "System.Reflection.TypeExtensions": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.Serialization.Json": "4.4.0-beta-24906-02",
- "System.Runtime.Serialization.Primitives": "4.4.0-beta-24906-02",
- "System.Runtime.Serialization.Xml": "4.4.0-beta-24906-02",
- "System.Text.RegularExpressions": "4.4.0-beta-24906-02",
- "System.Xml.XmlDocument": "4.4.0-beta-24906-02",
- "System.Xml.XmlSerializer": "4.4.0-beta-24906-02",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.IO": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem": "4.4.0-beta-24911-08",
+ "System.Linq": "4.4.0-beta-24911-08",
+ "System.ObjectModel": "4.4.0-beta-24911-08",
+ "System.Dynamic.Runtime": "4.4.0-beta-24911-08",
+ "System.Reflection": "4.4.0-beta-24911-08",
+ "System.Reflection.Extensions": "4.4.0-beta-24911-08",
+ "System.Reflection.TypeExtensions": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.Serialization.Json": "4.4.0-beta-24911-08",
+ "System.Runtime.Serialization.Primitives": "4.4.0-beta-24911-08",
+ "System.Runtime.Serialization.Xml": "4.4.0-beta-24911-08",
+ "System.Text.RegularExpressions": "4.4.0-beta-24911-08",
+ "System.Xml.XmlDocument": "4.4.0-beta-24911-08",
+ "System.Xml.XmlSerializer": "4.4.0-beta-24911-08",
"xunit": "2.2.0-beta2-build3300",
"xunit.console.netcore": "1.0.2-prerelease-00177",
"xunit.runner.utility": "2.2.0-beta2-build3300"
"Microsoft.DotNet.xunit.performance": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.analysis": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.runner.Windows": "1.0.0-alpha-build0040",
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "System.Collections.NonGeneric": "4.4.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.IO.FileSystem": "4.4.0-beta-24906-02",
- "System.Linq": "4.4.0-beta-24906-02",
- "System.Linq.Expressions": "4.4.0-beta-24906-02",
- "System.Numerics.Vectors": "4.4.0-beta-24906-02",
- "System.Reflection": "4.4.0-beta-24906-02",
- "System.Reflection.Extensions": "4.4.0-beta-24906-02",
- "System.Reflection.TypeExtensions": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Runtime.Numerics": "4.4.0-beta-24906-02",
- "System.Text.RegularExpressions": "4.4.0-beta-24906-02",
- "System.Threading": "4.4.0-beta-24906-02",
- "System.Threading.Tasks": "4.4.0-beta-24906-02",
- "System.Threading.Tasks.Parallel": "4.4.0-beta-24906-02",
- "System.Diagnostics.Process": "4.4.0-beta-24906-02",
- "System.Xml.XmlDocument": "4.4.0-beta-24906-02",
- "System.Xml.XPath": "4.4.0-beta-24906-02",
- "System.Xml.XPath.XmlDocument": "4.4.0-beta-24906-02",
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "System.Collections.NonGeneric": "4.4.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem": "4.4.0-beta-24911-08",
+ "System.Linq": "4.4.0-beta-24911-08",
+ "System.Linq.Expressions": "4.4.0-beta-24911-08",
+ "System.Numerics.Vectors": "4.4.0-beta-24911-08",
+ "System.Reflection": "4.4.0-beta-24911-08",
+ "System.Reflection.Extensions": "4.4.0-beta-24911-08",
+ "System.Reflection.TypeExtensions": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Runtime.Numerics": "4.4.0-beta-24911-08",
+ "System.Text.RegularExpressions": "4.4.0-beta-24911-08",
+ "System.Threading": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks.Parallel": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Process": "4.4.0-beta-24911-08",
+ "System.Xml.XmlDocument": "4.4.0-beta-24911-08",
+ "System.Xml.XPath": "4.4.0-beta-24911-08",
+ "System.Xml.XPath.XmlDocument": "4.4.0-beta-24911-08",
"xunit": "2.2.0-beta2-build3300",
"xunit.console.netcore": "1.0.2-prerelease-00177",
"xunit.runner.utility": "2.2.0-beta2-build3300"
{
"dependencies": {
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "System.Collections": "4.4.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.Diagnostics.Debug": "4.4.0-beta-24906-02",
- "System.Runtime.InteropServices.RuntimeInformation": "4.4.0-beta-24906-02",
- "System.Diagnostics.Process": "4.4.0-beta-24906-02",
- "System.Globalization": "4.4.0-beta-24906-02",
- "System.IO": "4.4.0-beta-24906-02",
- "System.IO.FileSystem": "4.4.0-beta-24906-02",
- "System.Reflection": "4.4.0-beta-24906-02",
- "System.Reflection.Extensions": "4.4.0-beta-24906-02",
- "System.Reflection.TypeExtensions": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Runtime.CompilerServices.Unsafe": "4.4.0-beta-24906-02",
- "System.Runtime.InteropServices": "4.4.0-beta-24906-02"
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "System.Collections": "4.4.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Debug": "4.4.0-beta-24911-08",
+ "System.Runtime.InteropServices.RuntimeInformation": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Process": "4.4.0-beta-24911-08",
+ "System.Globalization": "4.4.0-beta-24911-08",
+ "System.IO": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem": "4.4.0-beta-24911-08",
+ "System.Reflection": "4.4.0-beta-24911-08",
+ "System.Reflection.Extensions": "4.4.0-beta-24911-08",
+ "System.Reflection.TypeExtensions": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Runtime.CompilerServices.Unsafe": "4.4.0-beta-24911-08",
+ "System.Runtime.InteropServices": "4.4.0-beta-24911-08"
},
"frameworks": {
"netcoreapp1.1": {}
{
"dependencies": {
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Runtime.InteropServices": "4.4.0-beta-24906-02"
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Runtime.InteropServices": "4.4.0-beta-24911-08"
},
"frameworks": {
"netcoreapp1.1": {}
{
"dependencies": {
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.Numerics.Vectors": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Threading": "4.4.0-beta-24906-02",
- "System.Threading.Thread": "4.4.0-beta-24906-02"
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.Numerics.Vectors": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Threading": "4.4.0-beta-24911-08",
+ "System.Threading.Thread": "4.4.0-beta-24911-08"
},
"frameworks": {
"netcoreapp1.1": {}
{
"dependencies": {
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Threading": "4.4.0-beta-24906-02"
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Threading": "4.4.0-beta-24911-08"
},
"frameworks": {
"netcoreapp1.1": {}
<PropertyGroup>
<DebugType>Full</DebugType>
<Optimize>True</Optimize>
+ <!-- This test is very resource heavy and doesn't play well with some JitStress modes, especially when memory is limited -->
+ <JitOptimizationSensitive Condition="'$(Platform)' == 'x86'">true</JitOptimizationSensitive>
</PropertyGroup>
<ItemGroup>
<Compile Include="hugeexpr1.cs" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
<PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
</PropertyGroup>
-</Project>
\ No newline at end of file
+</Project>
do
{
bool[,,,,][,] local8 = (new bool[81u, 98u, ((uint)(58.0f)), ((uint)(36.0f)),
- 74u][,]);
+ 74u*4u][,]);
while ((((uint)(local5)) != 4u))
{
if (Convert.ToBoolean((local5 + local5)))
"Microsoft.DotNet.xunit.performance": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.analysis": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.runner.Windows": "1.0.0-alpha-build0040",
- "Microsoft.NETCore.Platforms": "1.2.0-beta-24906-02",
- "System.Collections.NonGeneric": "4.4.0-beta-24906-02",
- "System.Console": "4.4.0-beta-24906-02",
- "System.IO.FileSystem": "4.4.0-beta-24906-02",
- "System.Linq": "4.4.0-beta-24906-02",
- "System.Linq.Expressions": "4.4.0-beta-24906-02",
- "System.Numerics.Vectors": "4.4.0-beta-24906-02",
- "System.Reflection": "4.4.0-beta-24906-02",
- "System.Reflection.Extensions": "4.4.0-beta-24906-02",
- "System.Reflection.TypeExtensions": "4.4.0-beta-24906-02",
- "System.Runtime": "4.4.0-beta-24906-02",
- "System.Runtime.Extensions": "4.4.0-beta-24906-02",
- "System.Runtime.Numerics": "4.4.0-beta-24906-02",
- "System.Text.RegularExpressions": "4.4.0-beta-24906-02",
- "System.Threading": "4.4.0-beta-24906-02",
- "System.Threading.Tasks": "4.4.0-beta-24906-02",
- "System.Threading.Tasks.Parallel": "4.4.0-beta-24906-02",
- "System.Diagnostics.Process": "4.4.0-beta-24906-02",
- "System.Xml.XmlDocument": "4.4.0-beta-24906-02",
- "System.Xml.XPath": "4.4.0-beta-24906-02",
- "System.Xml.XPath.XmlDocument": "4.4.0-beta-24906-02",
+ "Microsoft.NETCore.Platforms": "1.2.0-beta-24911-08",
+ "System.Collections.NonGeneric": "4.4.0-beta-24911-08",
+ "System.Console": "4.4.0-beta-24911-08",
+ "System.IO.FileSystem": "4.4.0-beta-24911-08",
+ "System.Linq": "4.4.0-beta-24911-08",
+ "System.Linq.Expressions": "4.4.0-beta-24911-08",
+ "System.Numerics.Vectors": "4.4.0-beta-24911-08",
+ "System.Reflection": "4.4.0-beta-24911-08",
+ "System.Reflection.Extensions": "4.4.0-beta-24911-08",
+ "System.Reflection.TypeExtensions": "4.4.0-beta-24911-08",
+ "System.Runtime": "4.4.0-beta-24911-08",
+ "System.Runtime.Extensions": "4.4.0-beta-24911-08",
+ "System.Runtime.Numerics": "4.4.0-beta-24911-08",
+ "System.Text.RegularExpressions": "4.4.0-beta-24911-08",
+ "System.Threading": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks": "4.4.0-beta-24911-08",
+ "System.Threading.Tasks.Parallel": "4.4.0-beta-24911-08",
+ "System.Diagnostics.Process": "4.4.0-beta-24911-08",
+ "System.Xml.XmlDocument": "4.4.0-beta-24911-08",
+ "System.Xml.XPath": "4.4.0-beta-24911-08",
+ "System.Xml.XPath.XmlDocument": "4.4.0-beta-24911-08",
"xunit": "2.2.0-beta2-build3300",
"xunit.console.netcore": "1.0.2-prerelease-00177",
"xunit.runner.utility": "2.2.0-beta2-build3300"