HRESULT CorHost::UnloadDomain(IUnknown *pUnkDomain) { HRESULT hr = S_OK; if(!pUnkDomain) return E_POINTER; BEGINCANNOTTHROWCOMPLUSEXCEPTION(); Thread* pThread = GetThread(); if (!pThread) IfFailGo(E_UNEXPECTED); IfFailGo(QuickCOMStartup()); BEGIN_ENSURE_COOPERATIVE_GC(); COMPLUS_TRY { // unload doesn't need to switch to the domain to be unloaded OBJECTREF pRef = NULL; GCPROTECT_BEGIN(pRef); pRef = GetObjectRefFromComIP(pUnkDomain); MethodDesc* pMD = g_Mscorlib.GetMethod(METHOD__APP_DOMAIN__UNLOAD); ARG_SLOT arg = ObjToArgSlot((OBJECTREF) pRef); pMD->Call(&arg, METHOD__APP_DOMAIN__UNLOAD); GCPROTECT_END(); } COMPLUS_CATCH { hr = SecurityHelper::MapToHR(GETTHROWABLE()); } COMPLUS_END_CATCH END_ENSURE_COOPERATIVE_GC(); ErrExit: ENDCANNOTTHROWCOMPLUSEXCEPTION(); return hr; }
FCIMPLEND // Return a method info for the method were the exception was thrown FCIMPL1(ReflectMethodObject*, SystemNative::GetMethodFromStackTrace, ArrayBase* pStackTraceUNSAFE) { FCALL_CONTRACT; I1ARRAYREF pArray(static_cast<I1Array *>(pStackTraceUNSAFE)); StackTraceArray stackArray(pArray); if (!stackArray.Size()) return NULL; // The managed stacktrace classes always returns typical method definition, so we don't need to bother providing exact instantiation. // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(pElements[0].pFunc, pElements[0].pExactGenericArgsToken, pTypeHandle, &pMD); MethodDesc* pFunc = stackArray[0].pFunc; // Strip the instantiation to make sure that the reflection never gets a bad method desc back. REFLECTMETHODREF refRet = NULL; HELPER_METHOD_FRAME_BEGIN_RET_0() pFunc = pFunc->LoadTypicalMethodDefinition(); refRet = pFunc->GetStubMethodInfo(); _ASSERTE(pFunc->IsRuntimeMethodHandle()); HELPER_METHOD_FRAME_END(); return (ReflectMethodObject*)OBJECTREFToObject(refRet); }
void PrintDotFile::printDotHeader(MethodDesc& mh) { *os << "digraph dotgraph {" << ::std::endl << "node [shape=record,fontname=\"Courier\",fontsize=9];" << ::std::endl << "label=\"" << mh.getParentType()->getName() << "::" << mh.getName() << "\";" << ::std::endl; }
virtual void run () { CompilationContext* cc = getCompilationContext(); CompilationInterface* ci = cc->getVMCompilationInterface(); ci->lockMethodData(); MethodDesc* methDesc = ci->getMethodToCompile(); if (methDesc->getCodeBlockSize(0) > 0 || methDesc->getCodeBlockSize(1) > 0){ cc->setCompilationFinished(true); ci->unlockMethodData(); } }
MethodDesc *Binder::GetMethod(BinderMethodID id) { THROWSCOMPLUSEXCEPTION(); MethodDesc *pMD = FetchMethod(id); CheckInit(pMD->GetMethodTable()); return pMD; }
CorJitResult __stdcall CInjection::compileMethod(ICorJitInfo * pJitInfo , CORINFO_METHOD_INFO * pCorMethodInfo , UINT nFlags , LPBYTE * pEntryAddress , ULONG * pSizeOfCode ) { ICorJitCompiler * pCorJitCompiler = (ICorJitCompiler *)this; LPBYTE pOriginalILCode = pCorMethodInfo->ILCode; unsigned int nOriginalSize = pCorMethodInfo->ILCodeSize; // find the method to be replaced ILCodeBuffer tILCodeBuffer = {0}; if( pCorMethodInfo && GetStatus() == Status_Ready ) { MethodDesc * pMethodDesc = (MethodDesc*)pCorMethodInfo->ftn; std::map< CORINFO_METHOD_HANDLE, ILCodeBuffer>::iterator iter = s_mpILBuffers.find((CORINFO_METHOD_HANDLE)pMethodDesc); // if the current method is not found, try to search its generic definition method if( iter == s_mpILBuffers.end() && pMethodDesc->HasClassOrMethodInstantiation() ) { MethodDesc * pStripMD = pMethodDesc->StripMethodInstantiation(); if( pStripMD ) iter = s_mpILBuffers.find((CORINFO_METHOD_HANDLE)pStripMD); if( iter == s_mpILBuffers.end() ) { MethodDesc * pWrappedMD = pMethodDesc->GetWrappedMethodDesc(); if( pWrappedMD ) iter = s_mpILBuffers.find((CORINFO_METHOD_HANDLE)pWrappedMD); } } if( iter != s_mpILBuffers.end() ) { tILCodeBuffer = iter->second; pCorMethodInfo->ILCode = tILCodeBuffer.pBuffer; pCorMethodInfo->ILCodeSize = tILCodeBuffer.dwSize; if( !tILCodeBuffer.bIsGeneric ) s_mpILBuffers.erase(iter); } } CorJitResult result = pCorJitCompiler->compileMethod( pJitInfo, pCorMethodInfo, nFlags, pEntryAddress, pSizeOfCode); if( tILCodeBuffer.pBuffer ) { pCorMethodInfo->ILCode = pOriginalILCode; pCorMethodInfo->ILCodeSize = nOriginalSize; if( !tILCodeBuffer.bIsGeneric ) LocalFree(tILCodeBuffer.pBuffer); } return result; }
/* * ProfileArgIterator::GetHiddenArgValue * * Called after initialization, any number of times, to retrieve any * hidden argument, so that resolution for Generics can be done. * * Parameters: * None. * * Returns: * Value of the hidden parameter, or NULL if none exists. */ LPVOID ProfileArgIterator::GetHiddenArgValue(void) { // // It would be really nice to contract this, but the underlying functions are convolutedly // contracted. Basically everything should be loaded by the time the profiler gets a call // back, so everything is NOTHROW/NOTRIGGER, but there is not mechanism for saying that the // contracts in called functions should be for the best case, not the worst case, now. // WRAPPER_NO_CONTRACT; PROFILE_PLATFORM_SPECIFIC_DATA *pData = (PROFILE_PLATFORM_SPECIFIC_DATA *)m_handle; MethodDesc *pMethodDesc = FunctionIdToMethodDesc(pData->functionId); if (!pMethodDesc->RequiresInstArg()) { return NULL; } // // The ArgIterator::GetParamTypeOffset() can only be called after calling GetNextOffset until the // entire signature has been walked, but *before* GetNextOffset returns TransitionBlock::InvalidOffset // - indicating the end. // // // Get the offset of the hidden arg // int argOffset = m_argIterator.GetParamTypeArgOffset(); // // If this is not enregistered, return the value // if (TransitionBlock::IsStackArgumentOffset(argOffset)) { return *(LPVOID *)(((LPBYTE)pData->esp) + (argOffset - TransitionBlock::GetOffsetOfArgs())); } switch (argOffset - TransitionBlock::GetOffsetOfArgumentRegisters()) { case offsetof(ArgumentRegisters, ECX): return (LPVOID)(pData->ecx); case offsetof(ArgumentRegisters, EDX): return (LPVOID)(pData->edx); } _ASSERTE(!"Arg is an unsaved register!"); return NULL; }
static MethodDesc* GetInvokeMemberMD() { static MethodDesc* s_pInvokeMemberMD = NULL; // If we already have retrieved the specified MD then just return it. if (s_pInvokeMemberMD == NULL) { // The method desc has not been retrieved yet so find it. MethodDesc *pMD = g_Mscorlib.GetMethod(METHOD__CLASS__INVOKE_MEMBER); // Ensure that the value types in the signature are loaded. MetaSig::EnsureSigValueTypesLoaded(pMD->GetSig(), pMD->GetModule()); // Cache the method desc. s_pInvokeMemberMD = pMD; } // Return the specified method desc. return s_pInvokeMemberMD; }
void JavaTranslator::translateMethod(CompilationInterface& ci, MethodDesc& methodDesc, IRBuilder& irBuilder) { U_32 byteCodeSize = methodDesc.getByteCodeSize(); const unsigned char* byteCodes = methodDesc.getByteCodes(); MemoryManager translatorMemManager("JavaTranslator::translateMethod.translatorMemManager"); JavaFlowGraphBuilder cfgBuilder(irBuilder.getInstFactory()->getMemManager(),irBuilder); ByteCodeParser parser((const U_8*)byteCodes,byteCodeSize); // generate code JavaByteCodeTranslator translator(ci, translatorMemManager, irBuilder, parser, methodDesc, *irBuilder.getTypeManager(), cfgBuilder); // isInlined parser.parse(&translator); cfgBuilder.build(); }
MethodDesc *Binder::FetchMethod(BinderMethodID id) { THROWSCOMPLUSEXCEPTION(); _ASSERTE(id != METHOD__NIL); _ASSERTE(id <= m_cMethodRIDs); MethodDesc *pMD; if (m_pMethodRIDs[id-1] == 0) pMD = LookupMethod(id); else { pMD = RawGetMethod(id); pMD->GetMethodTable()->CheckRestore(); } // Initialize the sig here where it's safe. (Otherwise it would typically happen // during a MethodDesc::Call.) m_methodDescriptions[id-1].sig->GetBinarySig(); return pMD; }
MethodDesc *Binder::LookupMethod(BinderMethodID id) { _ASSERTE(m_pModule != NULL); _ASSERTE(id != METHOD__NIL); _ASSERTE(id <= m_cMethodRIDs); THROWSCOMPLUSEXCEPTION(); const MethodDescription *d = m_methodDescriptions + id - 1; MethodTable *pMT = FetchClass(d->classID); MethodDesc *pMD = pMT->GetClass()->FindMethod(d->name, d->sig); _ASSERTE(pMD != NULL || !"EE expects method to exist"); _ASSERTE(pMD->GetSlot()+1 <= USHRT_MAX); m_pMethodRIDs[id-1] = (USHORT) pMD->GetSlot()+1; // Go ahead and fill in the rid map since we're here anyway m_pModule->StoreMethodDef(pMD->GetMemberDef(), pMD); return pMD; }
//+---------------------------------------------------------------------------- // // Method: CStackBuilderSink::PrivateProcessMessage, public // // Synopsis: Builds the stack and calls an object // //+---------------------------------------------------------------------------- FCIMPL7(Object*, CStackBuilderSink::PrivateProcessMessage, Object* pSBSinkUNSAFE, ReflectBaseObject* pMethodBaseUNSAFE, PTRArray* pArgsUNSAFE, Object* pServerUNSAFE, void* iMethodPtr, BOOL fContext, PTRARRAYREF* ppVarOutParams) { OBJECTREF ret = NULL; struct _gc { REFLECTBASEREF pMethodBase; PTRARRAYREF pArgs; OBJECTREF pServer; OBJECTREF pSBSink; } gc; gc.pMethodBase = (REFLECTBASEREF) pMethodBaseUNSAFE; gc.pArgs = (PTRARRAYREF) pArgsUNSAFE; gc.pServer = (OBJECTREF) pServerUNSAFE; gc.pSBSink = (OBJECTREF) pSBSinkUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_NOPOLL(Frame::FRAME_ATTR_RETURNOBJ); GCPROTECT_BEGIN(gc); HELPER_METHOD_POLL(); //-[autocvtpro]------------------------------------------------------- THROWSCOMPLUSEXCEPTION(); TRIGGERSGC(); LOG((LF_REMOTING, LL_INFO10, "CStackBuilderSink::PrivateProcessMessage\n")); _ASSERTE(gc.pMethodBase != NULL); ReflectMethod *pRM = (ReflectMethod *)gc.pMethodBase->GetData(); MethodDesc *pMD = pRM->pMethod; // Either pServer is non-null or the method is static (but not both) _ASSERTE((gc.pServer!=NULL) == !(pMD->IsStatic())); // Check if this is an interface invoke, if yes, then we have to find the // real method descriptor on the class of the server object. if(pMD->GetMethodTable()->IsInterface()) { _ASSERTE(gc.pServer != NULL); MethodDesc* pTemp = pMD; // NOTE: This method can trigger GC pMD = gc.pServer->GetMethodTable()->GetMethodDescForInterfaceMethod(pMD, gc.pServer); if(NULL == pMD) { MAKE_WIDEPTR_FROMUTF8(wName, pTemp->GetName()) COMPlusThrow(kMissingMethodException, IDS_EE_MISSING_METHOD, NULL, wName); } } MetaSig mSig(pMD->GetSig(), pMD->GetModule()); // get the target depending on whether the method is virtual or non-virtual // like a constructor, private or final method const BYTE* pTarget = NULL; if (iMethodPtr) { pTarget = (const BYTE*) iMethodPtr; } else { // Get the address of the code pTarget = MethodTable::GetTargetFromMethodDescAndServer(pMD, &(gc.pServer), fContext); } VASigCookie *pCookie = NULL; _ASSERTE(NULL != pTarget); GCPROTECT_BEGIN (ret); // this function does the work ::CallDescrWithObjectArray( gc.pServer, pRM, pTarget, &mSig, pCookie, gc.pServer==NULL?TRUE:FALSE, //fIsStatic gc.pArgs, &ret, ppVarOutParams); GCPROTECT_END (); LOG((LF_REMOTING, LL_INFO10, "CStackBuilderSink::PrivateProcessMessage OUT\n")); //-[autocvtepi]------------------------------------------------------- GCPROTECT_END(); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(ret); }
/** * Executes lazy exception optimization pass. */ void LazyExceptionOpt::doLazyExceptionOpt() { MethodDesc &md = irManager.getMethodDesc(); BitSet excOpnds(leMemManager,irManager.getOpndManager().getNumSsaOpnds()); StlDeque<Inst*> candidateSet(leMemManager); optCandidates = new (leMemManager) OptCandidates(leMemManager); Method_Side_Effects m_sideEff = md.getSideEffect(); const Nodes& nodes = irManager.getFlowGraph().getNodes(); Nodes::const_iterator niter; #ifdef _DEBUG mtdDesc=&md; #endif #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << std::endl; for (int i=0; i<level; i++) Log::out() << " "; Log::out() << "doLE "; md.printFullName(Log::out()); Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif level++; U_32 opndId = 0; isArgCheckNull = false; isExceptionInit = md.isInstanceInitializer() && md.getParentType()->isLikelyExceptionType(); // core api exception init if (m_sideEff == MSE_Unknown && isExceptionInit && strncmp(md.getParentType()->getName(),"java/lang/",10) == 0) { m_sideEff = MSE_False; md.setSideEffect(m_sideEff); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " core api exc "; md.printFullName(Log::out()); Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); for (Inst* inst=headInst->getNextInst(); inst!=NULL; inst=inst->getNextInst()) { #ifdef _DEBUG if (inst->getOpcode()==Op_DefArg && isExceptionInit) { if (Log::isEnabled()) { Log::out() << " defarg: "; inst->print(Log::out()); Log::out() << std::endl; Log::out() << " "; Log::out() << (int)(inst->getDefArgModifier()) << " " << (inst->getDefArgModifier()==DefArgNoModifier) << " " << (inst->getDefArgModifier()==NonNullThisArg) << " " << (inst->getDefArgModifier()==SpecializedToExactType) << " " << (inst->getDefArgModifier()==DefArgBothModifiers) << std::endl; } } #endif if (inst->getOpcode()==Op_Throw) { if (inst->getSrc(0)->getInst()->getOpcode()==Op_NewObj) { excOpnds.setBit(opndId=inst->getSrc(0)->getId(),true); if (!addOptCandidates(opndId,inst)) excOpnds.setBit(opndId,false); // different exc. edges #ifdef _DEBUG if (excOpnds.getBit(opndId)==1) { if (Log::isEnabled()) { Log::out() << " add opnd: "; inst->print(Log::out()); Log::out() << std::endl; Log::out() << " add obj: "; inst->getSrc(0)->getInst()->print(Log::out()); Log::out() << std::endl; } } #endif } } if (m_sideEff == MSE_Unknown) if (instHasSideEffect(inst)) { m_sideEff = MSE_True; #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << "~~~~~~inst sideEff "; inst->print(Log::out()); Log::out() << std::endl; } #endif } } } if (md.getSideEffect() == MSE_Unknown) { if (m_sideEff == MSE_Unknown) { if (isExceptionInit && isArgCheckNull) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << "~~~~~~init sideEff reset: " << m_sideEff << " 3 "; md.printFullName(Log::out()); Log::out() << std::endl; } #endif m_sideEff = MSE_True_Null_Param; } else m_sideEff = MSE_False; } md.setSideEffect(m_sideEff); } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); Opnd* opnd; for (Inst* inst=headInst->getNextInst(); inst!=NULL; inst=inst->getNextInst()) { U_32 nsrc = inst->getNumSrcOperands(); for (U_32 i=0; i<nsrc; i++) { if (!(opnd=inst->getSrc(i))->isSsaOpnd()) // check ssa operands continue; if (excOpnds.getBit(opndId=opnd->getId())==0) continue; if (inst->getOpcode()==Op_DirectCall) { MethodDesc* md = inst->asMethodInst()->getMethodDesc(); if (md->isInstanceInitializer() && md->getParentType()->isLikelyExceptionType()) { if (!addOptCandidates(opndId,inst)) { excOpnds.setBit(opndId,false); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " - rem opnd " << opnd->getId() << " "; inst->print(Log::out()); Log::out() << std::endl; } #endif } } else { excOpnds.setBit(opndId,false); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " -- rem opnd " << opnd->getId() << " "; inst->print(Log::out()); Log::out() << std::endl; } #endif } } else { if (inst->getOpcode()!=Op_Throw) { excOpnds.setBit(opndId,false); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " rem opnd " << opnd->getId() << " "; inst->print(Log::out()); Log::out() << std::endl; } #endif } } } } } if (!excOpnds.isEmpty()) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << "------LE: "; md.printFullName(Log::out()); Log::out() << std::endl; } #endif fixOptCandidates(&excOpnds); } level--; #ifdef _DEBUG if (Log::isEnabled()) { for (int i=0; i<level; i++) Log::out() << " "; Log::out() << "done "; md.printFullName(Log::out()); Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif };
CustomMarshalerInfo::CustomMarshalerInfo(BaseDomain *pDomain, TypeHandle hndCustomMarshalerType, TypeHandle hndManagedType, LPCUTF8 strCookie, DWORD cCookieStrBytes) : m_NativeSize(0) , m_hndManagedType(hndManagedType) , m_hndCustomMarshaler(NULL) , m_pMarshalNativeToManagedMD(NULL) , m_pMarshalManagedToNativeMD(NULL) , m_pCleanUpNativeDataMD(NULL) , m_pCleanUpManagedDataMD(NULL) , m_bDataIsByValue(FALSE) { CONTRACTL { THROWS; GC_TRIGGERS; MODE_COOPERATIVE; PRECONDITION(CheckPointer(pDomain)); } CONTRACTL_END; // Make sure the custom marshaller implements ICustomMarshaler. if (!hndCustomMarshalerType.GetMethodTable()->CanCastToNonVariantInterface(MscorlibBinder::GetClass(CLASS__ICUSTOM_MARSHALER))) { DefineFullyQualifiedNameForClassW() COMPlusThrow(kApplicationException, IDS_EE_ICUSTOMMARSHALERNOTIMPL, GetFullyQualifiedNameForClassW(hndCustomMarshalerType.GetMethodTable())); } // Determine if this type is a value class. m_bDataIsByValue = m_hndManagedType.GetMethodTable()->IsValueType(); // Custom marshalling of value classes is not currently supported. if (m_bDataIsByValue) COMPlusThrow(kNotSupportedException, W("NotSupported_ValueClassCM")); #ifndef CROSSGEN_COMPILE // Run the <clinit> on the marshaler since it might not have run yet. hndCustomMarshalerType.GetMethodTable()->EnsureInstanceActive(); hndCustomMarshalerType.GetMethodTable()->CheckRunClassInitThrowing(); // Create a COM+ string that will contain the string cookie. STRINGREF CookieStringObj = StringObject::NewString(strCookie, cCookieStrBytes); GCPROTECT_BEGIN(CookieStringObj); #endif // Load the method desc's for all the methods in the ICustomMarshaler interface. m_pMarshalNativeToManagedMD = GetCustomMarshalerMD(CustomMarshalerMethods_MarshalNativeToManaged, hndCustomMarshalerType); m_pMarshalManagedToNativeMD = GetCustomMarshalerMD(CustomMarshalerMethods_MarshalManagedToNative, hndCustomMarshalerType); m_pCleanUpNativeDataMD = GetCustomMarshalerMD(CustomMarshalerMethods_CleanUpNativeData, hndCustomMarshalerType); m_pCleanUpManagedDataMD = GetCustomMarshalerMD(CustomMarshalerMethods_CleanUpManagedData, hndCustomMarshalerType); // Load the method desc for the static method to retrieve the instance. MethodDesc *pGetCustomMarshalerMD = GetCustomMarshalerMD(CustomMarshalerMethods_GetInstance, hndCustomMarshalerType); // If the GetInstance method is generic, get an instantiating stub for it - // the CallDescr infrastructure doesn't know how to pass secret generic arguments. if (pGetCustomMarshalerMD->RequiresInstMethodTableArg()) { pGetCustomMarshalerMD = MethodDesc::FindOrCreateAssociatedMethodDesc( pGetCustomMarshalerMD, hndCustomMarshalerType.GetMethodTable(), FALSE, // forceBoxedEntryPoint Instantiation(), // methodInst FALSE, // allowInstParam FALSE); // forceRemotableMethod _ASSERTE(!pGetCustomMarshalerMD->RequiresInstMethodTableArg()); } #ifndef CROSSGEN_COMPILE MethodDescCallSite getCustomMarshaler(pGetCustomMarshalerMD, (OBJECTREF*)&CookieStringObj); pGetCustomMarshalerMD->EnsureActive(); // Prepare the arguments that will be passed to GetCustomMarshaler. ARG_SLOT GetCustomMarshalerArgs[] = { ObjToArgSlot(CookieStringObj) }; // Call the GetCustomMarshaler method to retrieve the custom marshaler to use. OBJECTREF CustomMarshalerObj = getCustomMarshaler.Call_RetOBJECTREF(GetCustomMarshalerArgs); if (!CustomMarshalerObj) { DefineFullyQualifiedNameForClassW() COMPlusThrow(kApplicationException, IDS_EE_NOCUSTOMMARSHALER, GetFullyQualifiedNameForClassW(hndCustomMarshalerType.GetMethodTable())); } m_hndCustomMarshaler = pDomain->CreateHandle(CustomMarshalerObj); // Retrieve the size of the native data. if (m_bDataIsByValue) { // <TODO>@TODO(DM): Call GetNativeDataSize() to retrieve the size of the native data.</TODO> _ASSERTE(!"Value classes are not yet supported by the custom marshaler!"); } else { m_NativeSize = sizeof(void *); } GCPROTECT_END(); #endif }
/** * Checks a callee method side effect. * @param inst - method call instruction * @return <code>true</code> if method has side effect; * <code>false<code> if method has no side effect. */ bool LazyExceptionOpt::methodCallHasSideEffect(Inst* inst) { U_32 opcode = inst->getOpcode(); MethodDesc* cmd = NULL; Method_Side_Effects mse = MSE_Unknown; if (opcode==Op_DirectCall || opcode==Op_TauVirtualCall) { cmd = inst->asMethodCallInst()->getMethodDesc(); } else { if (opcode==Op_IndirectCall || opcode==Op_IndirectMemoryCall) { Type* type = inst->asCallInst()->getFunPtr()->getType(); if (type->isUnresolvedType()) { return true; } cmd = type->asMethodPtrType()->getMethodDesc(); } else { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: no check "; inst->print(Log::out()); Log::out() << std::endl; } #endif return true; } } #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: "; cmd->printFullName(Log::out()); Log::out() << std::endl; } #endif mse = cmd->getSideEffect(); #ifdef _DEBUG if (mse != MSE_Unknown) { if (Log::isEnabled()) { Log::out() << " checkMC: prev.set sideEff " << mse << " "; inst->print(Log::out()); Log::out() << std::endl; } } #endif if (mse == MSE_True) { return true; } if (mse == MSE_False) { return false; } // core api exception init if (cmd->isInstanceInitializer() && cmd->getParentType()->isLikelyExceptionType() && strncmp(cmd->getParentType()->getName(),"java/lang/",10) == 0) { cmd->setSideEffect(MSE_False); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: core api exc "; inst->print(Log::out()); Log::out() << std::endl; } #endif return false; } if ( opcode!=Op_DirectCall && !cmd->isFinal() ) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: not DirCall not final "; inst->print(Log::out()); Log::out() << std::endl; } #endif return true; } if (!isExceptionInit && !(cmd->isInstanceInitializer()&&cmd->getParentType()->isLikelyExceptionType())) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: no init "; Log::out() << isExceptionInit << " "; Log::out() << cmd->isInstanceInitializer() << " "; Log::out() << cmd->getParentType()->isLikelyExceptionType() << " "; inst->print(Log::out()); Log::out() << std::endl; } #endif return true; } /* if (cmd->getParentType()->needsInitialization()) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: need cinit "; inst->print(Log::out()); Log::out() << std::endl; } #endif return true; // cannot compile <init> before <clinit> (to fix vm) } */ if (mse == MSE_Unknown) { // try to compile method //TODO: avoid compilation here. Use translator to perform analysis needed bool allowRecursion = !compInterface.getTypeManager().isLazyResolutionMode(); if (!allowRecursion) { return MSE_True; } if (!compInterface.compileMethod(cmd)) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: method was not compiled " << std::endl; } #endif return true; } else { mse = cmd->getSideEffect(); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: method was compiled, sideEff " << mse << std::endl; } #endif if (mse == MSE_True) return true; if (mse == MSE_False) { return false; } } } if (mse == MSE_True_Null_Param) { U_32 nsrc=inst->getNumSrcOperands(); bool mayBeNull; if (nsrc>3) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkMC: exc.init "; inst->print(Log::out()); Log::out() << std::endl; } #endif mayBeNull=false; for (U_32 i=3; i<nsrc; i++) { if (inst->getSrc(i)->getType()->isReference()) { if (mayBeNullArg(inst,i)) mayBeNull=true; } } if (!mayBeNull) return false; #ifdef _DEBUG for (U_32 i=0; i<nsrc; i++) { if (Log::isEnabled()) { Log::out() << " "<<i<<" isRef: "<< inst->getSrc(i)->getType()->isReference()<<" "; inst->getSrc(i)->getInst()->print(Log::out()); Log::out() << std::endl; } } #endif return true; } #ifdef _DEBUG else { if (Log::isEnabled()) { Log::out() << " ?????? MSE_NULL_PARAM & nsrc "<< nsrc << std::endl; } } #endif } return true; }
BOOL CInjection::StartUpdateILCodes( MethodTable * pMethodTable , CORINFO_METHOD_HANDLE pMethodHandle , mdMethodDef md , LPBYTE pBuffer , DWORD dwSize ) { if( s_nStatus != Status_Ready || !pMethodHandle ) return FALSE; MethodDesc * pMethodDesc = (MethodDesc*)pMethodHandle; pMethodDesc->Reset(); MethodDesc * pStripMethodDesc = pMethodDesc->StripMethodInstantiation(); if( pStripMethodDesc ) pStripMethodDesc->Reset(); ILCodeBuffer tILCodeBuffer; tILCodeBuffer.pBuffer = pBuffer; tILCodeBuffer.dwSize = dwSize; tILCodeBuffer.bIsGeneric = FALSE; // this is a generic method if( pMethodDesc->ContainsGenericVariables() || pMethodDesc->HasClassOrMethodInstantiation() ) { tILCodeBuffer.bIsGeneric = TRUE; MethodDesc * pWrappedMethodDesc = pMethodDesc->GetWrappedMethodDesc(); if( pWrappedMethodDesc ) { pWrappedMethodDesc->Reset(); } // find out all the instantiations of this generic method Module * pModule = pMethodDesc->GetLoaderModule(); AppDomain * pAppDomain = pMethodDesc->GetDomain(); if( pModule ) { LoadedMethodDescIterator * pLoadedMethodDescIter = new LoadedMethodDescIterator( pAppDomain, pModule, md); while(pLoadedMethodDescIter->Next()) { MethodDesc * pMD = pLoadedMethodDescIter->Current(); if( pMD ) pMD->Reset(); } delete pLoadedMethodDescIter; } } std::map< CORINFO_METHOD_HANDLE, ILCodeBuffer>::iterator iter = s_mpILBuffers.find(pMethodHandle); if( iter != s_mpILBuffers.end() ) { LocalFree(iter->second.pBuffer); s_mpILBuffers.erase(iter); } s_mpILBuffers.insert( std::pair< CORINFO_METHOD_HANDLE, ILCodeBuffer>( pMethodHandle, tILCodeBuffer) ); return TRUE; }
// Creates a domain in the runtime. The identity array is // a pointer to an array TYPE containing IIdentity objects defining // the security identity. HRESULT CorHost::CreateDomainEx(LPCWSTR pwzFriendlyName, IUnknown* pSetup, // Optional IUnknown* pEvidence, // Optional IUnknown ** pAppDomain) { HRESULT hr = S_OK; if(!pwzFriendlyName) return E_POINTER; if(pAppDomain == NULL) return E_POINTER; if(g_RefCount == 0) return E_FAIL; BEGINCANNOTTHROWCOMPLUSEXCEPTION(); // This will set up a managed thread object if one does not already exist // for this particular thread. Thread* pThread = SetupThread(); if (pThread == NULL) { hr = E_OUTOFMEMORY; goto Exit; } if (!pThread) { hr = E_UNEXPECTED; goto Exit; } if (FAILED(hr = QuickCOMStartup())) goto Exit; BOOL fWasGCEnabled; fWasGCEnabled = !pThread->PreemptiveGCDisabled(); if (fWasGCEnabled) pThread->DisablePreemptiveGC(); COMPLUS_TRY { struct _gc { STRINGREF pName; OBJECTREF pSetup; OBJECTREF pEvidence; APPDOMAINREF pDomain; } gc; ZeroMemory(&gc, sizeof(gc)); GCPROTECT_BEGIN(gc); gc.pName = COMString::NewString(pwzFriendlyName); if(pSetup) gc.pSetup = GetObjectRefFromComIP(pSetup); if(pEvidence) gc.pEvidence = GetObjectRefFromComIP(pEvidence); MethodDesc *pMD = g_Mscorlib.GetMethod(METHOD__APP_DOMAIN__CREATE_DOMAIN); ARG_SLOT args[3] = { ObjToArgSlot(gc.pName), ObjToArgSlot(gc.pEvidence), ObjToArgSlot(gc.pSetup), }; gc.pDomain = (APPDOMAINREF) ArgSlotToObj(pMD->Call(args, METHOD__APP_DOMAIN__CREATE_DOMAIN)); IfFailThrow(QuickCOMStartup()); *pAppDomain = GetComIPFromObjectRef((OBJECTREF*) &gc.pDomain); GCPROTECT_END(); } COMPLUS_CATCH { hr = SecurityHelper::MapToHR(GETTHROWABLE()); } COMPLUS_END_CATCH if (fWasGCEnabled) pThread->EnablePreemptiveGC(); Exit: ENDCANNOTTHROWCOMPLUSEXCEPTION(); return hr; }
//+---------------------------------------------------------------------------- // // Function: CallDescrWithObjectArray, private // // Synopsis: Builds the stack from a object array and call the object // // Note this function triggers GC and assumes that pServer, pArguments, pVarRet, and ppVarOutParams are // all already protected!! //+---------------------------------------------------------------------------- void CallDescrWithObjectArray(OBJECTREF& pServer, ReflectMethod *pRM, const BYTE *pTarget, MetaSig* sig, VASigCookie *pCookie, BOOL fIsStatic, PTRARRAYREF& pArgArray, OBJECTREF *pVarRet, PTRARRAYREF *ppVarOutParams) { THROWSCOMPLUSEXCEPTION(); TRIGGERSGC(); // the debugger, profiler code triggers a GC LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray IN\n")); ByRefInfo *pByRefs = NULL; INT64 retval = 0; UINT nActualStackBytes = 0; LPBYTE pAlloc = 0; LPBYTE pFrameBase = 0; UINT32 numByRef = 0; DWORD attr = pRM->dwFlags; #ifdef _DEBUG MethodDesc *pMD = pRM->pMethod; #endif // check the calling convention BYTE callingconvention = sig->GetCallingConvention(); if (!isCallConv(callingconvention, IMAGE_CEE_CS_CALLCONV_DEFAULT)) { _ASSERTE(!"This calling convention is not supported."); COMPlusThrow(kInvalidProgramException); } #ifdef DEBUGGING_SUPPORTED // debugger goo What does this do? can someone put a comment here? if (CORDebuggerTraceCall()) g_pDebugInterface->TraceCall(pTarget); #endif // DEBUGGING_SUPPORTED #ifdef PROFILING_SUPPORTED // If we're profiling, notify the profiler that we're about to invoke the remoting target if (CORProfilerTrackRemoting()) g_profControlBlock.pProfInterface->RemotingServerInvocationStarted( reinterpret_cast<ThreadID>(GetThread())); #endif // PROFILING_SUPPORTED // Create a fake FramedMethodFrame on the stack. nActualStackBytes = sig->SizeOfActualFixedArgStack(fIsStatic); pAlloc = (LPBYTE)_alloca(FramedMethodFrame::GetNegSpaceSize() + sizeof(FramedMethodFrame) + nActualStackBytes); pFrameBase = pAlloc + FramedMethodFrame::GetNegSpaceSize(); // cycle through the parameters and see if there are byrefs BYTE typ = 0; BOOL fHasByRefs = FALSE; if (attr & RM_ATTR_BYREF_FLAG_SET) fHasByRefs = attr & RM_ATTR_HAS_BYREF_ARG; else { sig->Reset(); while ((typ = sig->NextArg()) != ELEMENT_TYPE_END) { if (typ == ELEMENT_TYPE_BYREF) { fHasByRefs = TRUE; attr |= RM_ATTR_HAS_BYREF_ARG; break; } } attr |= RM_ATTR_BYREF_FLAG_SET; pRM->dwFlags = attr; sig->Reset(); } int nFixedArgs = sig->NumFixedArgs(); // if there are byrefs allocate and array for the out parameters if (fHasByRefs) { *ppVarOutParams = PTRARRAYREF(AllocateObjectArray(sig->NumFixedArgs(), g_pObjectClass)); // Null out the array memset(&(*ppVarOutParams)->m_Array, 0, sizeof(OBJECTREF) * sig->NumFixedArgs()); } ArgIterator argit(pFrameBase, sig, fIsStatic); // set the this pointer OBJECTREF *ppThis = (OBJECTREF*)argit.GetThisAddr(); *ppThis = NULL; // if there is a return buffer, allocate it if (sig->HasRetBuffArg()) { EEClass *pEECValue = sig->GetRetEEClass(); _ASSERTE(pEECValue->IsValueClass()); MethodTable * mt = pEECValue->GetMethodTable(); *pVarRet = AllocateObject(mt); *(argit.GetRetBuffArgAddr()) = (*pVarRet)->UnBox(); #if defined(_PPC_) || defined(_SPARC_) // retbuf // the CallDescrWorker callsite for methods with return buffer is // different for RISC CPUs - we pass this information along by setting // the lowest bit in pTarget pTarget = (const BYTE *)((UINT_PTR)pTarget | 0x1); #endif } // gather data about the parameters by iterating over the sig: UINT32 arg = 0; UINT32 structSize = 0; int ofs = 0; // REVIEW: need to use actual arg count if VarArgs are supported ArgInfo* pArgInfo = (ArgInfo*) _alloca(nFixedArgs*sizeof(ArgInfo)); #ifdef _DEBUG // We expect to write useful data over every part of this so need // not do this in retail! memset((void *)pArgInfo, 0, sizeof(ArgInfo)*nFixedArgs); #endif for( ; 0 != (ofs = argit.GetNextOffset(&typ, &structSize)); arg++, pArgInfo++ ) { if (typ == ELEMENT_TYPE_BYREF) { EEClass *pClass = NULL; CorElementType brType = sig->GetByRefType(&pClass); if (CorIsPrimitiveType(brType)) { pArgInfo->dataSize = gElementTypeInfo[brType].m_cbSize; } else if (pClass->IsValueClass()) { pArgInfo->dataSize = pClass->GetAlignedNumInstanceFieldBytes(); numByRef ++; } else { pArgInfo->dataSize = sizeof(Object *); numByRef ++; } ByRefInfo *brInfo = (ByRefInfo *) _alloca(offsetof(ByRefInfo,data) + pArgInfo->dataSize); brInfo->argIndex = arg; brInfo->typ = brType; brInfo->pClass = pClass; brInfo->pNext = pByRefs; pByRefs = brInfo; pArgInfo->dataLocation = (BYTE*)brInfo->data; *((void**)(pFrameBase + ofs)) = (void*)pArgInfo->dataLocation; pArgInfo->dataClass = pClass; pArgInfo->dataType = brType; pArgInfo->byref = TRUE; } else { pArgInfo->dataLocation = pFrameBase + ofs; pArgInfo->dataSize = StackElemSize(structSize); pArgInfo->dataClass = sig->GetTypeHandle().GetClass(); // this may cause GC! pArgInfo->dataType = typ; pArgInfo->byref = FALSE; } } if (!fIsStatic) { // If this isn't a value class, verify the objectref #ifdef _DEBUG if (pMD->GetClass()->IsValueClass() == FALSE) { VALIDATEOBJECTREF(pServer); } #endif //_DEBUG *ppThis = pServer; } // There should be no GC when we fill up the stack with parameters, as we don't protect them // Assignment of "*ppThis" above triggers the point where we become unprotected. BEGINFORBIDGC(); // reset pArgInfo to point to the start of the block we _alloca-ed pArgInfo = pArgInfo-nFixedArgs; PBYTE dataLocation; INT32 dataSize; EEClass *dataClass; BYTE dataType; OBJECTREF* pArguments = pArgArray->m_Array; UINT32 i, j = arg; for (i=0; i<j; i++) { dataSize = pArgInfo->dataSize; dataLocation = pArgInfo->dataLocation; dataClass = pArgInfo->dataClass; dataType = pArgInfo->dataType; switch (dataSize) { case 1: // This "if" statement is necessary to make the assignement big-endian aware if (pArgInfo->byref) *((INT8*)dataLocation) = *((INT8*)pArguments[i]->GetData()); else *(StackElemType*)dataLocation = (StackElemType)*((INT8*)pArguments[i]->GetData()); break; case 2: // This "if" statement is necessary to make the assignement big-endian aware if (pArgInfo->byref) *((INT16*)dataLocation) = *((INT16*)pArguments[i]->GetData()); else *(StackElemType*)dataLocation = (StackElemType)*((INT16*)pArguments[i]->GetData()); break; case 4: if ((dataType == ELEMENT_TYPE_STRING) || (dataType == ELEMENT_TYPE_OBJECT) || (dataType == ELEMENT_TYPE_CLASS) || (dataType == ELEMENT_TYPE_SZARRAY) || (dataType == ELEMENT_TYPE_ARRAY)) { *(OBJECTREF *)dataLocation = pArguments[i]; } else { *(StackElemType*)dataLocation = (StackElemType)*((INT32*)pArguments[i]->GetData()); } break; case 8: *((INT64*)dataLocation) = *((INT64*)pArguments[i]->GetData()); break; default: { memcpy(dataLocation, pArguments[i]->UnBox(), dataSize); } } pArgInfo++; } #ifdef _DEBUG // Should not be using this any more pArgInfo = pArgInfo - nFixedArgs; memset((void *)pArgInfo, 0, sizeof(ArgInfo)*nFixedArgs); #endif // if there were byrefs, push a protection frame ProtectByRefsFrame *pProtectionFrame = NULL; if (pByRefs && numByRef > 0) { char *pBuffer = (char*)_alloca (sizeof (ProtectByRefsFrame)); pProtectionFrame = new (pBuffer) ProtectByRefsFrame(GetThread(), pByRefs); } // call the correct worker function depending of if the method // is varargs or not ENDFORBIDGC(); #ifdef _PPC_ FramedMethodFrame::Enregister(pFrameBase, sig, fIsStatic, nActualStackBytes); #endif INSTALL_COMPLUS_EXCEPTION_HANDLER(); retval = CallDescrWorker( pFrameBase + sizeof(FramedMethodFrame) + nActualStackBytes, nActualStackBytes / STACK_ELEM_SIZE, #if defined(_X86_) || defined(_PPC_) // argregs (ArgumentRegisters*)(pFrameBase + FramedMethodFrame::GetOffsetOfArgumentRegisters()), #endif (LPVOID)pTarget); UNINSTALL_COMPLUS_EXCEPTION_HANDLER(); // set floating point return values getFPReturn(sig->GetFPReturnSize(), &retval); // need to build a object based on the return type. if (!sig->HasRetBuffArg()) { BYTE *pRetVal = (BYTE*)&retval; #ifdef BIGENDIAN switch (sig->GetReturnTypeSize()) { case 1: pRetVal += sizeof(void*)-1; break; case 2: pRetVal += sizeof(void*)-2; break; default: // nothing to do break; } #endif GetObjectFromStack(pVarRet, pRetVal, sig->GetReturnType(), sig->GetRetEEClass()); } // extract the out args from the byrefs if (pByRefs) { do { // Always extract the data ptr every time we enter this loop because // calls to GetObjectFromStack below can cause a GC. // Even this is not enough, because that we are passing a pointer to GC heap // to GetObjectFromStack . If GC happens, nobody is protecting the passed in pointer. OBJECTREF pTmp = NULL; GetObjectFromStack(&pTmp, pByRefs->data, pByRefs->typ, pByRefs->pClass); (*ppVarOutParams)->SetAt(pByRefs->argIndex, pTmp); pByRefs = pByRefs->pNext; } while (pByRefs); if (pProtectionFrame) pProtectionFrame->Pop(); } #ifdef PROFILING_SUPPORTED // If we're profiling, notify the profiler that we're about to invoke the remoting target if (CORProfilerTrackRemoting()) g_profControlBlock.pProfInterface->RemotingServerInvocationReturned( reinterpret_cast<ThreadID>(GetThread())); #endif // PROFILING_SUPPORTED LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray OUT\n")); }
VOID ComCallWrapper::InvokeByNameCallback(LPVOID ptr) { InvokeByNameArgs* args = (InvokeByNameArgs*)ptr; INT32 NumByrefArgs = 0; INT32 *aByrefArgMngVariantIndex = NULL; INT32 iArg; struct __gc { OBJECTREF Target; STRINGREF MemberName; PTRARRAYREF ParamArray; OBJECTREF TmpObj; OBJECTREF RetVal; } gc; ZeroMemory(&gc, sizeof(gc)); GCPROTECT_BEGIN(gc); gc.MemberName = COMString::NewString(args->MemberName); gc.ParamArray = (PTRARRAYREF)AllocateObjectArray(args->ArgCount, g_pObjectClass); // // Fill in the arguments. // for (iArg = 0; iArg < args->ArgCount; iArg++) { // Convert the variant. VARIANT *pSrcOleVariant = &args->ArgList[iArg]; OleVariant::MarshalObjectForOleVariant(pSrcOleVariant, &gc.TmpObj); gc.ParamArray->SetAt(iArg, gc.TmpObj); // If the argument is byref then add it to the array of byref arguments. if (V_VT(pSrcOleVariant) & VT_BYREF) { if (aByrefArgMngVariantIndex == NULL) { aByrefArgMngVariantIndex = (INT32 *)_alloca(sizeof(INT32) * args->ArgCount); } aByrefArgMngVariantIndex[NumByrefArgs] = iArg; NumByrefArgs++; } } gc.Target = ObjectFromHandle(args->pThis->m_hThis); // // Invoke using IReflect::InvokeMember // EEClass *pClass = gc.Target->GetClass(); // Retrieve the method descriptor that will be called on. MethodDesc *pMD = GetInvokeMemberMD(); // Prepare the arguments that will be passed to Invoke. ARG_SLOT Args[] = { ObjToArgSlot(GetReflectionObject(pClass)), // IReflect ObjToArgSlot(gc.MemberName), // name (ARG_SLOT) args->BindingFlags, // invokeAttr ObjToArgSlot(GetOleAutBinder()),// binder ObjToArgSlot(gc.Target), // target ObjToArgSlot(gc.ParamArray), // args ObjToArgSlot(NULL), // modifiers ObjToArgSlot(NULL), // culture ObjToArgSlot(NULL) // namedParameters }; // Do the actual method invocation. MetaSig metaSig(pMD->GetSig(),pMD->GetModule()); gc.RetVal = ArgSlotToObj(pMD->Call(Args, &metaSig)); // // Convert the return value and the byref arguments. // // Convert all the ByRef arguments back. for (iArg = 0; iArg < NumByrefArgs; iArg++) { INT32 i = aByrefArgMngVariantIndex[iArg]; gc.TmpObj = gc.ParamArray->GetAt(i); OleVariant::MarshalOleRefVariantForObject(&gc.TmpObj, &args->ArgList[i]); } // Convert the return COM+ object to an OLE variant. if (args->pRetVal) OleVariant::MarshalOleVariantForObject(&gc.RetVal, args->pRetVal); GCPROTECT_END(); }
/* * ProfileArgIterator::ProfileArgIterator * * Constructor. Initializes for arg iteration. * * Parameters: * pMetaSig - The signature of the method we are going iterate over * platformSpecificHandle - the value passed to ProfileEnter/Leave/Tailcall * * Returns: * None. */ ProfileArgIterator::ProfileArgIterator(MetaSig * pSig, void * platformSpecificHandle) : m_argIterator(pSig) { WRAPPER_NO_CONTRACT; _ASSERTE(pSig != NULL); _ASSERTE(platformSpecificHandle != NULL); m_handle = platformSpecificHandle; PROFILE_PLATFORM_SPECIFIC_DATA* pData = (PROFILE_PLATFORM_SPECIFIC_DATA*)m_handle; // unwind a frame and get the Rsp for the profiled method to make sure it matches // what the JIT gave us #ifdef _DEBUG { // setup the context to represent the frame that called ProfileEnterNaked CONTEXT ctx; memset(&ctx, 0, sizeof(CONTEXT)); ctx.Rsp = (UINT64)pData->probeRsp; ctx.Rbp = (UINT64)pData->rbp; ctx.Rip = (UINT64)pData->ip; // walk up a frame to the caller frame (called the managed method which // called ProfileEnterNaked) Thread::VirtualUnwindCallFrame(&ctx); _ASSERTE(pData->profiledRsp == (void*)ctx.Rsp); } #endif // _DEBUG // Get the hidden arg if there is one MethodDesc * pMD = FunctionIdToMethodDesc(pData->functionId); if ( (pData->hiddenArg == NULL) && (pMD->RequiresInstArg() || pMD->AcquiresInstMethodTableFromThis()) ) { // In the enter probe, the JIT may not have pushed the generics token onto the stack yet. // Luckily, we can inspect the registers reliably at this point. if (pData->flags & PROFILE_ENTER) { _ASSERTE(!((pData->flags & PROFILE_LEAVE) || (pData->flags & PROFILE_TAILCALL))); if (pMD->AcquiresInstMethodTableFromThis()) { pData->hiddenArg = GetThis(); } else { // The param type arg comes after the return buffer argument and the "this" pointer. int index = 0; if (m_argIterator.HasThis()) { index++; } if (m_argIterator.HasRetBuffArg()) { index++; } pData->hiddenArg = *(LPVOID*)((LPBYTE)pData->profiledRsp + (index * sizeof(SIZE_T))); } } else { EECodeInfo codeInfo((PCODE)pData->ip); // We want to pass the caller SP here. pData->hiddenArg = EECodeManager::GetExactGenericsToken((SIZE_T)(pData->profiledRsp), &codeInfo); } } }
// // Callback for walking a thread's stack. Sends required frame data to the // DI as send buffers fill up. // StackWalkAction DebuggerThread::TraceAndSendStackCallback(FrameInfo *pInfo, VOID* data) { _RefreshStackFramesData *rsfd = (_RefreshStackFramesData*) data; Thread *t = rsfd->thread; DebuggerIPCEvent *pEvent = NULL; if (rsfd->iWhich == IPC_TARGET_INPROC) { pEvent = rsfd->pEvent; } else { _ASSERTE( rsfd->iWhich == IPC_TARGET_OUTOFPROC ); pEvent = rsfd->rcThread->GetIPCEventSendBuffer(rsfd->iWhich); } // Record registers for the start of the next chain, if appropriate. if (rsfd->needChainRegisters) { rsfd->chainRegisters = pInfo->registers; rsfd->needChainRegisters = false; } // Only report frames which are chain boundaries, or are not marked internal. LOG((LF_CORDB, LL_INFO1000, "DT::TASSC:chainReason:0x%x internal:0x%x " "md:0x%x **************************\n", pInfo->chainReason, pInfo->internal, pInfo->md)); if (pInfo->chainReason == 0 && (pInfo->internal || pInfo->md == NULL)) return SWA_CONTINUE; #ifdef LOGGING if( pInfo->quickUnwind == true ) LOG((LF_CORDB, LL_INFO10000, "DT::TASSC: rsfd => Doing quick unwind\n")); #endif // // If we've filled this event, send it off to the Right Side // before continuing the walk. // if ((rsfd->eventSize + sizeof(DebuggerIPCE_STRData)) >= rsfd->eventMaxSize) { // // pEvent->StackTraceResultData.threadUserState = g_pEEInterface->GetUserState(t); if (rsfd->iWhich == IPC_TARGET_OUTOFPROC) { rsfd->rcThread->SendIPCEvent(rsfd->iWhich); } else { DebuggerIPCEvent *peT; peT = rsfd->rcThread->GetIPCEventSendBufferContinuation(pEvent); if (peT == NULL) { pEvent->hr = E_OUTOFMEMORY; return SWA_ABORT; } CopyEventInfo(pEvent, peT); pEvent = peT; rsfd->pEvent = peT; rsfd->eventSize = 0; } // // Reset for the next set of frames. // pEvent->StackTraceResultData.traceCount = 0; rsfd->currentSTRData = &(pEvent->StackTraceResultData.traceData); rsfd->eventSize = (UINT_PTR)(rsfd->currentSTRData) - (UINT_PTR)(pEvent); } MethodDesc* fd = pInfo->md; if (fd != NULL && !pInfo->internal) { // // Send a frame // rsfd->currentSTRData->isChain = false; rsfd->currentSTRData->fp = pInfo->fp; rsfd->currentSTRData->quicklyUnwound = pInfo->quickUnwind; // Pass the appdomain that this thread was in when it was executing this frame to the Right Side. rsfd->currentSTRData->currentAppDomainToken = (void*)pInfo->currentAppDomain; REGDISPLAY* rd = &pInfo->registers; DebuggerREGDISPLAY* drd = &(rsfd->currentSTRData->rd); LPVOID FPAddress = GetRegdisplayFPAddress(rd); // Set some common elements drd->SP = rd->SP; drd->PC = (SIZE_T)*(rd->pPC); drd->FP = (FPAddress == NULL ? 0 : *((SIZE_T *)FPAddress)); // // PUSHED_REG_ADDR gives us NULL if the register still lives in the thread's context, or it gives us the address // of where the register was pushed for this frame. // #define PUSHED_REG_ADDR(_a) (((UINT_PTR)(_a) >= (UINT_PTR)rd->pContext) && ((UINT_PTR)(_a) <= ((UINT_PTR)rd->pContext + sizeof(CONTEXT)))) ? NULL : (_a) // Frame pointer drd->pFP = PUSHED_REG_ADDR(FPAddress); #ifdef _X86_ drd->pEdi = PUSHED_REG_ADDR(rd->pEdi); drd->Edi = (rd->pEdi == NULL ? 0 : *(rd->pEdi)); drd->pEsi = PUSHED_REG_ADDR(rd->pEsi); drd->Esi = (rd->pEsi == NULL ? 0 : *(rd->pEsi)); drd->pEbx = PUSHED_REG_ADDR(rd->pEbx); drd->Ebx = (rd->pEbx == NULL ? 0 : *(rd->pEbx)); drd->pEdx = PUSHED_REG_ADDR(rd->pEdx); drd->Edx = (rd->pEdx == NULL ? 0 : *(rd->pEdx)); drd->pEcx = PUSHED_REG_ADDR(rd->pEcx); drd->Ecx = (rd->pEcx == NULL ? 0 : *(rd->pEcx)); drd->pEax = PUSHED_REG_ADDR(rd->pEax); drd->Eax = (rd->pEax == NULL ? 0 : *(rd->pEax)); // Please leave EBP, ESP, EIP at the front so I don't have to scroll // left to see the most important registers. Thanks! LOG( (LF_CORDB, LL_INFO1000, "DT::TASSC:Registers:" "Ebp = %x Esp = %x Eip = %x Edi:%d " "Esi = %x Ebx = %x Edx = %x Ecx = %x Eax = %x\n", drd->FP, drd->SP, drd->PC, drd->Edi, drd->Esi, drd->Ebx, drd->Edx, drd->Ecx, drd->Eax ) ); #elif defined(_PPC_) || defined (_SPARC_) // All that's needed for now #else PORTABILITY_ASSERT("TraceAndSendStackCallback needs some munging for this platform."); #endif DebuggerIPCE_FuncData* currentFuncData = &rsfd->currentSTRData->v.funcData; _ASSERTE(fd != NULL); GetVAInfo(&(currentFuncData->fVarArgs), &(currentFuncData->rpSig), &(currentFuncData->cbSig), &(currentFuncData->rpFirstArg), fd, rd, pInfo->relOffset); LOG((LF_CORDB, LL_INFO10000, "DT::TASSC: good frame for %s::%s\n", fd->m_pszDebugClassName, fd->m_pszDebugMethodName)); // // Fill in information about the function that goes with this // frame. // currentFuncData->funcRVA = g_pEEInterface->MethodDescGetRVA(fd); _ASSERTE (t != NULL); Module *pRuntimeModule = g_pEEInterface->MethodDescGetModule(fd); AppDomain *pAppDomain = pInfo->currentAppDomain; currentFuncData->funcDebuggerModuleToken = (void*) g_pDebugger->LookupModule(pRuntimeModule, pAppDomain); if (currentFuncData->funcDebuggerModuleToken == NULL && rsfd->iWhich == IPC_TARGET_INPROC) { currentFuncData->funcDebuggerModuleToken = (void*)g_pDebugger->AddDebuggerModule(pRuntimeModule, pAppDomain); LOG((LF_CORDB, LL_INFO100, "DT::TASSC: load module Mod:%#08x AD:%#08x isDynamic:%#x runtimeMod:%#08x\n", currentFuncData->funcDebuggerModuleToken, pAppDomain, pRuntimeModule->IsReflection(), pRuntimeModule)); } _ASSERTE(currentFuncData->funcDebuggerModuleToken != 0); currentFuncData->funcDebuggerAssemblyToken = (g_pEEInterface->MethodDescGetModule(fd))->GetClassLoader()->GetAssembly(); currentFuncData->funcMetadataToken = fd->GetMemberDef(); currentFuncData->classMetadataToken = fd->GetClass()->GetCl(); // Pass back the local var signature token. COR_ILMETHOD *CorILM = g_pEEInterface->MethodDescGetILHeader(fd); if (CorILM == NULL ) { currentFuncData->localVarSigToken = mdSignatureNil; currentFuncData->ilStartAddress = NULL; currentFuncData->ilSize = 0; rsfd->currentSTRData->v.ILIP = NULL; currentFuncData->nativeStartAddressPtr = NULL; currentFuncData->nativeSize = 0; currentFuncData->nativenVersion = DebuggerJitInfo::DJI_VERSION_FIRST_VALID; } else { COR_ILMETHOD_DECODER ILHeader(CorILM); if (ILHeader.GetLocalVarSigTok() != 0) currentFuncData->localVarSigToken = ILHeader.GetLocalVarSigTok(); else currentFuncData->localVarSigToken = mdSignatureNil; // // currentFuncData->ilStartAddress = const_cast<BYTE*>(ILHeader.Code); currentFuncData->ilSize = ILHeader.GetCodeSize(); currentFuncData->ilnVersion = g_pDebugger->GetVersionNumber(fd); LOG((LF_CORDB,LL_INFO10000,"Sending il Ver:0x%x in stack trace!\n", currentFuncData->ilnVersion)); DebuggerJitInfo *jitInfo = g_pDebugger->GetJitInfo(fd, (const BYTE*)*pInfo->registers.pPC); if (jitInfo == NULL) { //EnC: Couldn't find the code; rsfd->currentSTRData->v.ILIP = NULL; // Note: always send back the size of the method. This // allows us to get the code, even when we haven't // been tracking. (Handling of the GetCode message // knows how to find the start address of the code, or // how to respond if is been pitched.) currentFuncData->nativeSize = g_pEEInterface->GetFunctionSize(fd); currentFuncData->nativeStartAddressPtr = NULL; currentFuncData->nativenVersion = DebuggerJitInfo::DJI_VERSION_FIRST_VALID; currentFuncData->CodeVersionToken = NULL; currentFuncData->ilToNativeMapAddr = NULL; currentFuncData->ilToNativeMapSize = 0; currentFuncData->nVersionMostRecentEnC = currentFuncData->ilnVersion; } else { LOG((LF_CORDB,LL_INFO10000,"DeTh::TASSC: Code: 0x%x Got DJI " "0x%x, from 0x%x to 0x%x\n",(const BYTE*)drd->PC,jitInfo, jitInfo->m_addrOfCode, jitInfo->m_addrOfCode + jitInfo->m_sizeOfCode)); DWORD whichIrrelevant; rsfd->currentSTRData->v.ILIP = const_cast<BYTE*>(ILHeader.Code) + jitInfo->MapNativeOffsetToIL((SIZE_T)pInfo->relOffset, &rsfd->currentSTRData->v.mapping, &whichIrrelevant); // Pass back the pointers to the sequence point map so // that the RIght Side can copy it out if needed. _ASSERTE(jitInfo->m_sequenceMapSorted); currentFuncData->ilToNativeMapAddr = jitInfo->m_sequenceMap; currentFuncData->ilToNativeMapSize = jitInfo->m_sequenceMapCount; if (!jitInfo->m_codePitched) { // It's there & life is groovy currentFuncData->nativeStartAddressPtr = &(jitInfo->m_addrOfCode); currentFuncData->nativeSize = g_pEEInterface->GetFunctionSize(fd); currentFuncData->nativenVersion = jitInfo->m_nVersion; currentFuncData->CodeVersionToken = (void *)jitInfo; } else { // It's been pitched currentFuncData->nativeStartAddressPtr = NULL; currentFuncData->nativeSize = 0; } LOG((LF_CORDB,LL_INFO10000,"Sending native Ver:0x%x Tok:0x%x in stack trace!\n", currentFuncData->nativenVersion,currentFuncData->CodeVersionToken)); } } currentFuncData->nativeOffset = (SIZE_T)pInfo->relOffset; // // Bump our pointers to the next space for the next frame. // pEvent->StackTraceResultData.traceCount++; rsfd->currentSTRData++; rsfd->eventSize += sizeof(DebuggerIPCE_STRData); } if (pInfo->chainReason != 0) { // // If we've filled this event, send it off to the Right Side // before continuing the walk. // if ((rsfd->eventSize + sizeof(DebuggerIPCE_STRData)) >= rsfd->eventMaxSize) { // // pEvent->StackTraceResultData.threadUserState = g_pEEInterface->GetUserState(t); if (rsfd->iWhich == IPC_TARGET_OUTOFPROC) { rsfd->rcThread->SendIPCEvent(rsfd->iWhich); } else { DebuggerIPCEvent *peT; peT = rsfd->rcThread->GetIPCEventSendBufferContinuation(pEvent); if (peT == NULL) { pEvent->hr = E_OUTOFMEMORY; return SWA_ABORT; } CopyEventInfo(pEvent, peT); pEvent = peT; rsfd->pEvent = peT; rsfd->eventSize = 0; } // // Reset for the next set of frames. // pEvent->StackTraceResultData.traceCount = 0; rsfd->currentSTRData = &(pEvent->StackTraceResultData.traceData); rsfd->eventSize = (UINT_PTR)(rsfd->currentSTRData) - (UINT_PTR)(pEvent); } // // Send a chain boundary // rsfd->currentSTRData->isChain = true; rsfd->currentSTRData->u.chainReason = pInfo->chainReason; rsfd->currentSTRData->u.managed = pInfo->managed; rsfd->currentSTRData->u.context = pInfo->context; rsfd->currentSTRData->fp = pInfo->fp; rsfd->currentSTRData->quicklyUnwound = pInfo->quickUnwind; #ifdef _DEBUG REGDISPLAY* rd = &rsfd->chainRegisters; #endif // _DEBUG #ifdef _X86_ LOG( (LF_CORDB, LL_INFO1000, "DT::TASSC:Registers: Edi:%d \ Esi = %x Ebx = %x Edx = %x Ecx = %x Eax = %x Ebp = %x\n", (rd->pEdi == NULL ? 0 : *(rd->pEdi)), (rd->pEsi == NULL ? 0 : *(rd->pEsi)), (rd->pEbx == NULL ? 0 : *(rd->pEbx)), (rd->pEdx == NULL ? 0 : *(rd->pEdx)), (rd->pEcx == NULL ? 0 : *(rd->pEcx)), (rd->pEax == NULL ? 0 : *(rd->pEax)), (rd->pEbp == NULL ? 0 : *(rd->pEbp))) ); #endif LOG( (LF_CORDB, LL_INFO1000, "DT::TASSC:PC: PC:%x SP:%x\n", (SIZE_T)*(rd->pPC), rd->SP)); rsfd->needChainRegisters = true; // // Bump our pointers to the next space for the next frame. // pEvent->StackTraceResultData.traceCount++; rsfd->currentSTRData++; rsfd->eventSize += sizeof(DebuggerIPCE_STRData); } return SWA_CONTINUE; }