Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use preferred region from PAL for JIT reloc hints #60747

Merged
merged 4 commits into from
Oct 26, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions src/coreclr/inc/executableallocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,17 @@ class ExecutableAllocator
// Callback to the runtime to report fatal errors
static FatalErrorHandler g_fatalErrorHandler;

#if USE_UPPER_ADDRESS
// Preferred region to allocate the code in.
static BYTE* g_codeMinAddr;
static BYTE* g_codeMaxAddr;
static BYTE* g_codeAllocStart;
// Next address to try to allocate for code in the preferred region.
static BYTE* g_codeAllocHint;
#endif // USE_UPPER_ADDRESS
#if USE_LAZY_PREFERRED_RANGE
static BYTE* g_lazyPreferredRangeStart;
// Next address to try to allocate for code in the lazy preferred region.
static BYTE* g_lazyPreferredRangeHint;
#endif // USE_LAZY_PREFERRED_RANGE

// For PAL, this region represents the area that is eagerly reserved on
// startup where executable memory and static fields are preferrably kept.
// For Windows, this is the region that we lazily reserve from.
static BYTE* g_preferredRangeMin;
static BYTE* g_preferredRangeMax;

// Caches the COMPlus_EnableWXORX setting
static bool g_isWXorXEnabled;
Expand Down Expand Up @@ -154,14 +157,16 @@ class ExecutableAllocator
// Return true if W^X is enabled
static bool IsWXORXEnabled();

// Use this function to initialize the g_codeAllocHint
// during startup. base is runtime .dll base address,
// size is runtime .dll virtual size.
static void InitCodeAllocHint(size_t base, size_t size, int randomPageOffset);
// Use this function to initialize g_lazyPreferredRangeHint during startup.
// base is runtime .dll base address, size is runtime .dll virtual size.
static void InitLazyPreferredRange(size_t base, size_t size, int randomPageOffset);

// Use this function to reset the g_codeAllocHint
// after unloading an AppDomain
static void ResetCodeAllocHint();
// Use this function to reset g_lazyPreferredRangeHint after unloading code.
static void ResetLazyPreferredRangeHint();

// Use this function to initialize the preferred range of executable memory
// from PAL.
static void InitPreferredRange();

// Returns TRUE if p is located in near clr.dll that allows us
// to use rel32 IP-relative addressing modes.
Expand Down
18 changes: 9 additions & 9 deletions src/coreclr/inc/switches.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@
#endif

#if defined(TARGET_X86) || defined(TARGET_ARM)
#define USE_UPPER_ADDRESS 0
#define USE_LAZY_PREFERRED_RANGE 0

#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_S390X)
#define UPPER_ADDRESS_MAPPING_FACTOR 2
#define CLR_UPPER_ADDRESS_MIN 0x64400000000
#define CODEHEAP_START_ADDRESS 0x64480000000
#define CLR_UPPER_ADDRESS_MAX 0x644FC000000

#if !defined(HOST_UNIX)
#define USE_UPPER_ADDRESS 1
#if defined(HOST_UNIX)
// In PAL we have a smechanism that reserves memory on start up that is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// In PAL we have a smechanism that reserves memory on start up that is
// In PAL we have a mechanism that reserves memory on start up that is

// close to libcoreclr and intercepts calls to VirtualAlloc to serve back
// from this area.
#define USE_LAZY_PREFERRED_RANGE 0
#else
#define USE_UPPER_ADDRESS 0
#endif // !HOST_UNIX
// On Windows we lazily try to reserve memory close to coreclr.dll.
#define USE_LAZY_PREFERRED_RANGE 1
#endif

#else
#error Please add a new #elif clause and define all portability macros for the new platform
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/pal/inc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2743,6 +2743,13 @@ PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange(
IN LPCVOID lpEndAddress,
IN SIZE_T dwSize);

PALIMPORT
void
PALAPI
PAL_GetExecutableMemoryAllocatorReservedRange(
OUT PVOID *start,
OUT PVOID *end);

PALIMPORT
LPVOID
PALAPI
Expand Down
14 changes: 10 additions & 4 deletions src/coreclr/pal/src/include/pal/virtual.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ class ExecutableMemoryAllocator
--*/
void *AllocateMemoryWithinRange(const void *beginAddress, const void *endAddress, SIZE_T allocationSize);

void GetReservedRange(void **start, void **end)
{
*start = m_startAddress;
*end = (void*)((char*)m_startAddress + m_totalSizeOfReservedMemory);
}

private:
/*++
Function:
Expand Down Expand Up @@ -179,17 +185,17 @@ class ExecutableMemoryAllocator
static const int32_t MaxExecutableMemorySizeNearCoreClr = MaxExecutableMemorySize - CoreClrLibrarySize;

// Start address of the reserved virtual address space
void* m_startAddress;
void* m_startAddress = NULL;
jakobbotsch marked this conversation as resolved.
Show resolved Hide resolved

// Next available address in the reserved address space
void* m_nextFreeAddress;
void* m_nextFreeAddress = NULL;

// Total size of the virtual memory that the allocator has been able to
// reserve during its initialization.
int32_t m_totalSizeOfReservedMemory;
int32_t m_totalSizeOfReservedMemory = 0;

// Remaining size of the reserved virtual memory that can be used to satisfy allocation requests.
int32_t m_remainingReservedMemory;
int32_t m_remainingReservedMemory = 0;
};

#endif // __cplusplus
Expand Down
24 changes: 19 additions & 5 deletions src/coreclr/pal/src/map/virtual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,25 @@ PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange(
#endif // HOST_64BIT
}

/*++
Function:
PAL_GetExecutableMemoryAllocatorReservedRange

This function gets the reserved range allocated by the executable memory allocator.

lpBeginAddress - Inclusive beginning of range
lpEndAddress - Exclusive end of range
dwSize - Number of bytes to allocate
--*/
void
PALAPI
PAL_GetExecutableMemoryAllocatorReservedRange(
OUT LPVOID *start,
OUT LPVOID *end)
{
g_executableMemoryAllocator.GetReservedRange(start, end);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we combine it with the libcoreclr.so range (using real base and the guesstimate CoreClrLibrarySize as a size)? In case there was a space in between, we could pretend it is not there. I think that without it, calls to helpers in it would not be optimized, or would they?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We always assume we can do rip-relative calls and the runtime will generate jump stubs if necessary, so calls to helpers already work out well with the current scheme. The question is if we ever bake in static addresses in coreclr.dll as part of jitted code -- those could not be contained without what you suggest. I can try to make this change tomorrow or Monday and see if there are any additional diffs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That further helps, we sometime call helpers through indirections of static variables stored in coreclr.dll:

// To avoid using a jump stub we always call certain helpers using an indirect call.
// Because when using a direct call and the target is father away than 2^31 bytes,
// the direct call instead goes to a jump stub which jumps to the jit helper.
// However in this process the jump stub will corrupt RAX.
//
// The set of helpers for which RAX must be preserved are the profiler probes
// and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
// In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
//
if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
{
_ASSERTE(ppIndirection != NULL);
*ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
return NULL;
}

In particular CORINFO_HELP_STOP_FOR_GC is one that has quite a few hits. That furthermore is conditional based on a static variable, so each site changes like this:

 G_M40601_IG08:
        mov      byte  ptr [rbx+12], 1
-       mov      rdi, 0xD1FFAB1E
-       cmp      dword ptr [rdi], 0
+       cmp      dword ptr [(reloc)], 0
        je       SHORT G_M40601_IG09
-       mov      rsi, 0xD1FFAB1E
-       call     [rsi]CORINFO_HELP_STOP_FOR_GC
-                                               ;; bbWeight=0.50 PerfScore 4.25
+       call     [CORINFO_HELP_STOP_FOR_GC]
+                                               ;; bbWeight=0.50 PerfScore 4.00

The additional diffs are:

Summary of Code Size diffs:
(Lower is better)

Total bytes of base: 59803609
Total bytes of diff: 59772903
Total bytes of delta: -30706 (-0.05 % of base)
Total relative delta: NaN
    diff is an improvement.
    relative diff is a regression.


Top file improvements (bytes):
       -7410 : System.Private.CoreLib.dasm (-0.13 % of base)
       -4853 : System.Drawing.Common.dasm (-1.26 % of base)
       -1946 : System.Security.Cryptography.Algorithms.dasm (-0.49 % of base)
       -1170 : System.Security.Cryptography.X509Certificates.dasm (-0.32 % of base)
       -1026 : System.Net.Security.dasm (-0.57 % of base)
        -895 : System.Net.Sockets.dasm (-0.40 % of base)
        -876 : System.Diagnostics.Process.dasm (-0.98 % of base)
        -852 : System.DirectoryServices.Protocols.dasm (-0.72 % of base)
        -772 : System.Security.Cryptography.OpenSsl.dasm (-0.69 % of base)
        -713 : System.Console.dasm (-0.92 % of base)
        -686 : Microsoft.Diagnostics.Tracing.TraceEvent.dasm (-0.02 % of base)
        -618 : System.Private.Xml.dasm (-0.02 % of base)
        -540 : System.Data.Odbc.dasm (-0.25 % of base)
        -528 : System.IO.Ports.dasm (-1.13 % of base)
        -474 : System.IO.Pipes.dasm (-1.22 % of base)
        -450 : System.Reflection.MetadataLoadContext.dasm (-0.20 % of base)
        -449 : System.IO.MemoryMappedFiles.dasm (-2.12 % of base)
        -415 : System.Net.Primitives.dasm (-0.55 % of base)
        -402 : System.Net.Mail.dasm (-0.21 % of base)
        -378 : System.Net.Http.dasm (-0.05 % of base)

74 total files with Code Size differences (74 improved, 0 regressed), 198 unchanged.

Top method regressions (bytes):
           9 (0.10 % of base) : System.Private.Xml.dasm - <GetTokenAsync>d__173:MoveNext():this

Top method improvements (bytes):
        -300 (-6.46 % of base) : System.Drawing.Common.dasm - ILStubClass:IL_STUB_PInvoke(System.Runtime.InteropServices.HandleRef,byref):int (25 methods)
        -258 (-12.48 % of base) : System.Reflection.MetadataLoadContext.dasm - System.Reflection.TypeLoading.CoreTypeHelpers:GetFullName(int,byref,byref)
        -192 (-6.90 % of base) : System.Drawing.Common.dasm - ILStubClass:IL_STUB_PInvoke(System.Runtime.InteropServices.HandleRef,int):int (16 methods)
        -144 (-9.59 % of base) : System.Security.Cryptography.Algorithms.dasm - Internal.Cryptography.AesImplementation:GetAlgorithm(int,int,int):long
        -132 (-8.67 % of base) : System.Drawing.Common.dasm - System.Drawing.MacSupport:GetCGContextForView(long):System.Drawing.CarbonContext
        -120 (-6.78 % of base) : System.Drawing.Common.dasm - ILStubClass:IL_STUB_PInvoke(long,byref):int (10 methods)
        -100 (-4.54 % of base) : System.Drawing.Common.dasm - System.Drawing.Graphics:CopyFromScreenX11(int,int,int,int,System.Drawing.Size,int):this
         -72 (-8.14 % of base) : System.Private.CoreLib.dasm - ILStubClass:IL_STUB_PInvoke():long (7 methods)
         -72 (-7.19 % of base) : System.Private.CoreLib.dasm - ILStubClass:IL_STUB_PInvoke(long,long):int (6 methods)
         -72 (-7.87 % of base) : System.Private.CoreLib.dasm - ILStubClass:IL_STUB_PInvoke(long) (7 methods)
         -72 (-3.43 % of base) : System.DirectoryServices.Protocols.dasm - ILStubClass:IL_STUB_PInvoke(System.DirectoryServices.Protocols.ConnectionHandle,int,byref):int (6 methods)
         -72 (-5.97 % of base) : System.Drawing.Common.dasm - ILStubClass:IL_STUB_PInvoke(System.Runtime.InteropServices.HandleRef,byref,byref):int (6 methods)
         -72 (-6.78 % of base) : System.Drawing.Common.dasm - ILStubClass:IL_STUB_PInvoke(System.Runtime.InteropServices.HandleRef,long,int):int (6 methods)
         -66 (-7.39 % of base) : System.Net.Sockets.dasm - ILStubClass:IL_STUB_PInvoke(long,long):int (6 methods)
         -60 (-7.19 % of base) : System.Private.CoreLib.dasm - ILStubClass:IL_STUB_PInvoke(long,int):int (5 methods)
         -60 (-7.19 % of base) : System.Security.Cryptography.X509Certificates.dasm - ILStubClass:IL_STUB_PInvoke(long,long):int (5 methods)
         -60 (-7.45 % of base) : System.Private.CoreLib.dasm - ILStubClass:IL_STUB_PInvoke(long):long (5 methods)
         -60 (-5.91 % of base) : System.Drawing.Common.dasm - ILStubClass:IL_STUB_PInvoke(System.Runtime.InteropServices.HandleRef,System.Runtime.InteropServices.HandleRef,byref):int (5 methods)
         -60 (-7.87 % of base) : System.Drawing.Common.dasm - System.Drawing.MacSupport:GetCGContextForNSView(long):System.Drawing.CocoaContext
         -54 (-8.06 % of base) : System.Private.CoreLib.dasm - ILStubClass:IL_STUB_PInvoke():int (5 methods)

Top method regressions (percentages):
           9 (0.10 % of base) : System.Private.Xml.dasm - <GetTokenAsync>d__173:MoveNext():this

Top method improvements (percentages):
          -9 (-22.50 % of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:SetLastSystemError(int)
          -9 (-21.95 % of base) : System.Private.CoreLib.dasm - System.Diagnostics.Stopwatch:GetTimestamp():long
          -9 (-21.95 % of base) : System.Private.CoreLib.dasm - System.Diagnostics.Stopwatch:QueryPerformanceCounter():long
          -9 (-21.95 % of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:GetLastSystemError():int
          -9 (-20.93 % of base) : System.Net.NameResolution.dasm - Microsoft.Extensions.Internal.ValueStopwatch:StartNew():Microsoft.Extensions.Internal.ValueStopwatch
          -9 (-20.93 % of base) : System.Net.Http.dasm - Microsoft.Extensions.Internal.ValueStopwatch:StartNew():Microsoft.Extensions.Internal.ValueStopwatch
          -9 (-20.93 % of base) : System.Net.Security.dasm - Microsoft.Extensions.Internal.ValueStopwatch:StartNew():Microsoft.Extensions.Internal.ValueStopwatch
          -9 (-20.93 % of base) : Microsoft.Extensions.Http.dasm - Microsoft.Extensions.Internal.ValueStopwatch:StartNew():Microsoft.Extensions.Internal.ValueStopwatch
          -9 (-19.15 % of base) : System.Diagnostics.Process.dasm - System.Diagnostics.Process:SetDelayedSigChildConsoleConfigurationHandler()
          -3 (-18.75 % of base) : System.Net.Http.dasm - Http2Stream:get_StatusHeaderName():System.ReadOnlySpan`1[Byte]
          -3 (-18.75 % of base) : Microsoft.Extensions.DependencyModel.dasm - Microsoft.Extensions.DependencyModel.DependencyContextJsonReader:get_Utf8Bom():System.ReadOnlySpan`1[Byte]
          -9 (-18.75 % of base) : System.IO.FileSystem.Watcher.dasm - Sys:GetLastError():int
          -9 (-18.75 % of base) : System.Private.CoreLib.dasm - Sys:GetLastError():int
          -9 (-18.75 % of base) : System.Diagnostics.Process.dasm - Sys:GetLastError():int
          -9 (-18.75 % of base) : System.Net.Sockets.dasm - Sys:GetLastError():int
          -3 (-18.75 % of base) : System.Memory.dasm - System.Buffers.Text.Base64:get_DecodingMap():System.ReadOnlySpan`1[SByte]
          -3 (-18.75 % of base) : System.Memory.dasm - System.Buffers.Text.Base64:get_EncodingMap():System.ReadOnlySpan`1[Byte]
          -3 (-18.75 % of base) : System.Drawing.Common.dasm - System.Drawing.ImageConverter:get_BMBytes():System.ReadOnlySpan`1[Byte]
          -3 (-18.75 % of base) : System.Drawing.Common.dasm - System.Drawing.ImageConverter:get_PBrush():System.ReadOnlySpan`1[Byte]
          -3 (-18.75 % of base) : System.Drawing.Primitives.dasm - System.Drawing.KnownColorTable:get_ColorKindTable():System.ReadOnlySpan`1[Byte]

2330 total methods with Code Size differences (2329 improved, 1 regressed), 366469 unchanged.

--------------------------------------------------------------------------------

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed the change, can you take another look please?

}

/*++
Function:
VirtualAlloc
Expand Down Expand Up @@ -2093,11 +2112,6 @@ void* ReserveMemoryFromExecutableAllocator(CPalThread* pThread, SIZE_T allocatio
--*/
void ExecutableMemoryAllocator::Initialize()
{
m_startAddress = NULL;
m_nextFreeAddress = NULL;
m_totalSizeOfReservedMemory = 0;
m_remainingReservedMemory = 0;

// Enable the executable memory allocator on 64-bit platforms only
// because 32-bit platforms have limited amount of virtual address space.
#ifdef HOST_64BIT
Expand Down
104 changes: 46 additions & 58 deletions src/coreclr/utilcode/executableallocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
#include "pedecoder.h"
#include "executableallocator.h"

#if USE_UPPER_ADDRESS
#if USE_LAZY_PREFERRED_RANGE
// Preferred region to allocate the code in.
BYTE * ExecutableAllocator::g_codeMinAddr;
BYTE * ExecutableAllocator::g_codeMaxAddr;
BYTE * ExecutableAllocator::g_codeAllocStart;
BYTE * ExecutableAllocator::g_lazyPreferredRangeStart;
// Next address to try to allocate for code in the preferred region.
BYTE * ExecutableAllocator::g_codeAllocHint;
#endif // USE_UPPER_ADDRESS
BYTE * ExecutableAllocator::g_lazyPreferredRangeHint;
#endif // USE_LAZY_PREFERRED_RANGE

BYTE * ExecutableAllocator::g_preferredRangeMin;
BYTE * ExecutableAllocator::g_preferredRangeMax;

bool ExecutableAllocator::g_isWXorXEnabled = false;

Expand Down Expand Up @@ -50,12 +51,9 @@ size_t ExecutableAllocator::Granularity()
return g_SystemInfo.dwAllocationGranularity;
}

// Use this function to initialize the g_codeAllocHint
// during startup. base is runtime .dll base address,
// size is runtime .dll virtual size.
void ExecutableAllocator::InitCodeAllocHint(size_t base, size_t size, int randomPageOffset)
void ExecutableAllocator::InitLazyPreferredRange(size_t base, size_t size, int randomPageOffset)
{
#if USE_UPPER_ADDRESS
#if USE_LAZY_PREFERRED_RANGE

#ifdef _DEBUG
// If GetForceRelocs is enabled we don't constrain the pMinAddr
Expand All @@ -64,39 +62,25 @@ void ExecutableAllocator::InitCodeAllocHint(size_t base, size_t size, int random
#endif

//
// If we are using the UPPER_ADDRESS space (on Win64)
// then for any code heap that doesn't specify an address
// range using [pMinAddr..pMaxAddr] we place it in the
// upper address space
// This enables us to avoid having to use long JumpStubs
// to reach the code for our ngen-ed images.
// Which are also placed in the UPPER_ADDRESS space.
// If we are using USE_LAZY_PREFERRED_RANGE then we try to allocate memory close
// to coreclr.dll. This avoids having to create jump stubs for calls to
// helpers and R2R images loaded close to coreclr.dll.
//
SIZE_T reach = 0x7FFF0000u;

// We will choose the preferred code region based on the address of clr.dll. The JIT helpers
// in clr.dll are the most heavily called functions.
g_codeMinAddr = (base + size > reach) ? (BYTE *)(base + size - reach) : (BYTE *)0;
g_codeMaxAddr = (base + reach > base) ? (BYTE *)(base + reach) : (BYTE *)-1;
// We will choose the preferred code region based on the address of coreclr.dll. The JIT helpers
// in coreclr.dll are the most heavily called functions.
g_preferredRangeMin = (base + size > reach) ? (BYTE *)(base + size - reach) : (BYTE *)0;
g_preferredRangeMax = (base + reach > base) ? (BYTE *)(base + reach) : (BYTE *)-1;

BYTE * pStart;

if (g_codeMinAddr <= (BYTE *)CODEHEAP_START_ADDRESS &&
(BYTE *)CODEHEAP_START_ADDRESS < g_codeMaxAddr)
{
// clr.dll got loaded at its preferred base address? (OS without ASLR - pre-Vista)
// Use the code head start address that does not cause collisions with NGen images.
// This logic is coupled with scripts that we use to assign base addresses.
pStart = (BYTE *)CODEHEAP_START_ADDRESS;
}
else
if (base > UINT32_MAX)
{
// clr.dll got address assigned by ASLR?
// Try to occupy the space as far as possible to minimize collisions with other ASLR assigned
// addresses. Do not start at g_codeMinAddr exactly so that we can also reach common native images
// that can be placed at higher addresses than clr.dll.
pStart = g_codeMinAddr + (g_codeMaxAddr - g_codeMinAddr) / 8;
// that can be placed at higher addresses than coreclr.dll.
pStart = g_preferredRangeMin + (g_preferredRangeMax - g_preferredRangeMin) / 8;
}
else
{
Expand All @@ -108,31 +92,35 @@ void ExecutableAllocator::InitCodeAllocHint(size_t base, size_t size, int random
// Randomize the address space
pStart += GetOsPageSize() * randomPageOffset;

g_codeAllocStart = pStart;
g_codeAllocHint = pStart;
g_lazyPreferredRangeStart = pStart;
g_lazyPreferredRangeHint = pStart;
#endif
}

// Use this function to reset the g_codeAllocHint
// after unloading an AppDomain
void ExecutableAllocator::ResetCodeAllocHint()
void ExecutableAllocator::InitPreferredRange()
{
LIMITED_METHOD_CONTRACT;
#if USE_UPPER_ADDRESS
g_codeAllocHint = g_codeAllocStart;
#ifdef TARGET_UNIX
void *start, *end;
PAL_GetExecutableMemoryAllocatorReservedRange(&start, &end);
g_preferredRangeMin = (BYTE *)start;
g_preferredRangeMax = (BYTE *)end;
#endif
}

// Returns TRUE if p is located in near clr.dll that allows us
// to use rel32 IP-relative addressing modes.
bool ExecutableAllocator::IsPreferredExecutableRange(void * p)
void ExecutableAllocator::ResetLazyPreferredRangeHint()
{
LIMITED_METHOD_CONTRACT;
#if USE_UPPER_ADDRESS
if (g_codeMinAddr <= (BYTE *)p && (BYTE *)p < g_codeMaxAddr)
return true;
#if USE_LAZY_PREFERRED_RANGE
g_lazyPreferredRangeHint = g_lazyPreferredRangeStart;
#endif
return false;
}
// Returns TRUE if p is is located in the memory area where we prefer to put
// executable code and static fields. This area is typically close to the
// coreclr library.
bool ExecutableAllocator::IsPreferredExecutableRange(void * p)
{
LIMITED_METHOD_CONTRACT;
return g_preferredRangeMin <= (BYTE *)p && (BYTE *)p < g_preferredRangeMax;
}

ExecutableAllocator* ExecutableAllocator::Instance()
Expand Down Expand Up @@ -553,7 +541,7 @@ void* ExecutableAllocator::Reserve(size_t size)

BYTE *result = NULL;

#if USE_UPPER_ADDRESS
#if USE_LAZY_PREFERRED_RANGE
//
// If we are using the UPPER_ADDRESS space (on Win64)
// then for any heap that will contain executable code
Expand All @@ -563,32 +551,32 @@ void* ExecutableAllocator::Reserve(size_t size)
// to reach the code for our ngen-ed images on x64,
// since they are also placed in the UPPER_ADDRESS space.
//
BYTE * pHint = g_codeAllocHint;
BYTE * pHint = g_lazyPreferredRangeHint;

if (size <= (SIZE_T)(g_codeMaxAddr - g_codeMinAddr) && pHint != NULL)
if (size <= (SIZE_T)(g_preferredRangeMax - g_preferredRangeMin) && pHint != NULL)
{
// Try to allocate in the preferred region after the hint
result = (BYTE*)ReserveWithinRange(size, pHint, g_codeMaxAddr);
result = (BYTE*)ReserveWithinRange(size, pHint, g_preferredRangeMax);
if (result != NULL)
{
g_codeAllocHint = result + size;
g_lazyPreferredRangeHint = result + size;
}
else
{
// Try to allocate in the preferred region before the hint
result = (BYTE*)ReserveWithinRange(size, g_codeMinAddr, pHint + size);
result = (BYTE*)ReserveWithinRange(size, g_preferredRangeMin, pHint + size);

if (result != NULL)
{
g_codeAllocHint = result + size;
g_lazyPreferredRangeHint = result + size;
}

g_codeAllocHint = NULL;
g_lazyPreferredRangeHint = NULL;
}
}

// Fall through to
#endif // USE_UPPER_ADDRESS
#endif // USE_LAZY_PREFERRED_RANGE

if (result == NULL)
{
Expand Down
8 changes: 5 additions & 3 deletions src/coreclr/vm/ceemain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,14 +808,16 @@ void EEStartupHelper()

StubManager::InitializeStubManagers();

#ifndef TARGET_UNIX
#ifdef TARGET_UNIX
ExecutableAllocator::InitPreferredRange();
#else
{
// Record mscorwks geometry
// Record coreclr.dll geometry
PEDecoder pe(GetClrModuleBase());

g_runtimeLoadedBaseAddress = (SIZE_T)pe.GetBase();
g_runtimeVirtualSize = (SIZE_T)pe.GetVirtualSize();
ExecutableAllocator::InitCodeAllocHint(g_runtimeLoadedBaseAddress, g_runtimeVirtualSize, GetRandomInt(64));
ExecutableAllocator::InitLazyPreferredRange(g_runtimeLoadedBaseAddress, g_runtimeVirtualSize, GetRandomInt(64));
}
#endif // !TARGET_UNIX

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/codeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3343,7 +3343,7 @@ void EEJitManager::Unload(LoaderAllocator *pAllocator)
}
}

ExecutableAllocator::ResetCodeAllocHint();
ExecutableAllocator::ResetLazyPreferredRangeHint();
}

EEJitManager::DomainCodeHeapList::DomainCodeHeapList()
Expand Down
Loading