diff options
Diffstat (limited to 'src/vm/virtualcallstub.cpp')
-rw-r--r-- | src/vm/virtualcallstub.cpp | 132 |
1 files changed, 91 insertions, 41 deletions
diff --git a/src/vm/virtualcallstub.cpp b/src/vm/virtualcallstub.cpp index d1ad6ec16d..c234e8c470 100644 --- a/src/vm/virtualcallstub.cpp +++ b/src/vm/virtualcallstub.cpp @@ -1204,6 +1204,10 @@ extern "C" PCODE STDCALL StubDispatchFixupWorker(TransitionBlock * pTransitionBl MAKE_CURRENT_THREAD_AVAILABLE(); +#ifdef _DEBUG + Thread::ObjectRefFlush(CURRENT_THREAD); +#endif + FrameWithCookie<StubDispatchFrame> frame(pTransitionBlock); StubDispatchFrame * pSDFrame = &frame; @@ -1280,12 +1284,13 @@ extern "C" PCODE STDCALL StubDispatchFixupWorker(TransitionBlock * pTransitionBl else token = DispatchToken::CreateDispatchToken(slot); - OBJECTREF pObj = pSDFrame->GetThis(); - if (pObj == NULL) { + OBJECTREF *protectedObj = pSDFrame->GetThisPtr(); + _ASSERTE(protectedObj != NULL); + if (*protectedObj == NULL) { COMPlusThrow(kNullReferenceException); } - pTarget = pMgr->ResolveWorker(&callSite, pObj, token, VirtualCallStubManager::SK_LOOKUP); + pTarget = pMgr->ResolveWorker(&callSite, protectedObj, token, VirtualCallStubManager::SK_LOOKUP); _ASSERTE(pTarget != NULL); // Ready to return @@ -1509,6 +1514,10 @@ PCODE VSD_ResolveWorker(TransitionBlock * pTransitionBlock, MAKE_CURRENT_THREAD_AVAILABLE(); +#ifdef _DEBUG + Thread::ObjectRefFlush(CURRENT_THREAD); +#endif + FrameWithCookie<StubDispatchFrame> frame(pTransitionBlock); StubDispatchFrame * pSDFrame = &frame; @@ -1516,7 +1525,9 @@ PCODE VSD_ResolveWorker(TransitionBlock * pTransitionBlock, StubCallSite callSite(siteAddrForRegisterIndirect, returnAddress); - OBJECTREF pObj = pSDFrame->GetThis(); + OBJECTREF *protectedObj = pSDFrame->GetThisPtr(); + _ASSERTE(protectedObj != NULL); + OBJECTREF pObj = *protectedObj; PCODE target = NULL; @@ -1588,7 +1599,7 @@ PCODE VSD_ResolveWorker(TransitionBlock * pTransitionBlock, } #endif - target = pMgr->ResolveWorker(&callSite, pObj, token, stubKind); + target = pMgr->ResolveWorker(&callSite, protectedObj, token, stubKind); GCPROTECT_END(); @@ -1624,7 +1635,7 @@ void VirtualCallStubManager::BackPatchWorkerStatic(PCODE returnAddress, TADDR si } PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, - OBJECTREF pObj, + OBJECTREF *protectedObj, DispatchToken token, StubKind stubKind) { @@ -1633,15 +1644,14 @@ PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, GC_TRIGGERS; MODE_COOPERATIVE; INJECT_FAULT(COMPlusThrowOM();); - PRECONDITION(pObj != NULL); + PRECONDITION(protectedObj != NULL); + PRECONDITION(*protectedObj != NULL); + PRECONDITION(IsProtectedByGCFrame(protectedObj)); } CONTRACTL_END; - MethodTable* objectType = pObj->GetMethodTable(); + MethodTable* objectType = (*protectedObj)->GetMethodTable(); CONSISTENCY_CHECK(CheckPointer(objectType)); - // pObj is not protected. Clear it in debug builds to avoid accidental use. - INDEBUG(pObj = NULL); - #ifdef STUB_LOGGING if (g_dumpLogCounter != 0) { @@ -1772,11 +1782,12 @@ PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, if (target == NULL) { CONSISTENCY_CHECK(stub == CALL_STUB_EMPTY_ENTRY); - patch = Resolver(objectType, token, &target); + patch = Resolver(objectType, token, protectedObj, &target); #if defined(_DEBUG) - if (!objectType->IsTransparentProxy() && - !objectType->IsComObjectType()) + if ( !objectType->IsTransparentProxy() && + !objectType->IsComObjectType() && + !objectType->IsICastable()) { CONSISTENCY_CHECK(!MethodTable::GetMethodDescForSlotAddress(target)->IsGenericMethodDefinition()); } @@ -2065,7 +2076,8 @@ it means that the token is not resolvable. BOOL VirtualCallStubManager::Resolver( MethodTable * pMT, - DispatchToken token, + DispatchToken token, + OBJECTREF * protectedObj, // this one can actually be NULL, consider using pMT is you don't need the object itself PCODE * ppTarget) { CONTRACTL { @@ -2215,40 +2227,73 @@ VirtualCallStubManager::Resolver( } } #ifdef FEATURE_COMINTEROP - else if (IsInterfaceToken(token)) + else if (pMT->IsComObjectType() && IsInterfaceToken(token)) { - if (pMT->IsComObjectType()) - { - MethodTable * pItfMT = GetTypeFromToken(token); - implSlot = pItfMT->FindDispatchSlot(token.GetSlotNumber()); + MethodTable * pItfMT = GetTypeFromToken(token); + implSlot = pItfMT->FindDispatchSlot(token.GetSlotNumber()); - if (pItfMT->HasInstantiation()) + if (pItfMT->HasInstantiation()) + { + DispatchSlot ds(implSlot); + MethodDesc * pTargetMD = ds.GetMethodDesc(); + if (!pTargetMD->HasMethodInstantiation()) { - DispatchSlot ds(implSlot); - MethodDesc * pTargetMD = ds.GetMethodDesc(); - if (!pTargetMD->HasMethodInstantiation()) - { - _ASSERTE(pItfMT->IsProjectedFromWinRT() || pItfMT->IsWinRTRedirectedInterface(TypeHandle::Interop_ManagedToNative)); + _ASSERTE(pItfMT->IsProjectedFromWinRT() || pItfMT->IsWinRTRedirectedInterface(TypeHandle::Interop_ManagedToNative)); - MethodDesc *pInstMD = MethodDesc::FindOrCreateAssociatedMethodDesc( - pTargetMD, - pItfMT, - FALSE, // forceBoxedEntryPoint - Instantiation(), // methodInst - FALSE, // allowInstParam - TRUE); // forceRemotableMethod + MethodDesc *pInstMD = MethodDesc::FindOrCreateAssociatedMethodDesc( + pTargetMD, + pItfMT, + FALSE, // forceBoxedEntryPoint + Instantiation(), // methodInst + FALSE, // allowInstParam + TRUE); // forceRemotableMethod - _ASSERTE(pInstMD->IsComPlusCall() || pInstMD->IsGenericComPlusCall()); + _ASSERTE(pInstMD->IsComPlusCall() || pInstMD->IsGenericComPlusCall()); - *ppTarget = pInstMD->GetStableEntryPoint(); - return TRUE; - } + *ppTarget = pInstMD->GetStableEntryPoint(); + return TRUE; } - - fShouldPatch = TRUE; } + + fShouldPatch = TRUE; } #endif // FEATURE_COMINTEROP +#ifdef FEATURE_ICASTABLE + else if (pMT->IsICastable() && protectedObj != NULL && *protectedObj != NULL) + { + GCStress<cfg_any>::MaybeTrigger(); + + // In case of ICastable, instead of trying to find method implementation in the real object type + // we call pObj.GetValueInternal() and call Resolver() again with whatever type it returns. + // It allows objects that implement ICastable to mimic behavior of other types. + MethodTable * pTokenMT = GetTypeFromToken(token); + + // Make call to obj.GetImplType(interfaceTypeObj) + MethodDesc *pGetImplTypeMD = pMT->GetMethodDescForInterfaceMethod(MscorlibBinder::GetMethod(METHOD__ICASTABLE__GETIMPLTYPE)); + OBJECTREF tokenManagedType = pTokenMT->GetManagedClassObject(); //GC triggers + + PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(pGetImplTypeMD); + + DECLARE_ARGHOLDER_ARRAY(args, 2); + args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(*protectedObj); + args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(tokenManagedType); + + OBJECTREF impTypeObj = NULL; + CALL_MANAGED_METHOD_RETREF(impTypeObj, OBJECTREF, args); + + INDEBUG(tokenManagedType = NULL); //tokenManagedType wasn't protected during the call + if (impTypeObj == NULL) // GetImplType returns default(RuntimeTypeHandle) + { + COMPlusThrow(kEntryPointNotFoundException); + } + + ReflectClassBaseObject* resultTypeObj = ((ReflectClassBaseObject*)OBJECTREFToObject(impTypeObj)); + TypeHandle resulTypeHnd = resultTypeObj->GetType(); + MethodTable *pResultMT = resulTypeHnd.GetMethodTable(); + + return Resolver(pResultMT, token, protectedObj, ppTarget); + } +#endif // FEATURE_ICASTABLE if (implSlot.IsNull()) { @@ -2586,7 +2631,10 @@ VirtualCallStubManager::GetTarget( // No match, now do full resolve BOOL fPatch; - fPatch = Resolver(pMT, token, &target); + + // TODO: passing NULL as protectedObj here can lead to incorrect behavior for ICastable objects + // We need to review if this is the case and refactor this code if we want ICastable to become officially supported + fPatch = Resolver(pMT, token, NULL, &target); _ASSERTE(target != NULL); #ifndef STUB_DISPATCH_PORTABLE @@ -4162,7 +4210,9 @@ MethodDesc *VirtualCallStubManagerManager::Entry2MethodDesc( CONSISTENCY_CHECK(!pMT->IsTransparentProxy()); PCODE target = NULL; - VirtualCallStubManager::Resolver(pMT, token, &target); + // TODO: passing NULL as protectedObj here can lead to incorrect behavior for ICastable objects + // We need to review if this is the case and refactor this code if we want ICastable to become officially supported + VirtualCallStubManager::Resolver(pMT, token, NULL, &target); return pMT->GetMethodDescForSlotAddress(target); } |