RETURN(mem);
}
-CodeHeader* EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag
+void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, CodeHeader** ppCodeHeader, CodeHeader** ppCodeHeaderRW,
+ size_t* pAllocatedSize, HeapList** ppCodeHeap
+#ifdef USE_INDIRECT_CODEHEADER
+ , BYTE** ppRealHeader
+#endif
#ifdef FEATURE_EH_FUNCLETS
- , UINT nUnwindInfos
- , TADDR * pModuleBase
+ , UINT nUnwindInfos
#endif
- )
+ )
{
- CONTRACT(CodeHeader *) {
+ CONTRACTL {
THROWS;
GC_NOTRIGGER;
- POSTCONDITION(CheckPointer(RETVAL));
- } CONTRACT_END;
+ } CONTRACTL_END;
//
// Alignment
SIZE_T totalSize = blockSize;
CodeHeader * pCodeHdr = NULL;
+ CodeHeader * pCodeHdrRW = NULL;
CodeHeapRequestInfo requestInfo(pMD);
#if defined(FEATURE_JIT_PITCHING)
{
CrstHolder ch(&m_CodeHeapCritSec);
- HeapList *pCodeHeap = NULL;
-
- TADDR pCode = (TADDR) allocCodeRaw(&requestInfo, sizeof(CodeHeader), totalSize, alignment, &pCodeHeap);
-
- _ASSERTE(pCodeHeap);
+ *ppCodeHeap = NULL;
+ TADDR pCode = (TADDR) allocCodeRaw(&requestInfo, sizeof(CodeHeader), totalSize, alignment, ppCodeHeap);
+ _ASSERTE(*ppCodeHeap);
if (pMD->IsLCGMethod())
{
_ASSERTE(IS_ALIGNED(pCode, alignment));
- // Initialize the CodeHeader *BEFORE* we publish this code range via the nibble
- // map so that we don't have to harden readers against uninitialized data.
- // However because we hold the lock, this initialization should be fast and cheap!
-
pCodeHdr = ((CodeHeader *)pCode) - 1;
+ *pAllocatedSize = sizeof(CodeHeader) + totalSize;
+#ifdef FEATURE_WXORX
+ pCodeHdrRW = (CodeHeader *)new BYTE[*pAllocatedSize];
+#else
+ pCodeHdrRW = pCodeHdr;
+#endif
+
#ifdef USE_INDIRECT_CODEHEADER
if (requestInfo.IsDynamicDomain())
{
- pCodeHdr->SetRealCodeHeader((BYTE*)pCode + ALIGN_UP(blockSize, sizeof(void*)));
+ // Set the real code header to the writeable mapping so that we can set its members via the CodeHeader methods below
+ pCodeHdrRW->SetRealCodeHeader((BYTE *)(pCodeHdrRW + 1) + ALIGN_UP(blockSize, sizeof(void*)));
}
else
{
//
// allocate the real header in the low frequency heap
BYTE* pRealHeader = (BYTE*)(void*)pMD->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(realHeaderSize));
- pCodeHdr->SetRealCodeHeader(pRealHeader);
+ pCodeHdrRW->SetRealCodeHeader(pRealHeader);
}
#endif
- pCodeHdr->SetDebugInfo(NULL);
- pCodeHdr->SetEHInfo(NULL);
- pCodeHdr->SetGCInfo(NULL);
- pCodeHdr->SetMethodDesc(pMD);
+ pCodeHdrRW->SetDebugInfo(NULL);
+ pCodeHdrRW->SetEHInfo(NULL);
+ pCodeHdrRW->SetGCInfo(NULL);
+ pCodeHdrRW->SetMethodDesc(pMD);
#ifdef FEATURE_EH_FUNCLETS
- pCodeHdr->SetNumberOfUnwindInfos(nUnwindInfos);
- *pModuleBase = pCodeHeap->GetModuleBase();
+ pCodeHdrRW->SetNumberOfUnwindInfos(nUnwindInfos);
#endif
- NibbleMapSet(pCodeHeap, pCode, TRUE);
+#ifdef USE_INDIRECT_CODEHEADER
+ if (requestInfo.IsDynamicDomain())
+ {
+ *ppRealHeader = (BYTE*)pCode + ALIGN_UP(blockSize, sizeof(void*));
+ }
+ else
+ {
+ *ppRealHeader = NULL;
+ }
+#endif // USE_INDIRECT_CODEHEADER
}
- RETURN(pCodeHdr);
+ *ppCodeHeader = pCodeHdr;
+ *ppCodeHeaderRW = pCodeHdrRW;
}
EEJitManager::DomainCodeHeapList *EEJitManager::GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly)
CodeHeader * pCodeHdr = (CodeHeader *) (mem - sizeof(CodeHeader));
pCodeHdr->SetStubCodeBlockKind(STUB_CODE_BLOCK_JUMPSTUB);
- NibbleMapSet(pCodeHeap, mem, TRUE);
+ NibbleMapSetUnlocked(pCodeHeap, mem, TRUE);
pBlock = (JumpStubBlockHeader *)mem;
CodeHeader * pCodeHdr = (CodeHeader *) (mem - sizeof(CodeHeader));
pCodeHdr->SetStubCodeBlockKind(kind);
- NibbleMapSet(pCodeHeap, mem, TRUE);
+ NibbleMapSetUnlocked(pCodeHeap, mem, TRUE);
// Record the jump stub reservation
pCodeHeap->reserveForJumpStubs += requestInfo.getReserveForJumpStubs();
if (pHp == NULL)
return;
- NibbleMapSet(pHp, (TADDR)(pCHdr + 1), FALSE);
+ NibbleMapSetUnlocked(pHp, (TADDR)(pCHdr + 1), FALSE);
}
// Backout the GCInfo
// so pCodeHeap can only be a HostCodeHeap.
// clean up the NibbleMap
- NibbleMapSet(pCodeHeap->m_pHeapList, (TADDR)codeStart, FALSE);
+ NibbleMapSetUnlocked(pCodeHeap->m_pHeapList, (TADDR)codeStart, FALSE);
// The caller of this method doesn't call HostCodeHeap->FreeMemForCode
// directly because the operation should be protected by m_CodeHeapCritSec.
}
#if !defined(DACCESS_COMPILE)
+
void EEJitManager::NibbleMapSet(HeapList * pHp, TADDR pCode, BOOL bSet)
{
CONTRACTL {
GC_NOTRIGGER;
} CONTRACTL_END;
+ CrstHolder ch(&m_CodeHeapCritSec);
+ NibbleMapSetUnlocked(pHp, pCode, bSet);
+}
+
+void EEJitManager::NibbleMapSetUnlocked(HeapList * pHp, TADDR pCode, BOOL bSet)
+{
+ CONTRACTL {
+ NOTHROW;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
// Currently all callers to this method ensure EEJitManager::m_CodeHeapCritSec
// is held.
_ASSERTE(m_CodeHeapCritSec.OwnedByCurrentThread());
// The number of code heaps at which we increase the size of new code heaps.
#define CODE_HEAP_SIZE_INCREASE_THRESHOLD 5
-typedef DPTR(struct _HeapList) PTR_HeapList;
+typedef DPTR(struct HeapList) PTR_HeapList;
-typedef struct _HeapList
+struct HeapList
{
PTR_HeapList hpNext;
void SetNext(PTR_HeapList next)
{ hpNext = next; }
-} HeapList;
+};
//-----------------------------------------------------------------------------
// Implementation of the standard CodeHeap.
BOOL LoadJIT();
- CodeHeader* allocCode(MethodDesc* pFD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag
+ void allocCode(MethodDesc* pFD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, CodeHeader** ppCodeHeader, CodeHeader** ppCodeHeaderRW,
+ size_t* pAllocatedSize, HeapList** ppCodeHeap
+#ifdef USE_INDIRECT_CODEHEADER
+ , BYTE** ppRealHeader
+#endif
#ifdef FEATURE_EH_FUNCLETS
- , UINT nUnwindInfos
- , TADDR * pModuleBase
+ , UINT nUnwindInfos
#endif
- );
+ );
BYTE * allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize);
EE_ILEXCEPTION* allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize);
JumpStubBlockHeader* allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps,
#ifndef DACCESS_COMPILE
// Heap Management functions
void NibbleMapSet(HeapList * pHp, TADDR pCode, BOOL bSet);
+ void NibbleMapSetUnlocked(HeapList * pHp, TADDR pCode, BOOL bSet);
#endif // !DACCESS_COMPILE
static TADDR FindMethodCode(RangeSection * pRangeSection, PCODE currentPC);
}
/*********************************************************************/
+void CEEJitInfo::WriteCode(EEJitManager * jitMgr)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ } CONTRACTL_END;
+
+#ifdef USE_INDIRECT_CODEHEADER
+ if (m_pRealCodeHeader != NULL)
+ {
+ // Restore the read only version of the real code header
+ m_CodeHeaderRW->SetRealCodeHeader(m_pRealCodeHeader);
+ m_pRealCodeHeader = NULL;
+ }
+#endif // USE_INDIRECT_CODEHEADER
+
+ if (m_CodeHeaderRW != m_CodeHeader)
+ {
+ memcpy(m_CodeHeader, m_CodeHeaderRW, m_codeWriteBufferSize);
+ }
+
+ // Now that the code header was written to the final location, publish the code via the nibble map
+ jitMgr->NibbleMapSet(m_pCodeHeap, m_CodeHeader->GetCodeStartAddress(), TRUE);
+
+#if defined(TARGET_AMD64)
+ // Publish the new unwind information in a way that the ETW stack crawler can find
+ _ASSERTE(m_usedUnwindInfos == m_totalUnwindInfos);
+ UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
+#endif // defined(TARGET_AMD64)
+
+}
+
+
+/*********************************************************************/
// Route jit information to the Jit Debug store.
void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, uint32_t cMap,
ICorDebugInfo::OffsetMapping *pMap)
NULL,
m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
- m_CodeHeader->SetDebugInfo(pDebugInfo);
+ m_CodeHeaderRW->SetDebugInfo(pDebugInfo);
}
EX_CATCH
{
_ASSERTE(m_usedUnwindInfos > 0);
}
- PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
+ PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeaderRW->GetUnwindInfo(m_usedUnwindInfos);
+
m_usedUnwindInfos++;
// Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
_ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
+
+ size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader;
UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
+ UNWIND_INFO * pUnwindInfoRW = (UNWIND_INFO *)((BYTE*)pUnwindInfo + writeableOffset);
+
m_usedUnwindSize += unwindSize;
reservePersonalityRoutineSpace(m_usedUnwindSize);
for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
{
- PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
- _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
- || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
+ PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeaderRW->GetUnwindInfo(iUnwindInfo);
+ _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress + writeableOffset)
+ || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress + writeableOffset) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
}
}
#endif // _DEBUG
- /* Copy the UnwindBlock */
- memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
+ memcpy(pUnwindInfoRW, pUnwindBlock, unwindSize);
#if defined(TARGET_X86)
#elif defined(TARGET_AMD64)
- pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
+ pUnwindInfoRW->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
- ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
- *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
+ ULONG * pPersonalityRoutineRW = (ULONG*)ALIGN_UP(&(pUnwindInfoRW->UnwindCode[pUnwindInfoRW->CountOfUnwindCodes]), sizeof(ULONG));
+ *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
#elif defined(TARGET_ARM64)
- *(LONG *)pUnwindInfo |= (1 << 20); // X bit
+ *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
- ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
- *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
+ ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
+ *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
#elif defined(TARGET_ARM)
- *(LONG *)pUnwindInfo |= (1 << 20); // X bit
+ *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
- ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
- *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
+ ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
+ *pPersonalityRoutineRW = (TADDR)ProcessCLRException - baseAddress;
#endif
-#if defined(TARGET_AMD64)
- // Publish the new unwind information in a way that the ETW stack crawler can find
- if (m_usedUnwindInfos == m_totalUnwindInfos)
- UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
-#endif // defined(TARGET_AMD64)
-
EE_TO_JIT_TRANSITION();
#else // FEATURE_EH_FUNCLETS
LIMITED_METHOD_CONTRACT;
delta = (INT64)(branchTarget - fixupLocation);
_ASSERTE((delta & 0x3) == 0); // the low two bits must be zero
- UINT32 branchInstr = *((UINT32*) fixupLocation);
+ UINT32 branchInstr = *((UINT32*) fixupLocationRW);
branchInstr &= 0xFC000000; // keep bits 31-26
_ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000); // Must be B or BL
pArgs->hotCodeSize + pArgs->coldCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId());
}
- m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag
+ m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap
+#ifdef USE_INDIRECT_CODEHEADER
+ , &m_pRealCodeHeader
+#endif
+#ifdef FEATURE_EH_FUNCLETS
+ , m_totalUnwindInfos
+#endif
+ );
+
#ifdef FEATURE_EH_FUNCLETS
- , m_totalUnwindInfos
- , &m_moduleBase
+ m_moduleBase = m_pCodeHeap->GetModuleBase();
#endif
- );
BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
+ size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader;
*codeBlock = current;
- *codeBlockRW = current;
+ *codeBlockRW = current + writeableOffset;
current += codeSize;
if (pArgs->roDataSize > 0)
{
current = (BYTE *)ALIGN_UP(current, roDataAlignment);
pArgs->roDataBlock = current;
- pArgs->roDataBlockRW = current;
+ pArgs->roDataBlockRW = current + writeableOffset;
current += pArgs->roDataSize;
}
else
JIT_TO_EE_TRANSITION();
- _ASSERTE(m_CodeHeader != 0);
- _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
+ _ASSERTE(m_CodeHeaderRW != 0);
+ _ASSERTE(m_CodeHeaderRW->GetGCInfo() == 0);
#ifdef HOST_64BIT
if (size & 0xFFFFFFFF80000000LL)
}
#endif // HOST_64BIT
- block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
+ block = m_jitManager->allocGCInfo(m_CodeHeaderRW,(DWORD)size, &m_GCinfo_len);
if (!block)
{
COMPlusThrowHR(CORJIT_OUTOFMEM);
}
- _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
+ _ASSERTE(m_CodeHeaderRW->GetGCInfo() != 0 && block == m_CodeHeaderRW->GetGCInfo());
EE_TO_JIT_TRANSITION();
JIT_TO_EE_TRANSITION();
_ASSERTE(cEH != 0);
- _ASSERTE(m_CodeHeader != 0);
- _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
+ _ASSERTE(m_CodeHeaderRW != 0);
+ _ASSERTE(m_CodeHeaderRW->GetEHInfo() == 0);
EE_ILEXCEPTION* ret;
- ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
+ ret = m_jitManager->allocEHInfo(m_CodeHeaderRW,cEH, &m_EHinfo_len);
_ASSERTE(ret); // allocEHInfo throws if there's not enough memory
- _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
+ _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && m_CodeHeaderRW->GetEHInfo()->EHCount() == cEH);
EE_TO_JIT_TRANSITION();
}
JIT_TO_EE_TRANSITION();
// <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
- _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
+ _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && EHnumber < m_CodeHeaderRW->GetEHInfo()->EHCount());
- EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
+ EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeaderRW->GetEHInfo()->EHClause(EHnumber);
pEHClause->TryStartPC = clause->TryOffset;
pEHClause->TryEndPC = clause->TryLength;
LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
- if (!SUCCEEDED(res))
+ if (SUCCEEDED(res))
+ {
+ jitInfo.WriteCode(jitMgr);
+ }
+ else
{
jitInfo.BackoutJitData(jitMgr);
ThrowExceptionForJit(res);
/*********************************************************************/
class EEJitManager;
+struct HeapList;
struct _hpCodeHdr;
typedef struct _hpCodeHdr CodeHeader;
GC_NOTRIGGER;
} CONTRACTL_END;
+ if (m_CodeHeaderRW != m_CodeHeader)
+ {
+ delete [] (BYTE*)m_CodeHeaderRW;
+ }
+
m_CodeHeader = NULL;
+ m_CodeHeaderRW = NULL;
+
+ m_codeWriteBufferSize = 0;
+#ifdef USE_INDIRECT_CODEHEADER
+ m_pRealCodeHeader = NULL;
+#endif
+ m_pCodeHeap = NULL;
if (m_pOffsetMapping != NULL)
delete [] ((BYTE*) m_pOffsetMapping);
: CEEInfo(fd, fVerifyOnly, allowInlining),
m_jitManager(jm),
m_CodeHeader(NULL),
+ m_CodeHeaderRW(NULL),
+ m_codeWriteBufferSize(0),
+#ifdef USE_INDIRECT_CODEHEADER
+ m_pRealCodeHeader(NULL),
+#endif
+ m_pCodeHeap(NULL),
m_ILHeader(header),
#ifdef FEATURE_EH_FUNCLETS
m_moduleBase(NULL),
MODE_ANY;
} CONTRACTL_END;
+ if (m_CodeHeaderRW != m_CodeHeader)
+ {
+ delete [] (BYTE*)m_CodeHeaderRW;
+ }
+
if (m_pOffsetMapping != NULL)
delete [] ((BYTE*) m_pOffsetMapping);
void BackoutJitData(EEJitManager * jitMgr);
+ void WriteCode(EEJitManager * jitMgr);
+
void setPatchpointInfo(PatchpointInfo* patchpointInfo) override final;
PatchpointInfo* getOSRInfo(unsigned* ilOffset) override final;
EEJitManager* m_jitManager; // responsible for allocating memory
CodeHeader* m_CodeHeader; // descriptor for JITTED code
+ CodeHeader* m_CodeHeaderRW;
+ size_t m_codeWriteBufferSize;
+#ifdef USE_INDIRECT_CODEHEADER
+ BYTE* m_pRealCodeHeader;
+#endif
+ HeapList* m_pCodeHeap;
COR_ILMETHOD_DECODER * m_ILHeader; // the code header as exist in the file
#ifdef FEATURE_EH_FUNCLETS
TADDR m_moduleBase; // Base for unwind Infos