diff options
author | Koundinya Veluri <kouvel@microsoft.com> | 2017-03-01 20:52:15 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-01 20:52:15 -0800 |
commit | 4bafc1004b99013eaa58450e4f974dc7169b5af1 (patch) | |
tree | c0238dcc72437a366a7f96e1aa5af4d5bc87e365 /tests/src/CoreMangLib/cti/system | |
parent | 1bf3bbb44397875e94ae95b8527fd1928b5373fe (diff) | |
download | coreclr-4bafc1004b99013eaa58450e4f974dc7169b5af1.tar.gz coreclr-4bafc1004b99013eaa58450e4f974dc7169b5af1.tar.bz2 coreclr-4bafc1004b99013eaa58450e4f974dc7169b5af1.zip |
Preallocate jump stubs for dynamic methods (#9883)
Preallocate jump stubs for dynamic methods
- This eliminates the possibility of running into an out-of-memory situation after compiling the method
- The temporary entry points block containing FixupPrecodes is extended for dynamic methods to include sufficient space for jump stubs
- When the target is too far for the FixupPrecode to encode a short relative jump, it instead does a short relative call or jump to the corresponding jump stub, which does an absolute jump to the target
Diffstat (limited to 'tests/src/CoreMangLib/cti/system')
2 files changed, 157 insertions, 0 deletions
diff --git a/tests/src/CoreMangLib/cti/system/reflection/emit/DynMethodJumpStubTests/DynMethodJumpStubTests.cs b/tests/src/CoreMangLib/cti/system/reflection/emit/DynMethodJumpStubTests/DynMethodJumpStubTests.cs new file mode 100644 index 0000000000..1dc717d884 --- /dev/null +++ b/tests/src/CoreMangLib/cti/system/reflection/emit/DynMethodJumpStubTests/DynMethodJumpStubTests.cs @@ -0,0 +1,136 @@ +// 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.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using System.Threading; + +public static class DynamicMethodJumpStubTests +{ + private static int Main() + { + DynamicMethodJumpStubTest(); + return 100; + } + + public static void DynamicMethodJumpStubTest() + { + if (!Environment.Is64BitProcess) + { + return; + } + + // Reserve memory around framework libraries. This is just a best attempt, it typically doesn't help since the + // precode allocator may have already committed pages it can allocate from, or it may commit reserved pages close to + // framework libraries. + ReserveMemoryAround(new Action(ExecutionContext.RestoreFlow).Method.MethodHandle); + + for (int i = 0; i < 64; ++i) + { + DynamicMethod dynamicMethod = CreateDynamicMethod("DynMethod" + i); + Action dynamicMethodDelegate = (Action)dynamicMethod.CreateDelegate(typeof(Action)); + + // Before compiling the dynamic method, reserve memory around its current entry point, which should be its + // precode. Then, when compiling the method, there would be a good chance that the code will be located far from + // the precode, forcing the use of a jump stub. + ReserveMemoryAround( + (RuntimeMethodHandle) + typeof(DynamicMethod).InvokeMember( + "GetMethodDescriptor", + BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, + null, + dynamicMethod, + null)); + + dynamicMethodDelegate(); + } + + // This test does not release reserved pages because they may have been committed by other components on the system + } + + private static DynamicMethod CreateDynamicMethod(string name) + { + var dynamicMethod = new DynamicMethod(name, null, null); + ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); + ilGenerator.Emit(OpCodes.Ret); + return dynamicMethod; + } + + private const uint AllocationGranularity = (uint)64 << 10; + private const ulong ReserveRangeRadius = (ulong)4 << 30; // reserve 4 GB before and after the base address + + private static void ReserveMemoryAround(RuntimeMethodHandle methodHandle) + { + ulong baseAddress = (ulong)methodHandle.Value.ToInt64(); + + ulong low = baseAddress - ReserveRangeRadius; + if (low > baseAddress) + { + low = ulong.MinValue; + } + else + { + low &= ~((ulong)AllocationGranularity - 1); + } + + ulong high = baseAddress + ReserveRangeRadius; + if (high < baseAddress) + { + high = ulong.MaxValue; + } + + ulong address = low; + while (address <= high) + { + VirtualAlloc( + new UIntPtr(address), + new UIntPtr(AllocationGranularity), + AllocationType.RESERVE, + MemoryProtection.NOACCESS); + + if (address + AllocationGranularity < address) + { + break; + } + address += AllocationGranularity; + } + } + + [Flags] + private enum AllocationType : uint + { + COMMIT = 0x1000, + RESERVE = 0x2000, + RESET = 0x80000, + LARGE_PAGES = 0x20000000, + PHYSICAL = 0x400000, + TOP_DOWN = 0x100000, + WRITE_WATCH = 0x200000 + } + + [Flags] + private enum MemoryProtection : uint + { + EXECUTE = 0x10, + EXECUTE_READ = 0x20, + EXECUTE_READWRITE = 0x40, + EXECUTE_WRITECOPY = 0x80, + NOACCESS = 0x01, + READONLY = 0x02, + READWRITE = 0x04, + WRITECOPY = 0x08, + GUARD_Modifierflag = 0x100, + NOCACHE_Modifierflag = 0x200, + WRITECOMBINE_Modifierflag = 0x400 + } + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern UIntPtr VirtualAlloc( + UIntPtr lpAddress, + UIntPtr dwSize, + AllocationType flAllocationType, + MemoryProtection flProtect); +} diff --git a/tests/src/CoreMangLib/cti/system/reflection/emit/DynMethodJumpStubTests/DynMethodJumpStubTests.csproj b/tests/src/CoreMangLib/cti/system/reflection/emit/DynMethodJumpStubTests/DynMethodJumpStubTests.csproj new file mode 100644 index 0000000000..65b8359d18 --- /dev/null +++ b/tests/src/CoreMangLib/cti/system/reflection/emit/DynMethodJumpStubTests/DynMethodJumpStubTests.csproj @@ -0,0 +1,21 @@ +<?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)' == '' ">x64</Platform> + <AssemblyName>DynMethodJumpStubTests</AssemblyName> + <ProjectGuid>{742D9E05-668D-4B90-97F9-717A7572FE6C}</ProjectGuid> + <OutputType>Exe</OutputType> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <Compile Include="DynMethodJumpStubTests.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> |