1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ===========================================================================
7 // Signature encoding for zapper (ngen)
10 // ===========================================================================
17 #include "sigbuilder.h"
19 #ifndef DACCESS_COMPILE
21 BOOL ZapSig::GetSignatureForTypeDesc(TypeDesc * desc, SigBuilder * pSigBuilder)
30 CorElementType elemType = desc->GetInternalCorElementType();
32 if (elemType == ELEMENT_TYPE_VALUETYPE)
34 // convert to ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG so that the right
35 // thing will happen in code:SigPointer.GetTypeHandleThrowing
36 elemType = (CorElementType) ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG;
38 else if (elemType == ELEMENT_TYPE_VAR || elemType == ELEMENT_TYPE_MVAR)
40 // Enable encoding of type variables for NGen signature only. IBC toolchain is not aware of them yet.
41 if (context.externalTokens == ZapSig::NormalTokens)
42 elemType = (CorElementType) ELEMENT_TYPE_VAR_ZAPSIG;
45 pSigBuilder->AppendElementType(elemType);
47 if (desc->HasTypeParam())
49 if (!this->GetSignatureForTypeHandle(desc->GetTypeParam(), pSigBuilder))
52 if (elemType == ELEMENT_TYPE_ARRAY)
54 ArrayTypeDesc *pArrayDesc = dac_cast<PTR_ArrayTypeDesc>(desc);
55 _ASSERTE(pArrayDesc->GetRank() != 0);
56 pSigBuilder->AppendData(pArrayDesc->GetRank());
57 pSigBuilder->AppendData(0);
58 pSigBuilder->AppendData(0);
63 switch ((DWORD)elemType)
65 case ELEMENT_TYPE_FNPTR:
67 FnPtrTypeDesc *pTD = dac_cast<PTR_FnPtrTypeDesc>(desc);
69 // Emit calling convention
70 pSigBuilder->AppendByte(pTD->GetCallConv());
73 unsigned numArgs = pTD->GetNumArgs();
74 pSigBuilder->AppendData(numArgs);
76 // return type and args
77 TypeHandle *retAndArgTypes = pTD->GetRetAndArgTypesPointer();
78 for (DWORD i = 0; i <= numArgs; i++)
80 TypeHandle th = retAndArgTypes[i];
81 // This should be a consequence of the type key being restored
82 CONSISTENCY_CHECK(!th.IsNull() && !th.IsEncodedFixup());
83 if (!this->GetSignatureForTypeHandle(th, pSigBuilder))
89 case ELEMENT_TYPE_MVAR:
90 // _ASSERTE(!"Cannot encode ET_MVAR in a ZapSig");
93 case ELEMENT_TYPE_VAR:
94 // _ASSERTE(!"Cannot encode ET_VAR in a ZapSig");
97 case ELEMENT_TYPE_VAR_ZAPSIG:
99 TypeVarTypeDesc * pTypeVarDesc = dac_cast<PTR_TypeVarTypeDesc>(desc);
100 Module * pVarTypeModule = pTypeVarDesc->GetModule();
101 if (pVarTypeModule != this->context.pInfoModule)
103 DWORD index = (*this->pfnEncodeModule)(this->context.pModuleContext, pVarTypeModule);
105 if (index == ENCODE_MODULE_FAILED)
108 // emit the ET_MODULE_ZAPSIG escape
109 pSigBuilder->AppendElementType((CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG);
110 // emit the module index
111 pSigBuilder->AppendData(index);
113 pSigBuilder->AppendData(RidFromToken(pTypeVarDesc->GetToken()));
118 _ASSERTE(!"Bad type");
127 // Create a signature for a typeHandle
128 // It can be decoded using MetaSig::GetTypeHandleThrowing
129 // The tokens are espressed relative to this->pInfoModule
130 // When handle.GetModule() != this->pInfoModule), we escape the signature
131 // with an ELEMENT_TYPE_MODULE_ZAPSIG <id-num> <token> to encode
132 // a temporary change of module
134 // Returns the number of characters written into the buffer.
135 // If buffer and bufferMax are NULL, it returns the number of
136 // characters that would have been written.
137 // If the buffer isn't big enough it doesn't write past bufferMax
138 // A return value of 0 indidates a failure to encode the signature
140 BOOL ZapSig::GetSignatureForTypeHandle(TypeHandle handle,
141 SigBuilder * pSigBuilder)
148 PRECONDITION(CheckPointer(handle));
149 PRECONDITION(CheckPointer(this->context.pInfoModule));
150 PRECONDITION(!handle.HasUnrestoredTypeKey());
155 if (handle.IsTypeDesc())
156 return GetSignatureForTypeDesc(handle.AsTypeDesc(), pSigBuilder);
158 MethodTable *pMT = handle.AsMethodTable();
160 // Can we encode the type using a short ET encoding?
162 CorElementType elemType = TryEncodeUsingShortcut(pMT);
163 if (elemType != ELEMENT_TYPE_END)
165 _ASSERTE(pMT->IsTypicalTypeDefinition());
167 // Check for an array type and encode that we are dealing with a MethodTable representation
168 if (elemType == ELEMENT_TYPE_SZARRAY || elemType == ELEMENT_TYPE_ARRAY)
170 pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
171 pSigBuilder->AppendElementType(elemType);
173 TypeHandle elementType = pMT->GetApproxArrayElementTypeHandle();
174 if (!this->GetSignatureForTypeHandle(elementType, pSigBuilder))
177 if (elemType == ELEMENT_TYPE_ARRAY)
179 pSigBuilder->AppendData(pMT->GetRank());
180 pSigBuilder->AppendData(0);
181 pSigBuilder->AppendData(0);
186 pSigBuilder->AppendElementType(elemType);
192 // We could not encode the type using a short encoding
193 // and we have a handle that represents a Class or ValueType
195 // We may need to emit an out-of-module escape sequence
197 Module *pTypeHandleModule = pMT->GetModule_NoLogging();
199 // If the type handle's module is different that the this->pInfoModule
200 // we will need to add an out-of-module escape for the type
203 mdToken token = pMT->GetCl_NoLogging();
204 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
205 if (pTypeHandleModule != this->context.pInfoModule && !pTypeHandleModule->IsInCurrentVersionBubble())
207 pTypeHandleModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
208 token = pTypeHandleModule->LookupTypeRefByMethodTable(pMT);
211 if (pTypeHandleModule != this->context.pInfoModule)
213 // During IBC profiling this calls
214 // code:Module.EncodeModuleHelper
215 // During ngen this calls
216 // code:ZapImportTable.EncodeModuleHelper)
218 index = (*this->pfnEncodeModule)(this->context.pModuleContext, pTypeHandleModule);
220 if (index == ENCODE_MODULE_FAILED)
223 // emit the ET_MODULE_ZAPSIG escape
224 pSigBuilder->AppendElementType((CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG);
225 // emit the module index
226 pSigBuilder->AppendData(index);
229 // Remember if we have an instantiated generic type
230 bool fNeedsInstantiation = pMT->HasInstantiation() && !pMT->IsGenericTypeDefinition();
232 // We possibly have an instantiated generic type
233 if (fNeedsInstantiation)
235 pSigBuilder->AppendElementType(ELEMENT_TYPE_GENERICINST);
238 // Beware of enums! Can't use GetInternalCorElementType() here.
239 pSigBuilder->AppendElementType(pMT->IsValueType() ? ELEMENT_TYPE_VALUETYPE : ELEMENT_TYPE_CLASS);
241 _ASSERTE(!IsNilToken(token));
242 if (IsNilToken(token))
245 if ((index != 0) && (this->pfnTokenDefinition != NULL))
248 // We do not want to log the metadata lookups that we perform here
250 IBCLoggingDisabler disableLogging;
252 // During IBC profiling this calls
253 // code:Module::TokenDefinitionHelper
254 (*this->pfnTokenDefinition)(this->context.pModuleContext, pTypeHandleModule, index, &token);
256 // ibcExternalType tokens are actually encoded as mdtTypeDef tokens in the signature
257 _ASSERT(TypeFromToken(token) == ibcExternalType);
258 token = TokenFromRid(RidFromToken(token), mdtTypeDef);
261 pSigBuilder->AppendToken(token);
263 if (fNeedsInstantiation)
265 pSigBuilder->AppendData(pMT->GetNumGenericArgs());
266 Instantiation inst = pMT->GetInstantiation();
267 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
269 TypeHandle t = inst[i];
270 CONSISTENCY_CHECK(!t.IsNull() && !t.IsEncodedFixup());
271 if (!this->GetSignatureForTypeHandle(t, pSigBuilder))
278 #endif // #ifndef DACCESS_COMPILE
281 // Returns element type when the typeHandle can be encoded using
282 // using a single CorElementType value
283 // This includes using ELEMENT_TYPE_CANON_ZAPSIG for the System.__Canon type
285 /*static */ CorElementType ZapSig::TryEncodeUsingShortcut(/* in */ MethodTable * pMT)
287 LIMITED_METHOD_CONTRACT;
289 CorElementType elemType = ELEMENT_TYPE_END; // An illegal value that we check for later
291 // Set elemType to a shortcut encoding whenever possible
293 if (pMT->IsTruePrimitive())
294 elemType = pMT->GetInternalCorElementType();
295 else if (pMT == g_pObjectClass)
296 elemType = ELEMENT_TYPE_OBJECT;
297 else if (pMT == g_pStringClass)
298 elemType = ELEMENT_TYPE_STRING;
299 else if (pMT == g_pCanonMethodTableClass)
300 elemType = (CorElementType) ELEMENT_TYPE_CANON_ZAPSIG;
301 else if (pMT->IsArray())
302 elemType = pMT->GetInternalCorElementType(); // either ELEMENT_TYPE_SZARRAY or ELEMENT_TYPE_ARRAY
308 // Compare a metadata signature element with a type handle
309 // The type handle must have a fully restored type key, which in turn means that modules for all of its
310 // components are loaded (e.g. type arguments to an instantiated type).
312 // Hence we can do the signature comparison without incurring any loads or restores.
314 /*static*/ BOOL ZapSig::CompareSignatureToTypeHandle(PCCOR_SIGNATURE pSig,
317 const ZapSig::Context * pZapSigContext)
325 PRECONDITION(CheckPointer(pModule));
326 PRECONDITION(CheckPointer(pZapSigContext));
327 PRECONDITION(CheckPointer(pZapSigContext->pModuleContext));
328 PRECONDITION(CheckPointer(pZapSigContext->pInfoModule));
329 PRECONDITION(CheckPointer(handle));
330 PRECONDITION(CheckPointer(pSig));
331 PRECONDITION(!handle.HasUnrestoredTypeKey());
338 // pOrigModule is the original module that contained this ZapSig
340 Module * pOrigModule = pZapSigContext->pInfoModule;
341 CorElementType sigType = CorSigUncompressElementType(pSig);
342 CorElementType handleType = handle.GetSignatureCorElementType();
344 switch ((DWORD)sigType)
349 _ASSERTE(!"Unknown type in ZapSig::CompareSignatureToTypeHandle");
353 case ELEMENT_TYPE_MODULE_ZAPSIG:
355 DWORD ix = CorSigUncompressData(pSig);
356 CONTRACT_VIOLATION(ThrowsViolation|GCViolation);
357 pModule = pZapSigContext->GetZapSigModule()->GetModuleFromIndexIfLoaded(ix);
361 RETURN(CompareSignatureToTypeHandle(pSig, pModule, handle, pZapSigContext));
366 case ELEMENT_TYPE_VOID:
367 case ELEMENT_TYPE_I1:
368 case ELEMENT_TYPE_U1:
369 case ELEMENT_TYPE_I2:
370 case ELEMENT_TYPE_U2:
371 case ELEMENT_TYPE_I4:
372 case ELEMENT_TYPE_U4:
373 case ELEMENT_TYPE_I8:
374 case ELEMENT_TYPE_U8:
375 case ELEMENT_TYPE_R4:
376 case ELEMENT_TYPE_R8:
377 case ELEMENT_TYPE_BOOLEAN:
378 case ELEMENT_TYPE_CHAR:
379 case ELEMENT_TYPE_TYPEDBYREF:
380 RETURN(sigType == handleType);
382 case ELEMENT_TYPE_STRING:
383 RETURN(handle == TypeHandle(g_pStringClass));
385 case ELEMENT_TYPE_OBJECT:
386 RETURN(handle == TypeHandle(g_pObjectClass));
388 case ELEMENT_TYPE_CANON_ZAPSIG:
389 RETURN(handle == TypeHandle(g_pCanonMethodTableClass));
391 case ELEMENT_TYPE_VAR:
392 case ELEMENT_TYPE_MVAR:
394 if (sigType != handleType)
397 unsigned varNum = CorSigUncompressData(pSig);
398 RETURN(varNum == (dac_cast<PTR_TypeVarTypeDesc>(handle.AsTypeDesc())->GetIndex()));
401 case ELEMENT_TYPE_VAR_ZAPSIG:
403 if (!handle.IsGenericVariable())
406 TypeVarTypeDesc *pTypeVarTypeDesc = handle.AsGenericVariable();
408 unsigned rid = CorSigUncompressData(pSig);
409 RETURN(TokenFromRid(rid, mdtGenericParam) == pTypeVarTypeDesc->GetToken() && pModule == pTypeVarTypeDesc->GetModule());
412 // These take an additional argument, which is the element type
413 case ELEMENT_TYPE_SZARRAY:
414 case ELEMENT_TYPE_PTR:
415 case ELEMENT_TYPE_BYREF:
417 if (sigType != handleType)
420 RETURN (CompareSignatureToTypeHandle(pSig, pModule, handle.GetTypeParam(), pZapSigContext));
423 case ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG:
425 if (handle.IsTypeDesc() || !handle.AsMethodTable()->IsArray())
428 RETURN (CompareSignatureToTypeHandle(pSig, pModule, handle, pZapSigContext));
431 case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG:
433 sigType = CorSigUncompressElementType(pSig);
434 _ASSERTE(sigType == ELEMENT_TYPE_VALUETYPE);
436 if (!handle.IsNativeValueType()) RETURN(FALSE);
439 case ELEMENT_TYPE_VALUETYPE:
440 case ELEMENT_TYPE_CLASS:
442 CorSigUncompressToken(pSig, &tk);
443 if (TypeFromToken(tk) == mdtTypeRef)
445 BOOL resolved = FALSE;
448 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
449 resolved = ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pModule, &tk, Loader::DontLoad);
454 EX_END_CATCH(SwallowAllExceptions);
458 _ASSERTE(TypeFromToken(tk) == mdtTypeDef);
459 RETURN (sigType == handleType && !handle.HasInstantiation() && pModule == handle.GetModule() && handle.GetCl() == tk);
462 case ELEMENT_TYPE_FNPTR:
464 if (sigType != handleType)
467 FnPtrTypeDesc *pTD = handle.AsFnPtrType();
468 DWORD callConv = CorSigUncompressData(pSig);
469 if (callConv != pTD->GetCallConv())
472 DWORD numArgs = CorSigUncompressData(pSig);
473 if (numArgs != pTD->GetNumArgs())
477 CONTRACT_VIOLATION(ThrowsViolation|GCViolation);
479 for (DWORD i = 0; i <= numArgs; i++)
482 if (!CompareSignatureToTypeHandle(pSig, pOrigModule, pTD->GetRetAndArgTypes()[i], pZapSigContext))
484 if (FAILED(sp.SkipExactlyOne()))
494 case ELEMENT_TYPE_GENERICINST:
496 if (!handle.HasInstantiation())
499 sigType = CorSigUncompressElementType(pSig);
500 if (sigType != handleType)
503 pSig += CorSigUncompressToken(pSig, &tk);
504 if (TypeFromToken(tk) == mdtTypeRef)
506 BOOL resolved = FALSE;
509 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
510 resolved = ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pModule, &tk, Loader::DontLoad);
515 EX_END_CATCH(SwallowAllExceptions);
519 _ASSERTE(TypeFromToken(tk) == mdtTypeDef);
520 if (pModule != handle.GetModule() || tk != handle.GetCl())
523 DWORD numGenericArgs = CorSigUncompressData(pSig);
525 if (numGenericArgs != handle.GetNumGenericArgs())
528 Instantiation inst = handle.GetInstantiation();
529 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
532 if (!CompareSignatureToTypeHandle(pSig, pOrigModule, inst[i], pZapSigContext))
534 if (FAILED(sp.SkipExactlyOne()))
543 case ELEMENT_TYPE_ARRAY:
545 if (sigType != handleType)
548 if (!CompareSignatureToTypeHandle(pSig, pModule, handle.GetTypeParam(), pZapSigContext))
551 if (FAILED(sp.SkipExactlyOne()))
555 if (FAILED(sp.GetData(&rank)))
558 if (rank != handle.AsArray()->GetRank())
568 #ifdef FEATURE_PREJIT
570 BOOL ZapSig::CompareFixupToTypeHandle(Module * pModule, TADDR fixup, TypeHandle handle)
578 PRECONDITION(CORCOMPILE_IS_POINTER_TAGGED(fixup));
579 PRECONDITION(CheckPointer(pModule));
583 Module *pDefiningModule;
584 PCCOR_SIGNATURE pSig = pModule->GetEncodedSigIfLoaded(CORCOMPILE_UNTAG_TOKEN(fixup), &pDefiningModule);
585 if (pDefiningModule == NULL)
588 ZapSig::Context zapSigContext(pDefiningModule, pModule);
589 return ZapSig::CompareSignatureToTypeHandle(pSig, pDefiningModule, handle, &zapSigContext);
591 #endif // FEATURE_PREJIT
594 BOOL ZapSig::CompareTypeHandleFieldToTypeHandle(TypeHandle *pTypeHnd, TypeHandle typeHnd2)
602 PRECONDITION(CheckPointer(pTypeHnd));
603 PRECONDITION(CheckPointer(typeHnd2));
604 PRECONDITION(!CORCOMPILE_IS_POINTER_TAGGED((SIZE_T) typeHnd2.AsPtr()));
608 // Ensure that the compiler won't fetch the value twice
609 SIZE_T fixup = VolatileLoadWithoutBarrier((SIZE_T *)pTypeHnd);
611 #ifdef FEATURE_PREJIT
612 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
614 Module *pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pTypeHnd));
615 CONSISTENCY_CHECK(pContainingModule != NULL);
617 Module *pDefiningModule;
618 PCCOR_SIGNATURE pSig = pContainingModule->GetEncodedSigIfLoaded(CORCOMPILE_UNTAG_TOKEN(fixup), &pDefiningModule);
619 if (pDefiningModule == NULL)
623 ZapSig::Context zapSigContext(pDefiningModule, pContainingModule);
624 ZapSig::Context * pZapSigContext = &zapSigContext;
625 return CompareSignatureToTypeHandle(pSig, pDefiningModule, typeHnd2, pZapSigContext);
629 #endif // FEATURE_PREJIT
630 return TypeHandle::FromTAddr(fixup) == typeHnd2;
633 #ifndef DACCESS_COMPILE
634 Module *ZapSig::DecodeModuleFromIndex(Module *fromModule,
645 Assembly *pAssembly = NULL;
649 pAssembly = fromModule->GetAssembly();
653 if (index < fromModule->GetAssemblyRefMax())
655 pAssembly = fromModule->LoadAssembly(RidToToken(index, mdtAssemblyRef))->GetAssembly();
659 index -= fromModule->GetAssemblyRefMax();
661 pAssembly = fromModule->GetNativeMetadataAssemblyRefFromCache(index);
663 if(pAssembly == NULL)
666 spec.InitializeSpec(TokenFromRid(index, mdtAssemblyRef),
667 fromModule->GetNativeAssemblyImport(),
670 pAssembly = spec.LoadAssembly(FILE_LOADED);
672 fromModule->SetNativeMetadataAssemblyRefInCache(index, pAssembly);
677 return pAssembly->GetManifestModule();
680 Module *ZapSig::DecodeModuleFromIndexIfLoaded(Module *fromModule,
691 Assembly *pAssembly = NULL;
692 mdAssemblyRef tkAssemblyRef;
695 pAssembly = fromModule->GetAssembly();
698 if (index < fromModule->GetAssemblyRefMax())
700 tkAssemblyRef = RidToToken(index, mdtAssemblyRef);
701 pAssembly = fromModule->GetAssemblyIfLoaded(tkAssemblyRef);
705 index -= fromModule->GetAssemblyRefMax();
706 tkAssemblyRef = RidToToken(index, mdtAssemblyRef);
707 IMDInternalImport * pMDImportOverride = fromModule->GetNativeAssemblyImport(FALSE);
708 if (pMDImportOverride != NULL)
710 CHAR szFullName[MAX_CLASS_NAME + 1];
711 LPCSTR szWinRtNamespace = NULL;
712 LPCSTR szWinRtClassName = NULL;
714 BOOL fValidAssemblyRef = TRUE;
715 LPCSTR pAssemblyName;
717 if (FAILED(pMDImportOverride->GetAssemblyRefProps(tkAssemblyRef,
725 { // Unexpected failure reading MetaData
726 fValidAssemblyRef = FALSE;
729 if (fValidAssemblyRef && IsAfContentType_WindowsRuntime(dwFlags))
731 // Find the encoded type name
732 LPCSTR pTypeName = NULL;
733 if (pAssemblyName != NULL)
734 pTypeName = strchr(pAssemblyName, '!');
736 if (pTypeName != NULL)
739 // pTypeName now contains the full type name (namespace + name)
741 strcpy_s(szFullName, _countof(szFullName), pTypeName);
742 LPSTR pszName = strrchr(szFullName, '.');
744 // WinRT types must have a namespace
747 // Replace . between namespace and name with null terminator.
748 // This breaks the string into a namespace and name pair.
752 szWinRtNamespace = szFullName;
753 szWinRtClassName = pszName;
756 { // Namespace '.' separator not found - invalid type name (namespace has to be always present)
757 fValidAssemblyRef = FALSE;
761 { // Type name separator in assembly name '!' not found
762 fValidAssemblyRef = FALSE;
766 if (fValidAssemblyRef)
768 pAssembly = fromModule->GetAssemblyIfLoaded(
778 if (pAssembly == NULL)
781 return pAssembly->GetManifestModule();
785 TypeHandle ZapSig::DecodeType(Module *pEncodeModuleContext,
787 PCCOR_SIGNATURE pBuffer,
788 ClassLoadLevel level)
798 SigPointer p(pBuffer);
800 ZapSig::Context zapSigContext(pInfoModule, pEncodeModuleContext);
801 ZapSig::Context * pZapSigContext = &zapSigContext;
803 SigTypeContext typeContext; // empty context is OK: encoding should not contain type variables.
805 TypeHandle th = p.GetTypeHandleThrowing(pInfoModule,
807 ClassLoader::LoadTypes,
809 level < CLASS_LOADED, // For non-full loads, drop a level when loading generic arguments
816 MethodDesc *ZapSig::DecodeMethod(Module *pReferencingModule,
818 PCCOR_SIGNATURE pBuffer,
819 TypeHandle * ppTH /*=NULL*/)
821 STANDARD_VM_CONTRACT;
823 SigTypeContext typeContext; // empty context is OK: encoding should not contain type variables.
825 return DecodeMethod(pReferencingModule, pInfoModule, pBuffer, &typeContext, ppTH);
828 MethodDesc *ZapSig::DecodeMethod(Module *pReferencingModule,
830 PCCOR_SIGNATURE pBuffer,
831 SigTypeContext *pContext,
832 TypeHandle *ppTH, /*=NULL*/
833 PCCOR_SIGNATURE *ppOwnerTypeSpecWithVars, /*=NULL*/
834 PCCOR_SIGNATURE *ppMethodSpecWithVars /*=NULL*/)
836 STANDARD_VM_CONTRACT;
838 MethodDesc *pMethod = NULL;
840 SigPointer sig(pBuffer);
842 ZapSig::Context zapSigContext(pInfoModule, (void *)pReferencingModule, ZapSig::NormalTokens);
843 ZapSig::Context * pZapSigContext = &zapSigContext;
847 IfFailThrow(sig.GetData(&methodFlags));
849 TypeHandle thOwner = NULL;
851 if ( methodFlags & ENCODE_METHOD_SIG_OwnerType )
853 if (ppOwnerTypeSpecWithVars != NULL)
854 *ppOwnerTypeSpecWithVars = sig.GetPtr();
856 thOwner = sig.GetTypeHandleThrowing(pInfoModule,
858 ClassLoader::LoadTypes,
864 IfFailThrow(sig.SkipExactlyOne());
867 if ( methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken )
869 // get the method desc using slot number
871 IfFailThrow(sig.GetData(&slot));
873 _ASSERTE(!thOwner.IsNull());
875 pMethod = thOwner.GetMethodTable()->GetMethodDescForSlot(slot);
880 // decode method token
883 IfFailThrow(sig.GetData(&rid));
885 if (methodFlags & ENCODE_METHOD_SIG_MemberRefToken)
887 if (thOwner.IsNull())
890 MethodDesc * pMD = NULL;
891 FieldDesc * pFD = NULL;
893 MemberLoader::GetDescFromMemberRef(pInfoModule, TokenFromRid(rid, mdtMemberRef), &pMD, &pFD, NULL, FALSE, &th);
894 _ASSERTE(pMD != NULL);
901 pMethod = MemberLoader::GetMethodDescFromMemberRefAndType(pInfoModule, TokenFromRid(rid, mdtMemberRef), thOwner.GetMethodTable());
906 pMethod = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, TokenFromRid(rid, mdtMethodDef), FALSE);
910 if (thOwner.IsNull())
911 thOwner = pMethod->GetMethodTable();
916 // Ensure that the methoddescs dependencies have been walked sufficiently for type forwarders to be resolved.
917 // This method is actually basically a nop for dependencies which are ngen'd, but is real work for jitted
918 // dependencies. (However, this shouldn't be meaningful work that wouldn't happen in any case very soon.)
919 pMethod->PrepareForUseAsADependencyOfANativeImage();
923 // Instantiate the method if needed, or create a stub to a static method in a generic class.
924 if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
926 if (ppMethodSpecWithVars != NULL)
927 *ppMethodSpecWithVars = sig.GetPtr();
930 IfFailThrow(sig.GetData(&nargs));
935 if (!ClrSafeInt<SIZE_T>::multiply(nargs, sizeof(TypeHandle), cbMem/* passed by ref */))
936 ThrowHR(COR_E_OVERFLOW);
938 TypeHandle * pInst = (TypeHandle*) _alloca(cbMem);
940 for (DWORD i = 0; i < nargs; i++)
942 pInst[i] = sig.GetTypeHandleThrowing(pInfoModule,
944 ClassLoader::LoadTypes,
949 IfFailThrow(sig.SkipExactlyOne());
952 inst = Instantiation(pInst, nargs);
956 inst = pMethod->GetMethodInstantiation();
960 // This must be called even if nargs == 0, in order to create an instantiating
961 // stub for static methods in generic classees if needed, also for BoxedEntryPointStubs
962 // in non-generic structs.
963 BOOL isInstantiatingStub = (methodFlags & ENCODE_METHOD_SIG_InstantiatingStub);
964 BOOL isUnboxingStub = (methodFlags & ENCODE_METHOD_SIG_UnboxingStub);
966 pMethod = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethod, thOwner.GetMethodTable(),
969 !(isInstantiatingStub || isUnboxingStub));
971 g_IBCLogger.LogMethodDescAccess(pMethod);
973 if (methodFlags & ENCODE_METHOD_SIG_Constrained)
975 TypeHandle constrainedType = sig.GetTypeHandleThrowing(pInfoModule,
977 ClassLoader::LoadTypes,
983 MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(thOwner.GetMethodTable(), pMethod);
984 if (directMethod == NULL)
986 // Method on value type was removed. Boxing stub would need to be generated to handle this case.
987 _ASSERTE(!"Constrained method resolution failed");
989 MemberLoader::ThrowMissingMethodException(constrainedType.GetMethodTable(), NULL, NULL, NULL, 0, NULL);
992 // Strip the instantiating stub if the signature did not ask for one
993 if (directMethod->IsInstantiatingStub() && !isInstantiatingStub)
995 pMethod = directMethod->GetWrappedMethodDesc();
999 pMethod = directMethod;
1006 FieldDesc * ZapSig::DecodeField(Module *pReferencingModule,
1007 Module *pInfoModule,
1008 PCCOR_SIGNATURE pBuffer,
1009 TypeHandle *ppTH /*=NULL*/)
1019 SigTypeContext typeContext; // empty context is OK: encoding should not contain type variables.
1021 return DecodeField(pReferencingModule, pInfoModule, pBuffer, &typeContext, ppTH);
1024 FieldDesc * ZapSig::DecodeField(Module *pReferencingModule,
1025 Module *pInfoModule,
1026 PCCOR_SIGNATURE pBuffer,
1027 SigTypeContext *pContext,
1028 TypeHandle *ppTH /*=NULL*/)
1038 FieldDesc *pField = NULL;
1040 SigPointer sig(pBuffer);
1043 IfFailThrow(sig.GetData(&fieldFlags));
1045 MethodTable *pOwnerMT = NULL;
1047 if (fieldFlags & ENCODE_FIELD_SIG_OwnerType)
1049 ZapSig::Context zapSigContext(pInfoModule, pReferencingModule);
1050 ZapSig::Context * pZapSigContext = &zapSigContext;
1052 pOwnerMT = sig.GetTypeHandleThrowing(pInfoModule,
1054 ClassLoader::LoadTypes,
1058 pZapSigContext).GetMethodTable();
1060 IfFailThrow(sig.SkipExactlyOne());
1063 if (fieldFlags & ENCODE_FIELD_SIG_IndexInsteadOfToken)
1065 // get the field desc using index
1067 IfFailThrow(sig.GetData(&fieldIndex));
1069 _ASSERTE(pOwnerMT != NULL);
1071 pField = pOwnerMT->GetFieldDescByIndex(fieldIndex);
1072 _ASSERTE(pOwnerMT == pField->GetApproxEnclosingMethodTable());
1077 IfFailThrow(sig.GetData(&rid));
1079 if (fieldFlags & ENCODE_FIELD_SIG_MemberRefToken)
1081 if (pOwnerMT == NULL)
1084 MethodDesc * pMD = NULL;
1085 FieldDesc * pFD = NULL;
1087 MemberLoader::GetDescFromMemberRef(pInfoModule, TokenFromRid(rid, mdtMemberRef), &pMD, &pFD, NULL, FALSE, &th);
1088 _ASSERTE(pFD != NULL);
1094 pField = MemberLoader::GetFieldDescFromMemberRefAndType(pInfoModule, TokenFromRid(rid, mdtMemberRef), pOwnerMT);
1099 pField = MemberLoader::GetFieldDescFromFieldDef(pInfoModule, TokenFromRid(rid, mdtFieldDef), FALSE);
1104 *ppTH = (pOwnerMT != NULL) ? pOwnerMT : pField->GetApproxEnclosingMethodTable();
1110 BOOL ZapSig::EncodeMethod(
1111 MethodDesc * pMethod,
1112 Module * pInfoModule,
1113 SigBuilder * pSigBuilder,
1114 LPVOID pEncodeModuleContext,
1115 ENCODEMODULE_CALLBACK pfnEncodeModule,
1116 DEFINETOKEN_CALLBACK pfnDefineToken,
1117 CORINFO_RESOLVED_TOKEN * pResolvedToken,
1118 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
1119 BOOL fEncodeUsingResolvedTokenSpecStreams)
1129 TypeHandle ownerType;
1131 #ifdef FEATURE_READYTORUN_COMPILER
1133 // For methods encoded outside of the version bubble, we use pResolvedToken which describes the metadata token from which the method originated
1134 // For tokens inside the version bubble we are not constrained by the contents of pResolvedToken and as such we skip this codepath
1135 // Generic interfaces in canonical form are an exception, we need to get the real type from the pResolvedToken so that the lookup at runtime
1136 // can find the type in interface map.
1137 // FUTURE: This condition should likely be changed or reevaluated once support for smaller version bubbles is implemented.
1138 if (IsReadyToRunCompilation() && (!IsLargeVersionBubbleEnabled() || !pMethod->GetModule()->IsInCurrentVersionBubble() || (pMethod->IsSharedByGenericInstantiations() && pMethod->IsInterface())))
1140 if (pMethod->IsNDirect())
1142 ownerType = pMethod->GetMethodTable_NoLogging();
1146 if (pResolvedToken == NULL)
1148 _ASSERTE(!"CORINFO_RESOLVED_TOKEN required to encode method!");
1152 // Encode the referencing method type
1153 ownerType = TypeHandle(pResolvedToken->hClass);
1159 ownerType = pMethod->GetMethodTable_NoLogging();
1162 ZapSig::ExternalTokens externalTokens = ZapSig::NormalTokens;
1163 if (pfnDefineToken != NULL)
1165 externalTokens = ZapSig::IbcTokens;
1168 ZapSig zapSig(pInfoModule, pEncodeModuleContext, externalTokens,
1169 (EncodeModuleCallback) pfnEncodeModule,
1170 (TokenDefinitionCallback) pfnDefineToken);
1173 // output the sequence that represents the token for the method
1175 mdMethodDef methodToken = pMethod->GetMemberDef_NoLogging();
1176 DWORD methodFlags = 0;
1177 BOOL fMethodNeedsInstantiation = pMethod->HasMethodInstantiation() && !pMethod->IsGenericMethodDefinition();
1179 if (pMethod->IsUnboxingStub())
1180 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
1181 if (pMethod->IsInstantiatingStub())
1182 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
1183 if (fMethodNeedsInstantiation)
1184 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
1187 // For backward compatibility, IBC tokens use slightly different encoding:
1188 // - Owning type is uncoditionally encoded
1189 // - Number of method instantiation arguments is not encoded
1191 if (externalTokens == ZapSig::IbcTokens)
1193 // The type is always encoded before flags for IBC
1194 if (!zapSig.GetSignatureForTypeHandle(ownerType, pSigBuilder))
1199 // Assume that the owner type is going to be needed
1200 methodFlags |= ENCODE_METHOD_SIG_OwnerType;
1203 #ifdef FEATURE_READYTORUN_COMPILER
1204 if (IsReadyToRunCompilation() && (pConstrainedResolvedToken != NULL))
1206 methodFlags |= ENCODE_METHOD_SIG_Constrained;
1209 // FUTURE: This condition should likely be changed or reevaluated once support for smaller version bubbles is implemented.
1210 if (IsReadyToRunCompilation() && (!IsLargeVersionBubbleEnabled() || !pMethod->GetModule()->IsInCurrentVersionBubble()))
1212 Module * pReferencingModule = pMethod->IsNDirect() ?
1213 pMethod->GetModule() :
1214 (Module *)pResolvedToken->tokenScope;
1216 if (!pReferencingModule->IsInCurrentVersionBubble())
1218 // FUTURE: Encoding of new cross-module references for ReadyToRun
1219 // This warning is hit for recursive cross-module inlining. It is commented out to avoid noise.
1220 // GetSvcLogger()->Printf(W("ReadyToRun: Method reference outside of current version bubble cannot be encoded\n"));
1224 methodToken = pMethod->IsNDirect() ?
1225 pMethod->GetMemberDef_NoLogging() :
1226 pResolvedToken->token;
1228 if (TypeFromToken(methodToken) == mdtMethodSpec)
1230 IfFailThrow(pReferencingModule->GetMDImport()->GetMethodSpecProps(methodToken, &methodToken, NULL, NULL));
1233 switch (TypeFromToken(methodToken))
1236 _ASSERTE(pMethod->IsNDirect() || pResolvedToken->pTypeSpec == NULL);
1237 if (!ownerType.HasInstantiation() || ownerType.IsTypicalTypeDefinition())
1239 methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
1244 _ASSERTE(pResolvedToken != NULL);
1245 methodFlags |= ENCODE_METHOD_SIG_MemberRefToken;
1247 if (pResolvedToken->pTypeSpec == NULL)
1249 methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
1252 if (!(methodFlags & ENCODE_METHOD_SIG_InstantiatingStub))
1254 if (SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec).IsPolyType(NULL) == hasNoVars)
1255 methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
1260 _ASSERTE(!"Unexpected method token type!");
1266 if (IsNilToken(methodToken))
1268 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
1271 if (!pMethod->GetModule()->IsInCurrentVersionBubble())
1273 // Using a method defined in another version bubble. We can assume the slot number is stable only for real interface methods.
1274 if (!ownerType.IsInterface() || pMethod->IsStatic() || pMethod->HasMethodInstantiation())
1276 // FUTURE TODO: Version resilience
1277 _ASSERTE(!"References to non-interface methods not yet supported in version resilient images");
1278 IfFailThrow(E_FAIL);
1280 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
1284 Module * pTypeHandleModule = pMethod->GetModule();
1286 if (pTypeHandleModule != pInfoModule)
1288 // During IBC profiling this calls
1289 // code:Module.EncodeModuleHelper
1290 // During ngen this calls
1291 // code:ZapImportTable.EncodeModuleHelper)
1293 DWORD index = (*((EncodeModuleCallback) pfnEncodeModule))(pEncodeModuleContext, pTypeHandleModule);
1295 if (index == ENCODE_MODULE_FAILED)
1300 // If the method handle's module is different that the pInfoModule
1301 // we need to call the TokenDefinitionCallback function
1302 // to record the names for the external module tokens
1304 if ((index != 0) && (pfnDefineToken != NULL))
1307 // We do not want to log the metadata lookups that we perform here
1309 IBCLoggingDisabler disableLogging;
1311 // During IBC profiling this calls
1312 // code:Module::TokenDefinitionHelper()
1313 (*((TokenDefinitionCallback) pfnDefineToken))(pEncodeModuleContext, pTypeHandleModule, index, &methodToken);
1318 _ASSERTE(pInfoModule = pMethod->GetModule());
1321 if (!ownerType.HasInstantiation())
1322 methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
1328 pSigBuilder->AppendData(methodFlags);
1330 if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
1332 if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pTypeSpec != NULL)
1334 _ASSERTE(pResolvedToken->cbTypeSpec > 0);
1336 if (IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != (Module *) pResolvedToken->tokenScope)
1338 pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_MODULE_ZAPSIG);
1339 DWORD index = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, (Module *) pResolvedToken->tokenScope);
1340 pSigBuilder->AppendData(index);
1343 pSigBuilder->AppendBlob((PVOID)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1347 if (!zapSig.GetSignatureForTypeHandle(ownerType, pSigBuilder))
1352 if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
1355 pSigBuilder->AppendData(RidFromToken(methodToken));
1359 // have no token (e.g. it could be an array), encode slot number
1360 pSigBuilder->AppendData(pMethod->GetSlot());
1363 if ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) != 0)
1365 if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pMethodSpec != NULL)
1367 _ASSERTE(pResolvedToken->cbMethodSpec > 1);
1369 if (*(BYTE*)pResolvedToken->pMethodSpec != (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST)
1370 ThrowHR(COR_E_BADIMAGEFORMAT);
1372 pSigBuilder->AppendBlob((PVOID)(((BYTE*)pResolvedToken->pMethodSpec) + 1), pResolvedToken->cbMethodSpec - 1);
1376 Instantiation inst = pMethod->GetMethodInstantiation();
1378 // Number of method instantiation arguments is not encoded in IBC tokens - see comment above
1379 if (externalTokens != ZapSig::IbcTokens)
1380 pSigBuilder->AppendData(inst.GetNumArgs());
1382 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
1384 TypeHandle t = inst[i];
1385 _ASSERTE(!t.IsNull());
1387 if (!zapSig.GetSignatureForTypeHandle(t, pSigBuilder))
1393 #ifdef FEATURE_READYTORUN_COMPILER
1394 if ((methodFlags & ENCODE_METHOD_SIG_Constrained) != 0)
1396 if (fEncodeUsingResolvedTokenSpecStreams && pConstrainedResolvedToken->pTypeSpec != NULL)
1398 _ASSERTE(pConstrainedResolvedToken->cbTypeSpec > 0);
1399 pSigBuilder->AppendBlob((PVOID)pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
1403 if (!zapSig.GetSignatureForTypeHandle(TypeHandle(pConstrainedResolvedToken->hClass), pSigBuilder))
1412 void ZapSig::EncodeField(
1414 Module *pInfoModule,
1415 SigBuilder *pSigBuilder,
1416 LPVOID pEncodeModuleContext,
1417 ENCODEMODULE_CALLBACK pfnEncodeModule,
1418 CORINFO_RESOLVED_TOKEN *pResolvedToken,
1419 BOOL fEncodeUsingResolvedTokenSpecStreams)
1431 mdMethodDef fieldToken = pField->GetMemberDef();
1432 DWORD fieldFlags = ENCODE_FIELD_SIG_OwnerType;
1434 #ifdef FEATURE_READYTORUN_COMPILER
1435 if (IsReadyToRunCompilation())
1437 if (pResolvedToken == NULL)
1439 _ASSERTE(!"CORINFO_RESOLVED_TOKEN required to encode field!");
1443 // Encode the referencing field type
1444 pMT = (MethodTable *)(pResolvedToken->hClass);
1446 Module * pReferencingModule = (Module *)pResolvedToken->tokenScope;
1448 if (!pReferencingModule->IsInCurrentVersionBubble())
1450 // FUTURE: Encoding of new cross-module references for ReadyToRun
1451 // This warning is hit for recursive cross-module inlining. It is commented out to avoid noise.
1452 // GetSvcLogger()->Printf(W("ReadyToRun: Field reference outside of current version bubble cannot be encoded\n"));
1455 _ASSERTE(pReferencingModule == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
1457 fieldToken = pResolvedToken->token;
1459 switch (TypeFromToken(fieldToken))
1462 _ASSERTE(pResolvedToken->pTypeSpec == NULL);
1463 fieldFlags &= ~ENCODE_FIELD_SIG_OwnerType;
1467 fieldFlags |= ENCODE_FIELD_SIG_MemberRefToken;
1469 if (pResolvedToken->pTypeSpec == NULL)
1471 fieldFlags &= ~ENCODE_METHOD_SIG_OwnerType;
1475 if (SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec).IsPolyType(NULL) == hasNoVars)
1476 fieldFlags &= ~ENCODE_METHOD_SIG_OwnerType;
1481 _ASSERTE(!"Unexpected field token type!");
1488 pMT = pField->GetApproxEnclosingMethodTable();
1490 fieldFlags |= ENCODE_FIELD_SIG_IndexInsteadOfToken;
1496 pSigBuilder->AppendData(fieldFlags);
1498 if (fieldFlags & ENCODE_FIELD_SIG_OwnerType)
1500 if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pTypeSpec != NULL)
1502 _ASSERTE(pResolvedToken->cbTypeSpec > 0);
1503 pSigBuilder->AppendBlob((PVOID)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1507 ZapSig zapSig(pInfoModule, pEncodeModuleContext, ZapSig::NormalTokens,
1508 (EncodeModuleCallback)pfnEncodeModule, NULL);
1514 fSuccess = zapSig.GetSignatureForTypeHandle(pMT, pSigBuilder);
1519 if ((fieldFlags & ENCODE_FIELD_SIG_IndexInsteadOfToken) == 0)
1522 pSigBuilder->AppendData(RidFromToken(fieldToken));
1527 // Write field index
1530 DWORD fieldIndex = pMT->GetIndexForFieldDesc(pField);
1531 _ASSERTE(fieldIndex < DWORD(pMT->GetNumStaticFields() + pMT->GetNumIntroducedInstanceFields()));
1533 // have no token (e.g. it could be an array), encode slot number
1534 pSigBuilder->AppendData(fieldIndex);
1538 #endif // DACCESS_COMPILE