FCIMPL3(DWORD, SynchronizationContextNative::WaitHelper, PTRArray *handleArrayUNSAFE, CLR_BOOL waitAll, DWORD millis) { DWORD ret = 0; PTRARRAYREF handleArrayObj = (PTRARRAYREF) handleArrayUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(handleArrayObj); CONTRACTL { GC_TRIGGERS; THROWS; MODE_COOPERATIVE; SO_TOLERANT; } CONTRACTL_END; CQuickArray<HANDLE> qbHandles; int cHandles = handleArrayObj->GetNumComponents(); // Since DoAppropriateWait could cause a GC, we need to copy the handles to an unmanaged block // of memory to ensure they aren't relocated during the call to DoAppropriateWait. qbHandles.AllocThrows(cHandles); memcpy(qbHandles.Ptr(), handleArrayObj->GetDataPtr(), cHandles * sizeof(HANDLE)); Thread * pThread = GetThread(); ret = pThread->DoAppropriateWait(cHandles, qbHandles.Ptr(), waitAll, millis, (WaitMode)(WaitMode_Alertable | WaitMode_IgnoreSyncCtx)); HELPER_METHOD_FRAME_END(); return ret; }
// SetMethodIL -- This function will create a method within the class void QCALLTYPE COMDynamicWrite::SetMethodIL(QCall::ModuleHandle pModule, INT32 tk, BOOL fIsInitLocal, LPCBYTE pBody, INT32 cbBody, LPCBYTE pLocalSig, INT32 sigLength, UINT16 maxStackSize, ExceptionInstance * pExceptions, INT32 numExceptions, INT32 * pTokenFixups, INT32 numTokenFixups) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); _ASSERTE(pLocalSig); PCCOR_SIGNATURE pcSig = (PCCOR_SIGNATURE)pLocalSig; _ASSERTE(*pcSig == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG); mdSignature pmLocalSigToken; if (sigLength==2 && pcSig[0]==0 && pcSig[1]==0) { //This is an empty local variable sig pmLocalSigToken=0; } else { IfFailThrow(pRCW->GetEmitter()->GetTokenFromSig( pcSig, sigLength, &pmLocalSigToken)); } COR_ILMETHOD_FAT fatHeader; // set fatHeader.Flags to CorILMethod_InitLocals if user wants to zero init the stack frame. // fatHeader.SetFlags(fIsInitLocal ? CorILMethod_InitLocals : 0); fatHeader.SetMaxStack(maxStackSize); fatHeader.SetLocalVarSigTok(pmLocalSigToken); fatHeader.SetCodeSize(cbBody); bool moreSections = (numExceptions != 0); unsigned codeSizeAligned = fatHeader.GetCodeSize(); if (moreSections) codeSizeAligned = AlignUp(codeSizeAligned, 4); // to insure EH section aligned unsigned headerSize = COR_ILMETHOD::Size(&fatHeader, numExceptions != 0); //Create the exception handlers. CQuickArray<COR_ILMETHOD_SECT_EH_CLAUSE_FAT> clauses; if (numExceptions > 0) { clauses.AllocThrows(numExceptions); for (int i = 0; i < numExceptions; i++) { clauses[i].SetFlags((CorExceptionFlag)(pExceptions[i].m_type)); clauses[i].SetTryOffset(pExceptions[i].m_start); clauses[i].SetTryLength(pExceptions[i].m_end - pExceptions[i].m_start); clauses[i].SetHandlerOffset(pExceptions[i].m_handle); clauses[i].SetHandlerLength(pExceptions[i].m_handleEnd - pExceptions[i].m_handle); if (pExceptions[i].m_type == COR_ILEXCEPTION_CLAUSE_FILTER) { clauses[i].SetFilterOffset(pExceptions[i].m_filterOffset); } else if (pExceptions[i].m_type!=COR_ILEXCEPTION_CLAUSE_FINALLY) { clauses[i].SetClassToken(pExceptions[i].m_exceptionType); } else { clauses[i].SetClassToken(mdTypeRefNil); } } } unsigned ehSize = ExceptionHandlingSize(numExceptions, clauses.Ptr()); S_UINT32 totalSizeSafe = S_UINT32(headerSize) + S_UINT32(codeSizeAligned) + S_UINT32(ehSize); if (totalSizeSafe.IsOverflow()) COMPlusThrowOM(); UINT32 totalSize = totalSizeSafe.Value(); ICeeGen* pGen = pRCW->GetCeeGen(); BYTE* buf = NULL; ULONG methodRVA; pGen->AllocateMethodBuffer(totalSize, &buf, &methodRVA); if (buf == NULL) COMPlusThrowOM(); _ASSERTE(buf != NULL); _ASSERTE((((size_t) buf) & 3) == 0); // header is dword aligned #ifdef _DEBUG BYTE* endbuf = &buf[totalSize]; #endif BYTE * startBuf = buf; // Emit the header buf += COR_ILMETHOD::Emit(headerSize, &fatHeader, moreSections, buf); //Emit the code //The fatHeader.CodeSize is a workaround to see if we have an interface or an //abstract method. Force enough verification in native to ensure that //this is true. if (fatHeader.GetCodeSize()!=0) { memcpy(buf, pBody, fatHeader.GetCodeSize()); } buf += codeSizeAligned; // Emit the eh CQuickArray<ULONG> ehTypeOffsets; if (numExceptions > 0) { // Allocate space for the the offsets to the TypeTokens in the Exception headers // in the IL stream. ehTypeOffsets.AllocThrows(numExceptions); // Emit the eh. This will update the array ehTypeOffsets with offsets // to Exception type tokens. The offsets are with reference to the // beginning of eh section. buf += COR_ILMETHOD_SECT_EH::Emit(ehSize, numExceptions, clauses.Ptr(), false, buf, ehTypeOffsets.Ptr()); } _ASSERTE(buf == endbuf); //Get the IL Section. HCEESECTION ilSection; IfFailThrow(pGen->GetIlSection(&ilSection)); // Token Fixup data... ULONG ilOffset = methodRVA + headerSize; //Add all of the relocs based on the info which I saved from ILGenerator. //Add the Token Fixups for (int iTokenFixup=0; iTokenFixup<numTokenFixups; iTokenFixup++) { IfFailThrow(pGen->AddSectionReloc(ilSection, pTokenFixups[iTokenFixup] + ilOffset, ilSection, srRelocMapToken)); } // Add token fixups for exception type tokens. for (int iException=0; iException < numExceptions; iException++) { if (ehTypeOffsets[iException] != (ULONG) -1) { IfFailThrow(pGen->AddSectionReloc( ilSection, ehTypeOffsets[iException] + codeSizeAligned + ilOffset, ilSection, srRelocMapToken)); } } //nasty interface workaround. What does this mean for abstract methods? if (fatHeader.GetCodeSize() != 0) { // add the starting address of the il blob to the il blob hash table // we need to find this information from out of process for debugger inspection // APIs so we have to store this information where we can get it later pModule->SetDynamicIL(mdToken(tk), TADDR(startBuf), FALSE); DWORD dwImplFlags; //Set the RVA of the method. IfFailThrow(pRCW->GetMDImport()->GetMethodImplProps(tk, NULL, &dwImplFlags)); dwImplFlags |= (miManaged | miIL); IfFailThrow(pRCW->GetEmitter()->SetMethodProps(tk, (DWORD) -1, methodRVA, dwImplFlags)); } END_QCALL; }
void DumpMD_DisplayUserStrings( RegMeta *pMD) // The scope to dump. { HCORENUM stringEnum = NULL; // string enumerator. mdString Strings[ENUM_BUFFER_SIZE]; // String tokens from enumerator. CQuickArray<WCHAR> rUserString; // Buffer to receive string. WCHAR *szUserString; // Working pointer into buffer. ULONG chUserString; // Size of user string. CQuickArray<char> rcBuf; // Buffer to hold the BLOB version of the string. char *szBuf; // Working pointer into buffer. ULONG chBuf; // Saved size of the user string. ULONG count; // Items returned from enumerator. ULONG totalCount = 1; // Running count of strings. bool bUnprint = false; // Is an unprintable character found? HRESULT hr; // A result. while (SUCCEEDED(hr = pMD->EnumUserStrings( &stringEnum, Strings, NumItems(Strings), &count)) && count > 0) { if (totalCount == 1) { // If only one, it is the NULL string, so don't print it. DumpMD_WriteLine("User Strings"); DumpMD_WriteLine("-------------------------------------------------------"); } for (ULONG i = 0; i < count; i++, totalCount++) { do { // Try to get the string into the existing buffer. hr = pMD->GetUserString( Strings[i], rUserString.Ptr(),(ULONG32)rUserString.MaxSize(), &chUserString); if (hr == CLDB_S_TRUNCATION) { // Buffer wasn't big enough, try to enlarge it. if (FAILED(rUserString.ReSizeNoThrow(chUserString))) DumpMD_VWriteLine("malloc failed: %#8x.", E_OUTOFMEMORY); continue; } } while (0); if (FAILED(hr)) DumpMD_VWriteLine("GetUserString failed: %#8x.", hr); szUserString = rUserString.Ptr(); chBuf = chUserString; DumpMD_VWrite("%08x : (%2d) L\"", Strings[i], chUserString); while (chUserString) { switch (*szUserString) { case 0: DumpMD_Write("\\0"); break; case W('\r'): DumpMD_Write("\\r"); break; case W('\n'): DumpMD_Write("\\n"); break; case W('\t'): DumpMD_Write("\\t"); break; default: if (iswprint(*szUserString)) DumpMD_VWrite("%lc", *szUserString); else { bUnprint = true; DumpMD_Write("."); } break; } ++szUserString; --chUserString; } DumpMD_WriteLine("\""); // Print the user string as a blob if an unprintable character is found. if (bUnprint) { bUnprint = false; szUserString = rUserString.Ptr(); // REVISIT_TODO: ReSizeNoThrow can fail. Check its return value and add an error path. rcBuf.ReSizeNoThrow(81); //(chBuf * 5 + 1); szBuf = rcBuf.Ptr(); ULONG j,k; DumpMD_WriteLine("\t\tUser string has unprintables, hex format below:"); for (j = 0,k=0; j < chBuf; j++) { // See rcBuf.ResSizeNoThrow(81) above sprintf_s (&szBuf[k*5],81-(k*5), "%04x ", szUserString[j]); k++; if((k==16)||(j == (chBuf-1))) { szBuf[k*5] = '\0'; DumpMD_VWriteLine("\t\t%s", szBuf); k=0; } } } } } if (stringEnum) pMD->CloseEnum(stringEnum); } // void MDInfo::DisplayUserStrings()