未验证 提交 f30a7182 编写于 作者: M Mike McLaughlin 提交者: GitHub

Enable Hot Reload API on Linux (#48497)

Enable Hot Reload API on Linux

Only define EnC_SUPPORTED for vm/ee on xplat. Doesn't enable the ENC ICorDebug API.

Enable hotreload api tests on Linux/MacOS. API not implemented on arm/arm64

Remove all the ENC_DELTA_HACK code. Remove more ENC_DELTA_HACK code from ilasm
上级 bc9259e7
......@@ -56,10 +56,10 @@ if(CLR_CMAKE_HOST_WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif(CLR_CMAKE_HOST_WIN32)
if(CLR_CMAKE_TARGET_WIN32)
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
# Only enable edit and continue on windows x86 and x64
# exclude Linux, arm & arm64
# Only enable edit and continue on x86 and x64, exclude arm & arm64
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:CROSSGEN_COMPONENT>>>:EnC_SUPPORTED>)
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
endif(CLR_CMAKE_TARGET_WIN32)
......
......@@ -2,6 +2,13 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_definitions(-DFEATURE_NO_HOST)
# Enable ENC subset for hot reload on Linux/MacOS x64, exclude arm & arm64
if(NOT CLR_CMAKE_TARGET_WIN32)
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
add_compile_definitions($<$<AND:$<NOT:$<BOOL:$<TARGET_PROPERTY:CROSSGEN_COMPONENT>>>,$<NOT:$<BOOL:$<TARGET_PROPERTY:DAC_COMPONENT>>>>:EnC_SUPPORTED>)
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
endif(NOT CLR_CMAKE_TARGET_WIN32)
include_directories(BEFORE ${VM_DIR})
include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR})
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
......
......@@ -225,14 +225,6 @@ inline IMAGE_SYMBOL* GetSymbolEntry(IMAGE_SYMBOL* pHead, SIZE_T idx)
return (IMAGE_SYMBOL*) (((BYTE*) pHead) + IMAGE_SIZEOF_SYMBOL * idx);
}
#ifdef EnC_SUPPORTED
#define ENC_DELTA_HACK
#endif
#ifdef ENC_DELTA_HACK
BOOL g_EnCMode = FALSE;
#endif
//*****************************************************************************
// To get a new instance, call CreateNewInstance() or CreateNewInstanceEx() instead of new
//*****************************************************************************
......@@ -376,14 +368,6 @@ CeeFileGenWriter::CeeFileGenWriter() // ctor is protected
#endif
#ifdef ENC_DELTA_HACK
// for EnC we want the RVA to be right at the front of the IL stream
PathString szFileName;
DWORD len = WszGetEnvironmentVariable(W("COMP_ENC_EMIT"), szFileName);
if (len > 0)
g_EnCMode = TRUE;
#endif
} // CeeFileGenWriter::CeeFileGenWriter()
//*****************************************************************************
......@@ -564,12 +548,8 @@ HRESULT CeeFileGenWriter::generateImage(void **ppImage)
}
#endif // !TARGET_UNIX
#ifdef ENC_DELTA_HACK
// fixups break because we've set the base RVA to 0 for the delta stream
if (! g_EnCMode)
#endif
if (!m_fixed)
IfFailGo(fixup());
if (!m_fixed)
IfFailGo(fixup());
outputFileName = m_outputFileName;
......@@ -715,14 +695,7 @@ HRESULT CeeFileGenWriter::checkForErrors()
HRESULT CeeFileGenWriter::getMethodRVA(ULONG codeOffset, ULONG *codeRVA)
{
_ASSERTE(codeRVA);
#ifdef ENC_DELTA_HACK
// for EnC we want the RVA to be right be relative to the front of the delta IL stream rather
// than take into account the .text section and the cor header as we would for a real PE file
if (g_EnCMode)
*codeRVA = codeOffset;
else
#endif
*codeRVA = getPEWriter().getIlRva() + codeOffset;
*codeRVA = getPEWriter().getIlRva() + codeOffset;
return S_OK;
} // HRESULT CeeFileGenWriter::getMethodRVA()
......
......@@ -7,14 +7,6 @@
#include "iceefilegen.h"
#include "ceefilegenwriter.h"
#ifdef EnC_SUPPORTED
#define ENC_DELTA_HACK
#endif
#ifdef ENC_DELTA_HACK
extern BOOL g_EnCMode;
#endif
// Deprecated
//****************************************************************************
HRESULT ICeeFileGen::EmitMethod ()
......@@ -130,17 +122,6 @@ HRESULT ICeeFileGen::CreateCeeFileEx2 (HCEEFILE *ceeFile, DWORD createFlags, LPC
TESTANDRETURN(gen != NULL, E_OUTOFMEMORY);
*ceeFile = gen;
#ifdef ENC_DELTA_HACK
// for EnC we want the RVA to be right be relative to the front of the delta IL stream rather
// than take into account the .text section and the cor header as we would for a real PE file
// However, the RVA must be non-zero, so just stick a dword on the front to push it out.
if (g_EnCMode)
{
CeeSection *sec = &gen->getIlSection();
sec->getBlock(sizeof(DWORD), sizeof(DWORD));
}
#endif
return S_OK;
}
......
......@@ -25,10 +25,6 @@ static const char RelocSpaces[] = " ";
static INT64 s_minPcRel25;
static INT64 s_maxPcRel25;
#endif
#ifdef EnC_SUPPORTED
#define ENC_DELTA_HACK
#endif
/* This is the stub program that says it can't be run in DOS mode */
......@@ -2192,48 +2188,6 @@ HRESULT PEWriter::write(__in LPCWSTR fileName) {
HRESULT hr;
#ifdef ENC_DELTA_HACK
PathString szFileName;
DWORD len = WszGetEnvironmentVariable(L"COMP_ENC_EMIT", szFileName);
_ASSERTE(len < sizeof(szFileName));
if (len > 0)
{
_ASSERTE(!m_pSeedFileDecoder);
szFileName.Append(L".dil");
HANDLE pDelta = WszCreateFile(szFileName,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
if (pDelta == INVALID_HANDLE_VALUE) {
hr = HRESULT_FROM_GetLastError();
_ASSERTE(!"failure so open .dil file");
goto ErrExit;
}
// write the actual data
for (PEWriterSection **cur = getSectStart(); cur < getSectCur(); cur++) {
if (strcmp((*cur)->m_name, ".text") == 0)
{
hr = (*cur)->write(pDelta);
CloseHandle(pDelta);
pDelta = NULL;
if (FAILED(hr))
{
_ASSERT(!"failure to write to .dil file");
goto ErrExit;
}
break;
}
}
PREFIX_ASSUME(!pDelta);
return S_OK;
}
#endif
bool ExeOrDll;
unsigned RoundUpVal;
ExeOrDll = isExeOrDll(m_ntHeaders);
......
......@@ -13,7 +13,6 @@ include_directories(.)
set(ILASM_SOURCES
assem.cpp
writer.cpp
writer_enc.cpp
method.cpp
asmman.cpp
main.cpp
......
......@@ -843,8 +843,7 @@ HRESULT AsmMan::EmitManifest()
EmitFiles();
EmitAssembly();
if((((Assembler*)m_pAssembler)->m_dwIncludeDebugInfo != 0) && (m_pAssembly == NULL)
&& !(((Assembler*)m_pAssembler)->m_fENCMode))
if((((Assembler*)m_pAssembler)->m_dwIncludeDebugInfo != 0) && (m_pAssembly == NULL))
{
mdToken tkOwner, tkMscorlib;
tkMscorlib = ((Assembler*)m_pAssembler)->GetAsmRef("mscorlib");
......
......@@ -40,7 +40,6 @@ Assembler::Assembler()
m_fStdMapping = FALSE;
m_fDisplayTraceOutput= FALSE;
m_fENCMode = FALSE;
m_fTolerateDupMethods = FALSE;
m_pCurOutputPos = NULL;
......@@ -534,41 +533,21 @@ BOOL Assembler::EmitMethodBody(Method* pMethod, BinStr* pbsOut)
BYTE* outBuff;
unsigned align = (headerSize == 1)? 1 : 4;
ULONG PEFileOffset, methodRVA;
if(m_fENCMode)
{
if(pbsOut)
{
PEFileOffset = pbsOut->length();
align--;
while(PEFileOffset & align)
{
pbsOut->appendInt8(0);
PEFileOffset++;
}
pbsOut->append(pbsBody);
outBuff = (BYTE*)(pbsOut->ptr()) + (pbsOut->length() - pbsBody->length());
}
else return FALSE;
}
else
{
if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, totalSize,
align, (void **) &outBuff))) return FALSE;
memcpy(outBuff,pbsBody->ptr(),totalSize);
// The offset where we start, (not where the alignment bytes start!
if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset)))
return FALSE;
PEFileOffset -= totalSize;
}
if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, totalSize,
align, (void **) &outBuff))) return FALSE;
memcpy(outBuff,pbsBody->ptr(),totalSize);
// The offset where we start, (not where the alignment bytes start!
if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset)))
return FALSE;
PEFileOffset -= totalSize;
pMethod->m_pCode = outBuff + headerSize;
pMethod->m_headerOffset= PEFileOffset;
pMethod->m_methodOffset= PEFileOffset + headerSize;
DoDeferredILFixups(pMethod);
if(m_fENCMode) methodRVA = PEFileOffset;
else m_pCeeFileGen->GetMethodRVA(m_pCeeFile, PEFileOffset,&methodRVA);
m_pCeeFileGen->GetMethodRVA(m_pCeeFile, PEFileOffset,&methodRVA);
pMethod->m_headerOffset= methodRVA;
pMethod->m_methodOffset= methodRVA + headerSize;
......@@ -881,7 +860,6 @@ BOOL Assembler::EmitMethodImpls()
int i;
for(i=0; (pMID = m_MethodImplDList.PEEK(i)); i++)
{
if(m_fENCMode && (!pMID->m_fNew)) continue;
pMID->m_tkImplementingMethod = ResolveLocalMemberRef(pMID->m_tkImplementingMethod);
pMID->m_tkImplementedMethod = ResolveLocalMemberRef(pMID->m_tkImplementedMethod);
if(FAILED(m_pEmitter->DefineMethodImpl( pMID->m_tkDefiningClass,
......
......@@ -756,7 +756,6 @@ public:
BOOL m_fReportProgress;
BOOL m_fIsMscorlib;
BOOL m_fTolerateDupMethods;
BOOL m_fENCMode;
BOOL m_fOptimize;
mdToken m_tkSysObject;
mdToken m_tkSysString;
......@@ -1221,11 +1220,6 @@ public:
void SetCodePage(unsigned val) { g_uCodePage = val; };
Clockwork* bClock;
void SetClock(Clockwork* val) { bClock = val; };
// ENC paraphernalia
HRESULT InitMetaDataForENC(__in __nullterminated WCHAR* wzOrigFileName, BOOL generatePdb);
BOOL EmitFieldsMethodsENC(Class* pClass);
BOOL EmitEventsPropsENC(Class* pClass);
HRESULT CreateDeltaFiles(__in __nullterminated WCHAR *pwzOutputFilename);
// Syntactic sugar paraphernalia
private:
......
......@@ -194,7 +194,6 @@ extern "C" int _cdecl wmain(int argc, __in WCHAR **argv)
printf("\n/ARM Target processor: ARM (AArch32) processor");
printf("\n/ARM64 Target processor: ARM64 (AArch64) processor");
printf("\n/32BITPREFERRED Create a 32BitPreferred image (PE32)");
printf("\n/ENC=<file> Create Edit-and-Continue deltas from specified source file");
printf("\n\nKey may be '-' or '/'\nOptions are recognized by first 3 characters (except ARM/ARM64)\nDefault source file extension is .il\n");
......@@ -208,8 +207,6 @@ extern "C" int _cdecl wmain(int argc, __in WCHAR **argv)
}
uCodePage = CP_UTF8;
WszSetEnvironmentVariable(W("COMP_ENC_OPENSCOPE"), W(""));
WszSetEnvironmentVariable(W("COMP_ENC_EMIT"), W(""));
if((pAsm = new Assembler()))
{
pAsm->SetCodePage(uCodePage);
......@@ -433,15 +430,6 @@ extern "C" int _cdecl wmain(int argc, __in WCHAR **argv)
}
}
}
else if (!_stricmp(szOpt, "ENC"))
{
WCHAR *pStr = EqualOrColon(argv[i]);
if(pStr == NULL) goto InvalidOption;
for(pStr++; *pStr == L' '; pStr++); //skip the blanks
if(wcslen(pStr)==0) goto InvalidOption; //if no file name
pwzDeltaFiles[NumDeltaFiles++] = pStr;
pAsm->m_fTolerateDupMethods = TRUE;
}
else if (!_stricmp(szOpt, "SUB"))
{
WCHAR *pStr = EqualOrColon(argv[i]);
......@@ -762,10 +750,8 @@ extern "C" int _cdecl wmain(int argc, __in WCHAR **argv)
}
}
if(bClock) cw.cEnd = GetTickCount();
#define ENC_ENABLED
if(exitval==0)
{
pAsm->m_fENCMode = TRUE;
WCHAR wzNewOutputFilename[MAX_FILENAME_LENGTH+16];
for(iFile = 0; iFile < NumDeltaFiles; iFile++)
{
......@@ -801,27 +787,7 @@ extern "C" int _cdecl wmain(int argc, __in WCHAR **argv)
pParser->msg("%s is not a text file\n",szInputFilename);
fAllFilesPresent = FALSE;
}
else
#endif
if (SUCCEEDED(pAsm->InitMetaDataForENC(wzNewOutputFilename, bGeneratePdb)))
{
pAsm->SetSourceFileName(FullFileName(wzInputFilename,uCodePage)); // deletes the argument!
pParser->ParseFile(pIn);
if (pParser->Success() || pAsm->OnErrGo)
{
exitval = 1;
if(FAILED(hr=pAsm->CreateDeltaFiles(wzNewOutputFilename)))
pParser->msg("Could not create output delta files, error code=0x%08X\n",hr);
else
{
if(pAsm->m_fFoldCode && pAsm->m_fReportProgress)
pParser->msg("%d methods folded\n",pAsm->m_dwMethodsFolded);
if(pParser->Success()) exitval = 0;
else pParser->msg("Output delta files contain errors\n");
}
} // end if (pParser->Success() || pAsm->OnErrGo)
} //end if (SUCCEEDED(pAsm->InitMetaDataForENC()))
} // end if ((!pIn) || !(pIn->IsValid())) -- else
if(pIn)
{
......@@ -845,9 +811,6 @@ extern "C" int _cdecl wmain(int argc, __in WCHAR **argv)
}
else printf("Insufficient memory\n");
WszSetEnvironmentVariable(W("COMP_ENC_OPENSCOPE"), W(""));
WszSetEnvironmentVariable(W("COMP_ENC_EMIT"), W(""));
if (exitval || !bGeneratePdb)
{
// PE file was not created, or no debug info required. Kill PDB if any
......
......@@ -34,15 +34,6 @@ HRESULT Assembler::InitMetaData()
if (FAILED(hr))
goto exit;
if(m_wzMetadataVersion)
{
VARIANT encOption;
BSTR bstr;
V_VT(&encOption) = VT_BSTR;
V_BSTR(&encOption) = bstr = ::SysAllocString(m_wzMetadataVersion);
hr = m_pDisp->SetOption(MetaDataRuntimeVersion, &encOption);
::SysFreeString(bstr);
}
hr = m_pDisp->DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataEmit3,
(IUnknown **)&m_pEmitter);
if (FAILED(hr))
......@@ -874,8 +865,6 @@ HRESULT Assembler::DoLocalMemberRefFixups()
int i;
for(i = 0; (pMRF = m_LocalMemberRefFixupList.PEEK(i)) != NULL; i++)
{
if(m_fENCMode && (!pMRF->m_fNew)) continue;
switch(TypeFromToken(pMRF->tk))
{
case 0x99000000: pList = &m_LocalMethodRefDList; break;
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//
// writer_ENC.cpp
//
//
#include "ilasmpch.h"
#include "assembler.h"
HRESULT Assembler::InitMetaDataForENC(__in __nullterminated WCHAR* wzOrigFileName, BOOL generatePdb)
{
HRESULT hr = E_FAIL;
if((wzOrigFileName==NULL)||(*wzOrigFileName == 0)||(m_pDisp==NULL)) return hr;
if (m_pImporter != NULL)
{
m_pImporter->Release();
m_pImporter = NULL;
}
if (m_pEmitter != NULL)
{
m_pEmitter->Release();
m_pEmitter = NULL;
}
if (m_pPortablePdbWriter != NULL)
{
delete m_pPortablePdbWriter;
m_pPortablePdbWriter = NULL;
}
//WszSetEnvironmentVariable(L"COMP_ENC_OPENSCOPE", wzOrigFileName);
//hr = m_pDisp->DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataEmit2,
// (IUnknown **)&m_pEmitter);
if((m_pbsMD==NULL)||(m_pbsMD->length()==0))
{
_ASSERTE(!"NO BASE METADATA!");
return E_FAIL;
}
VARIANT encOption;
V_VT(&encOption) = VT_UI4;
V_UI4(&encOption) = MDUpdateENC;
m_pDisp->SetOption(MetaDataSetENC, &encOption);
V_UI4(&encOption) = MDErrorOutOfOrderDefault;
m_pDisp->SetOption(MetaDataErrorIfEmitOutOfOrder, &encOption);
hr = m_pDisp->OpenScopeOnMemory( m_pbsMD->ptr(),
m_pbsMD->length(),
ofWrite,
IID_IMetaDataEmit2,
(IUnknown **)&m_pEmitter);
_ASSERTE(SUCCEEDED(hr));
if (FAILED(hr))
goto exit;
m_pManifest->SetEmitter(m_pEmitter);
if(FAILED(hr = m_pEmitter->QueryInterface(IID_IMetaDataImport2, (void**)&m_pImporter)))
goto exit;
//WszSetEnvironmentVariable(L"COMP_ENC_EMIT", wzOrigFileName);
if(!Init(generatePdb)) goto exit; // close and re-open CeeFileGen and CeeFile
hr = S_OK;
exit:
return hr;
}
/*********************************************************************************/
BOOL Assembler::EmitFieldsMethodsENC(Class* pClass)
{
unsigned n;
BOOL ret = TRUE;
// emit all field definition metadata tokens
if((pClass->m_FieldDList.COUNT()))
{
FieldDescriptor* pFD;
int j;
for(j=0, n=0; (pFD = pClass->m_FieldDList.PEEK(j)); j++) // can't use POP here: we'll need field list for props
{
if(pFD->m_fNew)
{
if(!EmitField(pFD))
{
if(!OnErrGo) return FALSE;
ret = FALSE;
}
pFD->m_fNew = FALSE;
n++;
}
}
if(m_fReportProgress) printf("Fields: %d;\t",n);
}
// Fields are emitted; emit the class layout
{
COR_FIELD_OFFSET *pOffsets = NULL;
ULONG ul = pClass->m_ulPack;
ULONG N = pClass->m_dwNumFieldsWithOffset;
EmitSecurityInfo(pClass->m_cl,
pClass->m_pPermissions,
pClass->m_pPermissionSets);
pClass->m_pPermissions = NULL;
pClass->m_pPermissionSets = NULL;
if((pClass->m_ulSize != 0xFFFFFFFF)||(ul != 0)||(N != 0))
{
if(IsTdAutoLayout(pClass->m_Attr)) report->warn("Layout specified for auto-layout class\n");
if((ul > 128)||((ul & (ul-1)) !=0 ))
report->error("Invalid packing parameter (%d), must be 1,2,4,8...128\n",pClass->m_ulPack);
if(N)
{
pOffsets = new COR_FIELD_OFFSET[N+1];
ULONG i,j=0;
FieldDescriptor *pFD;
for(i=0; (pFD = pClass->m_FieldDList.PEEK(i)); i++)
{
if(pFD->m_ulOffset != 0xFFFFFFFF)
{
pOffsets[j].ridOfField = RidFromToken(pFD->m_fdFieldTok);
pOffsets[j].ulOffset = pFD->m_ulOffset;
j++;
}
}
_ASSERTE(j == N);
pOffsets[j].ridOfField = mdFieldDefNil;
}
m_pEmitter->SetClassLayout (
pClass->m_cl, // [IN] typedef
ul, // [IN] packing size specified as 1, 2, 4, 8, or 16
pOffsets, // [IN] array of layout specification
pClass->m_ulSize); // [IN] size of the class
if(pOffsets) delete [] pOffsets;
}
}
// emit all method definition metadata tokens
if((pClass->m_MethodList.COUNT()))
{
Method* pMethod;
int i;
for(i=0, n=0; (pMethod = pClass->m_MethodList.PEEK(i));i++)
{
if(pMethod->m_fNew)
{
if(!EmitMethod(pMethod))
{
if(!OnErrGo) return FALSE;
ret = FALSE;
}
pMethod->m_fNew = FALSE;
n++;
}
}
if(m_fReportProgress) printf("Methods: %d;\t",n);
}
if(m_fReportProgress) printf("\n");
return ret;
}
BOOL Assembler::EmitEventsPropsENC(Class* pClass)
{
unsigned n;
BOOL ret = TRUE;
// emit all event definition metadata tokens
if((pClass->m_EventDList.COUNT()))
{
EventDescriptor* pED;
int j;
for(j=0,n=0; (pED = pClass->m_EventDList.PEEK(j)); j++) // can't use POP here: we'll need event list for props
{
if(pED->m_fNew)
{
if(!EmitEvent(pED))
{
if(!OnErrGo) return FALSE;
ret = FALSE;
}
pED->m_fNew = FALSE;
n++;
}
}
if(m_fReportProgress) printf("Events: %d;\t",n);
}
// emit all property definition metadata tokens
if((pClass->m_PropDList.COUNT()))
{
PropDescriptor* pPD;
int j;
for(j=0,n=0; (pPD = pClass->m_PropDList.PEEK(j)); j++)
{
if(pPD->m_fNew)
{
if(!EmitProp(pPD))
{
if(!OnErrGo) return FALSE;
ret = FALSE;
}
pPD->m_fNew = FALSE;
n++;
}
}
if(m_fReportProgress) printf("Props: %d;\t",n);
}
if(m_fReportProgress) printf("\n");
return ret;
}
HRESULT Assembler::CreateDeltaFiles(__in __nullterminated WCHAR *pwzOutputFilename)
{
HRESULT hr;
DWORD mresourceSize = 0;
BYTE* mresourceData = NULL;
WCHAR* pEnd = NULL;
if(m_fReportProgress) printf("Creating DMETA,DIL files\n");
if (!m_pEmitter)
{
printf("Error: Cannot create a PE file with no metadata\n");
return E_FAIL;
}
if(m_pManifest)
{
hr = S_OK;
if(m_pManifest->m_pAsmEmitter==NULL)
hr=m_pEmitter->QueryInterface(IID_IMetaDataAssemblyEmit, (void**) &(m_pManifest->m_pAsmEmitter));
if(SUCCEEDED(hr))
{
m_pManifest->EmitAssemblyRefs();
}
}
// Emit classes, class members and globals:
{
Class *pSearch;
int i;
BOOL bIsUndefClass = FALSE;
if(m_fReportProgress) printf("\nEmitting classes:\n");
for (i=1; (pSearch = m_lstClass.PEEK(i)); i++) // 0 is <Module>
{
if(pSearch->m_fNew)
{
if(m_fReportProgress)
printf("Class %d:\t%s\n",i,pSearch->m_szFQN);
if(pSearch->m_bIsMaster)
{
report->msg("Error: Reference to undefined class '%s'\n",pSearch->m_szFQN);
bIsUndefClass = TRUE;
}
if(!EmitClass(pSearch))
{
if(!OnErrGo) return E_FAIL;
}
pSearch->m_fNew = FALSE;
}
}
if(bIsUndefClass && !OnErrGo) return E_FAIL;
if(m_fReportProgress) printf("\nEmitting fields and methods:\n");
for (i=0; (pSearch = m_lstClass.PEEK(i)) != NULL; i++)
{
if(pSearch->m_fNewMembers)
{
if(m_fReportProgress)
{
if(i == 0) printf("Global \t");
else printf("Class %d\t",i);
}
if(!EmitFieldsMethodsENC(pSearch))
{
if(!OnErrGo) return E_FAIL;
}
}
}
}
// All ref'ed items def'ed in this file are emitted, resolve member refs to member defs:
hr = ResolveLocalMemberRefs();
if(FAILED(hr) &&(!OnErrGo)) goto exit;
// Local member refs resolved, emit events, props and method impls
{
Class *pSearch;
int i;
if(m_fReportProgress) printf("\nEmitting events and properties:\n");
for (i=0; (pSearch = m_lstClass.PEEK(i)); i++)
{
if(pSearch->m_fNewMembers)
{
if(m_fReportProgress)
{
if(i == 0) printf("Global \t");
else printf("Class %d\t",i);
}
if(!EmitEventsPropsENC(pSearch))
{
if(!OnErrGo) return E_FAIL;
}
pSearch->m_fNewMembers = FALSE;
}
}
}
if(m_MethodImplDList.COUNT())
{
if(m_fReportProgress) report->msg("Method Implementations (total): %d\n",m_MethodImplDList.COUNT());
if(!EmitMethodImpls())
{
if(!OnErrGo) return E_FAIL;
}
}
// Emit the rest of the metadata
hr = S_OK;
if(m_pManifest)
{
if (FAILED(hr = m_pManifest->EmitManifest())) goto exit;
}
ResolveLocalMemberRefs(); // in case CAs added some
EmitUnresolvedCustomAttributes();
hr = DoLocalMemberRefFixups();
if(FAILED(hr) &&(!OnErrGo)) goto exit;
// Local member refs resolved and fixed up in BinStr method bodies. Emit the bodies to a separate file.
pEnd = &pwzOutputFilename[wcslen(pwzOutputFilename)];
{
Class* pClass;
Method* pMethod;
FILE* pF = NULL;
wcscat_s(pwzOutputFilename,MAX_SCOPE_LENGTH,W(".dil"));
if(_wfopen_s(&pF,pwzOutputFilename,W("wb"))==0)
{
int i,j,L=0,M=0;
BinStr bsOut;
for (i=0; (pClass = m_lstClass.PEEK(i)); i++)
{
for(j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
{
if(pMethod->m_fNewBody)
{
L+= pMethod->m_pbsBody->length()+3;
M++;
}
}
}
bsOut.getBuff(L+sizeof(DWORD)); // to avoid reallocs
bsOut.remove(L);
for (i=0; (pClass = m_lstClass.PEEK(i)); i++)
{
for(j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
{
if(pMethod->m_fNewBody)
{
if(!EmitMethodBody(pMethod,&bsOut))
{
report->msg("Error: failed to emit body of '%s'\n",pMethod->m_szName);
hr = E_FAIL;
if(!OnErrGo)
{
fclose(pF);
*pEnd = 0;
goto exit;
}
}
pMethod->m_fNewBody = FALSE;
}
}
}
*((DWORD*)(bsOut.ptr())) = bsOut.length() - sizeof(DWORD);
fwrite(bsOut.ptr(),bsOut.length(),1,pF);
fclose(pF);
}
else
report->msg("Error: failed to open file '%S'\n",pwzOutputFilename);
*pEnd = 0;
}
// Emit the meta-data to a separate file
IMetaDataEmit2* pENCEmitter;
if(FAILED(hr = m_pEmitter->QueryInterface(IID_IMetaDataEmit2, (void**)&pENCEmitter)))
goto exit;
DWORD metaDataSize;
if (FAILED(hr=pENCEmitter->GetDeltaSaveSize(cssAccurate, &metaDataSize))) goto exit;
wcscat_s(pwzOutputFilename,MAX_SCOPE_LENGTH,W(".dmeta"));
pENCEmitter->SaveDelta(pwzOutputFilename,0); // second arg (dwFlags) is not used
*pEnd = 0;
pENCEmitter->Release();
// apply delta to create basis for the next ENC iteration
if(m_pbsMD)
{
IMetaDataEmit2* pBaseMDEmit = NULL;
if(FAILED(hr = m_pDisp->OpenScopeOnMemory(m_pbsMD->ptr(),
m_pbsMD->length(),
ofWrite,
IID_IMetaDataEmit2,
(IUnknown **)&pBaseMDEmit))) goto exit;
if(FAILED(hr = pBaseMDEmit->ApplyEditAndContinue((IUnknown*)m_pImporter))) goto exit;
delete m_pbsMD;
if((m_pbsMD = new BinStr()) != NULL)
{
DWORD cb;
hr = pBaseMDEmit->GetSaveSize(cssAccurate,&cb);
BYTE* pb = m_pbsMD->getBuff(cb);
hr = pBaseMDEmit->SaveToMemory(pb,cb);
}
pBaseMDEmit->Release();
}
// release all interfaces
if (m_pImporter != NULL)
{
m_pImporter->Release();
m_pImporter = NULL;
}
if (m_pEmitter != NULL)
{
m_pEmitter->Release();
m_pEmitter = NULL;
}
if (m_pPortablePdbWriter != NULL)
{
delete m_pPortablePdbWriter;
m_pPortablePdbWriter = NULL;
}
return S_OK;
// set managed resource entry, if any
if(m_pManifest && m_pManifest->m_dwMResSizeTotal)
{
mresourceSize = m_pManifest->m_dwMResSizeTotal;
if (FAILED(hr=m_pCeeFileGen->GetSectionBlock(m_pILSection, mresourceSize,
sizeof(DWORD), (void**) &mresourceData))) goto exit;
if (FAILED(hr=m_pCeeFileGen->SetManifestEntry(m_pCeeFile, mresourceSize, 0))) goto exit;
}
//Compute all the RVAs
if (FAILED(hr=m_pCeeFileGen->LinkCeeFile(m_pCeeFile))) goto exit;
// actually output the resources
if(mresourceSize && mresourceData)
{
size_t i, N = m_pManifest->m_dwMResNum, sizeread, L;
BYTE *ptr = (BYTE*)mresourceData;
BOOL mrfail = FALSE;
FILE* pFile = NULL;
char sz[2048];
for(i=0; i < N; i++)
{
if(!m_pManifest->m_fMResNew[i]) continue;
m_pManifest->m_fMResNew[i] = FALSE;
memset(sz,0,2048);
WszWideCharToMultiByte(CP_ACP,0,m_pManifest->m_wzMResName[i],-1,sz,2047,NULL,NULL);
L = m_pManifest->m_dwMResSize[i];
sizeread = 0;
memcpy(ptr,&L,sizeof(DWORD));
ptr += sizeof(DWORD);
pFile = NULL;
if(fopen_s(&pFile,sz,"rb")==0)
{
sizeread = fread((void *)ptr,1,L,pFile);
fclose(pFile);
ptr += sizeread;
}
else
{
report->msg("Error: failed to open mgd resource file '%ls'\n",m_pManifest->m_wzMResName[i]);
mrfail = TRUE;
}
if(sizeread < L)
{
report->msg("Error: failed to read expected %d bytes from mgd resource file '%ls'\n",L,m_pManifest->m_wzMResName[i]);
mrfail = TRUE;
L -= sizeread;
memset(ptr,0,L);
ptr += L;
}
}
if(mrfail)
{
hr = E_FAIL;
goto exit;
}
}
hr = S_OK;
exit:
return hr;
}
......@@ -8,10 +8,6 @@
#include "corerror.h"
#ifdef EnC_SUPPORTED
#define ENC_DELTA_HACK
#endif
//*****************************************************************************
// Creation for new CCeeGen instances
......@@ -578,25 +574,6 @@ HRESULT CCeeGen::emitMetaData(IMetaDataEmit *emitter, CeeSection* section, DWORD
_ASSERTE(metaDataLen <= buffLen);
#ifdef ENC_DELTA_HACK
{
extern int __cdecl fclose(FILE *);
WCHAR szFileName[256];
DWORD len = GetEnvironmentVariable(W("COMP_ENC_EMIT"), szFileName, ARRAYSIZE(szFileName));
_ASSERTE(len < (ARRAYSIZE(szFileName) + 6)); // +6 for the .dmeta
if (len > 0 && len < (ARRAYSIZE(szFileName) + 6))
{
wcscat_s(szFileName, ARRAYSIZE(szFileName), W(".dmeta"));
FILE *pDelta;
int ec = _wfopen_s(&pDelta, szFileName, W("wb"));
if (FAILED(ec)) { return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED); }
fwrite(buffer, 1, metaDataLen, pDelta);
fclose(pDelta);
}
}
#endif
// Set meta virtual address to offset of metadata within .meta, and
// and add a reloc for this offset, which will get turned
// into an rva when the pewriter writes out the file.
......
......@@ -16,10 +16,6 @@
#include <mdlog.h>
#include <mdcommon.h>
#ifdef EnC_SUPPORTED
#define ENC_DELTA_HACK
#endif
//*****************************************************************************
// Ctor.
//*****************************************************************************
......@@ -95,54 +91,6 @@ Disp::DefineScope(
IfFailGo(CLDB_E_FILE_OLDVER);
}
#ifdef ENC_DELTA_HACK
// Testers need this flag for their tests.
DWORD len;
EX_TRY{
len = WszGetEnvironmentVariable(W("COMP_ENC_OPENSCOPE"), szFileNameSuffix);
szFileName.Append(szFileNameSuffix);
}
EX_CATCH_HRESULT(hr);
if (len > 0)
{
// _ASSERTE(!"ENC override on DefineScope");
// m_OptionValue.m_UpdateMode = MDUpdateENC;
// m_OptionValue.m_ErrorIfEmitOutOfOrder = MDErrorOutOfOrderDefault;
// hr = OpenScope(szFileName, ofWrite, riid, ppIUnk);
IMetaDataEmit *pMetaEmit;
hr = OpenScope(szFileName, ofWrite, IID_IMetaDataEmit, (IUnknown **)&pMetaEmit);
DWORD cb;
CQuickBytes pbMetadata;
hr = pMetaEmit->GetSaveSize(cssAccurate,&cb);
_ASSERTE(SUCCEEDED(hr));
IfFailGo(pbMetadata.ReSizeNoThrow(cb));
hr = pMetaEmit->SaveToMemory(pbMetadata.Ptr(),cb);
_ASSERTE(SUCCEEDED(hr));
// hr = OpenScopeOnMemory( pbMetadata.Ptr(), cb, ofWrite|MDUpdateENC|MDUpdateDelta, riid, ppIUnk);
VARIANT encOption;
V_VT(&encOption) = VT_UI4;
V_UI4(&encOption) = MDUpdateENC;
SetOption(MetaDataSetENC, &encOption);
V_UI4(&encOption) = MDErrorOutOfOrderDefault;
SetOption(MetaDataErrorIfEmitOutOfOrder, &encOption);
hr = OpenScopeOnMemory( pbMetadata.Ptr(), cb, ofWrite, riid, ppIUnk);
_ASSERTE(SUCCEEDED(hr));
BOOL fResult = SUCCEEDED(hr);
// print out a message so people know what's happening
printf("Defining scope for EnC using %S %s\n",
static_cast<LPCWSTR>(szFileNameSuffix), fResult ? "succeeded" : "failed");
goto ErrExit;
}
#endif // ENC_DELTA_HACK
// Create a new coclass for this.
pMeta = new (nothrow) RegMeta();
IfNullGo(pMeta);
......
......@@ -39,6 +39,13 @@ if(FEATURE_PERFTRACING)
include_directories(${CORECLR_EVENTPIPE_SHIM_DIR})
endif(FEATURE_PERFTRACING)
# Enable ENC subset for hot reload on Linux/MacOS x64, exclude arm & arm64
if(NOT CLR_CMAKE_TARGET_WIN32)
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
add_compile_definitions($<$<AND:$<NOT:$<BOOL:$<TARGET_PROPERTY:CROSSGEN_COMPONENT>>>,$<NOT:$<BOOL:$<TARGET_PROPERTY:DAC_COMPONENT>>>>:EnC_SUPPORTED>)
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
endif(NOT CLR_CMAKE_TARGET_WIN32)
set(VM_SOURCES_DAC_AND_WKS_COMMON
appdomain.cpp
array.cpp
......
......@@ -1346,6 +1346,7 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
// points to will be zeroed out
// ...
}
__fallthrough;
case ICorDebugInfo::VLT_STK:
case ICorDebugInfo::VLT_STK2:
......
......@@ -58,7 +58,7 @@ EditAndContinueModule::EditAndContinueModule(Assembly *pAssembly, mdToken module
// in a state where Destruct() can be safely called.
//
/*virtual*/
void EditAndContinueModule::Initialize(AllocMemTracker *pamTracker)
void EditAndContinueModule::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
{
CONTRACTL
{
......@@ -69,7 +69,7 @@ void EditAndContinueModule::Initialize(AllocMemTracker *pamTracker)
CONTRACTL_END
LOG((LF_ENC,LL_INFO100,"EACM::Initialize 0x%x\n", this));
Module::Initialize(pamTracker);
Module::Initialize(pamTracker, szName);
}
// Called when the module is being destroyed (eg. AD unload time)
......@@ -1094,7 +1094,7 @@ EnCAddedField *EnCAddedField::Allocate(OBJECTREF thisPointer, EnCFieldDesc *pFD)
}
CONTRACTL_END;
LOG((LF_ENC, LL_INFO1000, "\tEnCAF:Allocate for this %p, FD %p\n", thisPointer, pFD->GetMemberDef()));
LOG((LF_ENC, LL_INFO1000, "\tEnCAF:Allocate for this %p, FD %p\n", OBJECTREFToObject(thisPointer), pFD->GetMemberDef()));
// Create a new EnCAddedField instance
EnCAddedField *pEntry = new EnCAddedField;
......@@ -1241,7 +1241,7 @@ PTR_CBYTE EnCSyncBlockInfo::ResolveField(OBJECTREF thisPointer, EnCFieldDesc *pF
PTR_EnCAddedField pEntry = NULL;
LOG((LF_ENC, LL_INFO1000, "EnCSBI:RF for this %p, FD %p\n", thisPointer, pFD->GetMemberDef()));
LOG((LF_ENC, LL_INFO1000, "EnCSBI:RF for this %p, FD %p\n", OBJECTREFToObject(thisPointer), pFD->GetMemberDef()));
// This list is not synchronized--it hasn't proved a problem, but we could conceivably see race conditions
// arise here.
......@@ -1315,7 +1315,7 @@ PTR_CBYTE EnCSyncBlockInfo::ResolveOrAllocateField(OBJECTREF thisPointer, EnCFie
// if the field doesn't yet have available storage, we'll have to allocate it.
PTR_EnCAddedField pEntry = NULL;
LOG((LF_ENC, LL_INFO1000, "EnCSBI:RF for this %p, FD %p\n", thisPointer, pFD->GetMemberDef()));
LOG((LF_ENC, LL_INFO1000, "EnCSBI:RF for this %p, FD %p\n", OBJECTREFToObject(thisPointer), pFD->GetMemberDef()));
// This list is not synchronized--it hasn't proved a problem, but we could conceivably see race conditions
// arise here.
......
......@@ -213,7 +213,7 @@ private:
protected:
#ifndef DACCESS_COMPILE
// Initialize the module
virtual void Initialize(AllocMemTracker *pamTracker);
virtual void Initialize(AllocMemTracker *pamTracker, LPCWSTR szName = NULL);
#endif
public:
......
......@@ -12,7 +12,6 @@ class NonRuntimeAssembly : Assembly
}
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/45689", platforms: ~TestPlatforms.Windows, runtimes: TestRuntimes.CoreCLR)]
public static void ApplyUpdateInvalidParameters()
{
// Dummy delta arrays
......@@ -27,9 +26,18 @@ public static void ApplyUpdateInvalidParameters()
Assert.Throws<ArgumentException>(() =>
AssemblyExtensions.ApplyUpdate(new NonRuntimeAssembly(), new ReadOnlySpan<byte>(metadataDelta), new ReadOnlySpan<byte>(ilDelta), ReadOnlySpan<byte>.Empty));
// Tests that this assembly isn't not editable
Assert.Throws<InvalidOperationException>(() =>
AssemblyExtensions.ApplyUpdate(typeof(AssemblyExtensions).Assembly, new ReadOnlySpan<byte>(metadataDelta), new ReadOnlySpan<byte>(ilDelta), ReadOnlySpan<byte>.Empty));
if (PlatformDetection.IsNotMonoRuntime && PlatformDetection.IsArmOrArm64Process)
{
// Not implemented on .NET Core arm and arm64
Assert.Throws<NotImplementedException>(() =>
AssemblyExtensions.ApplyUpdate(typeof(AssemblyExtensions).Assembly, new ReadOnlySpan<byte>(metadataDelta), new ReadOnlySpan<byte>(ilDelta), ReadOnlySpan<byte>.Empty));
}
else
{
// Tests that this assembly isn't not editable
Assert.Throws<InvalidOperationException>(() =>
AssemblyExtensions.ApplyUpdate(typeof(AssemblyExtensions).Assembly, new ReadOnlySpan<byte>(metadataDelta), new ReadOnlySpan<byte>(ilDelta), ReadOnlySpan<byte>.Empty));
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册