public override MethodIL EmitIL()
            {
                if (_owningType.BoxedValue == null)
                {
                    // If this is the fake unboxing thunk for ByRef-like types, just make a method that throws.
                    return(new ILStubMethodIL(this,
                                              new byte[] { (byte)ILOpcode.ldnull, (byte)ILOpcode.throw_ },
                                              Array.Empty <LocalVariableDefinition>(),
                                              Array.Empty <object>()));
                }

                // Generate the unboxing stub. This loosely corresponds to following C#:
                // return BoxedValue.InstanceMethod([rest of parameters])

                ILEmitter    emit       = new ILEmitter();
                ILCodeStream codeStream = emit.NewCodeStream();

                FieldDesc boxedValueField = _owningType.BoxedValue.InstantiateAsOpen();

                // unbox to get a pointer to the value type
                codeStream.EmitLdArg(0);
                codeStream.Emit(ILOpcode.ldflda, emit.NewToken(boxedValueField));

                // Load rest of the arguments
                for (int i = 0; i < _targetMethod.Signature.Length; i++)
                {
                    codeStream.EmitLdArg(i + 1);
                }

                TypeDesc   owner = _targetMethod.OwningType;
                MethodDesc methodToInstantiate = _targetMethod;

                if (owner.HasInstantiation)
                {
                    MetadataType instantiatedOwner = (MetadataType)owner.InstantiateAsOpen();
                    methodToInstantiate = _targetMethod.Context.GetMethodForInstantiatedType(_targetMethod, (InstantiatedType)instantiatedOwner);
                }
                if (methodToInstantiate.HasInstantiation)
                {
                    TypeSystemContext context = methodToInstantiate.Context;

                    var inst = new TypeDesc[methodToInstantiate.Instantiation.Length];
                    for (int i = 0; i < inst.Length; i++)
                    {
                        inst[i] = context.GetSignatureVariable(i, true);
                    }

                    methodToInstantiate = context.GetInstantiatedMethod(methodToInstantiate, new Instantiation(inst));
                }

                codeStream.Emit(ILOpcode.call, emit.NewToken(methodToInstantiate));
                codeStream.Emit(ILOpcode.ret);

                return(emit.Link(this));
            }
        public static MethodDesc ToMethodDesc(this RuntimeMethodHandle rmh, TypeSystemContext typeSystemContext)
        {
            RuntimeTypeHandle      declaringTypeHandle;
            MethodNameAndSignature nameAndSignature;

            RuntimeTypeHandle[] genericMethodArgs;

            if (!TypeLoaderEnvironment.Instance.TryGetRuntimeMethodHandleComponents(rmh, out declaringTypeHandle, out nameAndSignature, out genericMethodArgs))
            {
                return(null);
            }

            QMethodDefinition methodHandle;

            if (!TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(declaringTypeHandle, nameAndSignature, out methodHandle))
            {
                return(null);
            }

            TypeDesc declaringType = typeSystemContext.ResolveRuntimeTypeHandle(declaringTypeHandle);

            TypeDesc   declaringTypeDefinition = declaringType.GetTypeDefinition();
            MethodDesc typicalMethod           = null;

            if (methodHandle.IsNativeFormatMetadataBased)
            {
                var nativeFormatType = (NativeFormatType)declaringTypeDefinition;
                typicalMethod = nativeFormatType.MetadataUnit.GetMethod(methodHandle.NativeFormatHandle, nativeFormatType);
            }
            else if (methodHandle.IsEcmaFormatMetadataBased)
            {
                var ecmaFormatType = (EcmaType)declaringTypeDefinition;
                typicalMethod = ecmaFormatType.EcmaModule.GetMethod(methodHandle.EcmaFormatHandle);
            }
            Debug.Assert(typicalMethod != null);

            MethodDesc methodOnInstantiatedType = typicalMethod;

            if (declaringType != declaringTypeDefinition)
            {
                methodOnInstantiatedType = typeSystemContext.GetMethodForInstantiatedType(typicalMethod, (InstantiatedType)declaringType);
            }

            MethodDesc instantiatedMethod = methodOnInstantiatedType;

            if (genericMethodArgs != null)
            {
                Debug.Assert(genericMethodArgs.Length > 0);
                Instantiation genericMethodInstantiation = typeSystemContext.ResolveRuntimeTypeHandles(genericMethodArgs);
                typeSystemContext.GetInstantiatedMethod(methodOnInstantiatedType, genericMethodInstantiation);
            }

            return(instantiatedMethod);
        }
Esempio n. 3
0
        /// <summary>
        /// Retrieves method whose runtime handle is suitable for use with GVMLookupForSlot.
        /// </summary>
        public MethodDesc GetTargetOfGenericVirtualMethodCall(MethodDesc calledMethod)
        {
            // Should be a generic virtual method
            Debug.Assert(calledMethod.HasInstantiation && calledMethod.IsVirtual);

            // Needs to be either a concrete method, or a runtime determined form.
            Debug.Assert(!calledMethod.IsCanonicalMethod(CanonicalFormKind.Specific));

            MethodDesc targetMethod           = calledMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
            MethodDesc targetMethodDefinition = targetMethod.GetMethodDefinition();

            MethodDesc slotNormalizedMethodDefinition = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(targetMethodDefinition);

            // If the method defines the slot, we can use that.
            if (slotNormalizedMethodDefinition == targetMethodDefinition)
            {
                return(calledMethod);
            }

            // Normalize to the slot defining method
            MethodDesc slotNormalizedMethod = TypeSystemContext.GetInstantiatedMethod(
                slotNormalizedMethodDefinition,
                targetMethod.Instantiation);

            // Since the slot normalization logic modified what method we're looking at, we need to compute the new target of lookup.
            //
            // If we could use virtual method resolution logic with runtime determined methods, we wouldn't need what we're going
            // to do below.
            MethodDesc runtimeDeterminedSlotNormalizedMethod;

            if (!slotNormalizedMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
            {
                // If the owning type is not generic, we can use it as-is, potentially only replacing the runtime-determined
                // method instantiation part.
                runtimeDeterminedSlotNormalizedMethod = slotNormalizedMethod.GetMethodDefinition();
            }
            else
            {
                // If we need a runtime lookup but a normalization to the slot defining method happened above, we need to compute
                // the runtime lookup in terms of the base type that introduced the slot.
                //
                // To do that, we walk the base hierarchy of the runtime determined thing, looking for a type definition that matches
                // the slot-normalized virtual method. We then find the method on that type.
                TypeDesc runtimeDeterminedOwningType = calledMethod.OwningType;

                Debug.Assert(!runtimeDeterminedOwningType.IsInterface);

                while (!slotNormalizedMethod.OwningType.HasSameTypeDefinition(runtimeDeterminedOwningType))
                {
                    TypeDesc runtimeDeterminedBaseTypeDefinition = runtimeDeterminedOwningType.GetTypeDefinition().BaseType;
                    if (runtimeDeterminedBaseTypeDefinition.HasInstantiation)
                    {
                        runtimeDeterminedOwningType = runtimeDeterminedBaseTypeDefinition.InstantiateSignature(runtimeDeterminedOwningType.Instantiation, default);
                    }
                    else
                    {
                        runtimeDeterminedOwningType = runtimeDeterminedBaseTypeDefinition;
                    }
                }

                // Now get the method on the newly found type
                Debug.Assert(runtimeDeterminedOwningType.HasInstantiation);
                runtimeDeterminedSlotNormalizedMethod = TypeSystemContext.GetMethodForInstantiatedType(
                    slotNormalizedMethod.GetTypicalMethodDefinition(),
                    (InstantiatedType)runtimeDeterminedOwningType);
            }

            return(TypeSystemContext.GetInstantiatedMethod(runtimeDeterminedSlotNormalizedMethod, calledMethod.Instantiation));
        }
Esempio n. 4
0
        public MethodDesc ResolveMethodID(long handle, bool throwIfNotFound = true)
        {
            lock (_lock)
            {
                MethodDescInfo minfo;
                if (_methods.TryGetValue(handle, out minfo))
                {
                    if (minfo.Method != null)
                        return minfo.Method;

                    TypeDesc owningType = ResolveTypeHandle(minfo.MethodDetailsTraceData.TypeID, throwIfNotFound);
                    if (owningType == null)
                        return null;

                    MetadataType owningMDType = owningType as MetadataType;
                    if (owningMDType == null)
                        throw new Exception("Method not parented by MetadataType");

                    if ((minfo.MethodDetailsTraceData.MethodToken & 0xFF000000) != 0x06000000)
                    {
                        throw new Exception($"Invalid methoddef {minfo.MethodDetailsTraceData.MethodToken:4x}");
                    }

                    MethodDefinitionHandle methoddef = MetadataTokens.MethodDefinitionHandle(minfo.MethodDetailsTraceData.MethodToken & 0xFFFFFF);

                    MethodDesc uninstantiatedMethod = null;
                    foreach (MethodDesc m in owningMDType.GetMethods())
                    {
                        EcmaMethod ecmaMeth = m.GetTypicalMethodDefinition() as EcmaMethod;
                        if (ecmaMeth == null)
                        {
                            continue;
                        }

                        if (ecmaMeth.Handle == methoddef)
                        {
                            uninstantiatedMethod = m;
                            break;
                        }
                    }

                    if (uninstantiatedMethod == null)
                    {
                        if (throwIfNotFound)
                        {
                            EcmaType ecmaType = owningMDType.GetTypeDefinition() as EcmaType;
                            
                            throw new Exception($"Unknown MethodID value finding MethodDef {minfo.MethodDetailsTraceData.MethodToken:x} on type {owningMDType} from module {ecmaType.Module.Assembly.GetName().Name}");
                        }
                        return null;
                    }

                    // Instantiate the type if requested
                    if (minfo.MethodDetailsTraceData.TypeParameters.Length != 0)
                    {
                        if (uninstantiatedMethod.Instantiation.Length != minfo.MethodDetailsTraceData.TypeParameters.Length)
                        {
                            throw new Exception($"Invalid TypeParameterCount {minfo.MethodDetailsTraceData.TypeParameters.Length} expected {uninstantiatedMethod.Instantiation.Length} as needed by '{uninstantiatedMethod}'");
                        }

                        TypeDesc[] instantiation = new TypeDesc[minfo.MethodDetailsTraceData.TypeParameters.Length];
                        for (int i = 0; i < instantiation.Length; i++)
                        {
                            instantiation[i] = ResolveTypeHandle((long)minfo.MethodDetailsTraceData.TypeParameters[i], throwIfNotFound);
                            if (instantiation[i] == null)
                                return null;
                        }

                        minfo.Method = _context.GetInstantiatedMethod(uninstantiatedMethod, new Instantiation(instantiation));

                        if (minfo.Method == null)
                        {
                            if (throwIfNotFound)
                            {
                                StringBuilder s = new StringBuilder();
                                foreach (TypeDesc type in instantiation)
                                {
                                    if (s.Length != 0)
                                        s.Append(',');
                                    s.Append(type);
                                }
                                throw new Exception("Unable to instantiate {uninstantiatedMethod} over <{s}>");
                            }
                            return null;
                        }
                    }
                    else
                    {
                        minfo.Method = uninstantiatedMethod;
                    }

                    if (minfo.Method == null)
                    {
                        if (throwIfNotFound)
                            throw new Exception("Unknown MethodID value");
                        return null;
                    }

                    return minfo.Method;
                }
                else
                {
                    if (throwIfNotFound)
                        throw new Exception("Unknown MethodID value");
                    return null;
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Gets a stub that can be used to reflection-invoke a method with a given signature.
        /// </summary>
        public MethodDesc GetReflectionInvokeStub(MethodDesc method)
        {
            // Methods we see here shouldn't be canonicalized, or we'll end up creating bastardized instantiations
            // (e.g. we instantiate over System.Object below.)
            Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Any));

            TypeSystemContext context = method.Context;
            var sig = method.Signature;

            ParameterMetadata[] paramMetadata = null;

            // Get a generic method that can be used to invoke method with this shape.
            MethodDesc thunk;
            var        lookupSig = new DynamicInvokeMethodSignature(sig);

            if (!_dynamicInvokeThunks.TryGetValue(lookupSig, out thunk))
            {
                thunk = new DynamicInvokeMethodThunk(_nodeFactory.CompilationModuleGroup.GeneratedAssembly.GetGlobalModuleType(), lookupSig);
                _dynamicInvokeThunks.Add(lookupSig, thunk);
            }

            // If the method has no parameters and returns void, we don't need to specialize
            if (sig.ReturnType.IsVoid && sig.Length == 0)
            {
                Debug.Assert(!thunk.HasInstantiation);
                return(thunk);
            }

            //
            // Instantiate the generic thunk over the parameters and the return type of the target method
            //

            TypeDesc[] instantiation = new TypeDesc[sig.ReturnType.IsVoid ? sig.Length : sig.Length + 1];
            Debug.Assert(thunk.Instantiation.Length == instantiation.Length);
            for (int i = 0; i < sig.Length; i++)
            {
                TypeDesc parameterType = sig[i];
                if (parameterType.IsByRef)
                {
                    // strip ByRefType off the parameter (the method already has ByRef in the signature)
                    parameterType = ((ByRefType)parameterType).ParameterType;
                }

                if (parameterType.IsPointer || parameterType.IsFunctionPointer)
                {
                    // For pointer typed parameters, instantiate the method over IntPtr
                    parameterType = context.GetWellKnownType(WellKnownType.IntPtr);
                }
                else if (parameterType.IsEnum)
                {
                    // If the invoke method takes an enum as an input parameter and there is no default value for
                    // that paramter, we don't need to specialize on the exact enum type (we only need to specialize
                    // on the underlying integral type of the enum.)
                    if (paramMetadata == null)
                    {
                        paramMetadata = method.GetParameterMetadata();
                    }

                    bool hasDefaultValue = false;
                    foreach (var p in paramMetadata)
                    {
                        // Parameter metadata indexes are 1-based (0 is reserved for return "parameter")
                        if (p.Index == (i + 1) && p.HasDefault)
                        {
                            hasDefaultValue = true;
                            break;
                        }
                    }

                    if (!hasDefaultValue)
                    {
                        parameterType = parameterType.UnderlyingType;
                    }
                }

                instantiation[i] = parameterType;
            }

            if (!sig.ReturnType.IsVoid)
            {
                TypeDesc returnType = sig.ReturnType;
                Debug.Assert(!returnType.IsByRef);

                // If the invoke method return an object reference, we don't need to specialize on the
                // exact type of the object reference, as the behavior is not different.
                if ((returnType.IsDefType && !returnType.IsValueType) || returnType.IsArray)
                {
                    returnType = context.GetWellKnownType(WellKnownType.Object);
                }

                instantiation[sig.Length] = returnType;
            }

            return(context.GetInstantiatedMethod(thunk, new Instantiation(instantiation)));
        }
Esempio n. 6
0
        /// <summary>
        /// Gets a stub that can be used to reflection-invoke a method with a given signature.
        /// </summary>
        public MethodDesc GetReflectionInvokeStub(MethodDesc method)
        {
            // Methods we see here shouldn't be canonicalized, or we'll end up creating bastardized instantiations
            // (e.g. we instantiate over System.Object below.)
            Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Any));

            TypeSystemContext context = method.Context;
            var sig = method.Signature;

            // Get a generic method that can be used to invoke method with this shape.
            MethodDesc thunk;
            var        lookupSig = new DynamicInvokeMethodSignature(sig);

            if (!_dynamicInvokeThunks.TryGetValue(lookupSig, out thunk))
            {
                // TODO: figure out a better owning type (for multifile)
                thunk = new DynamicInvokeMethodThunk(context.SystemModule.GetGlobalModuleType(), lookupSig);
                _dynamicInvokeThunks.Add(lookupSig, thunk);
            }

            // If the method has no parameters and returns void, we don't need to specialize
            if (sig.ReturnType.IsVoid && sig.Length == 0)
            {
                Debug.Assert(!thunk.HasInstantiation);
                return(thunk);
            }

            //
            // Instantiate the generic thunk over the parameters and the return type of the target method
            //

            TypeDesc[] instantiation = new TypeDesc[sig.ReturnType.IsVoid ? sig.Length : sig.Length + 1];
            Debug.Assert(thunk.Instantiation.Length == instantiation.Length);
            for (int i = 0; i < sig.Length; i++)
            {
                TypeDesc parameterType = sig[i];
                if (parameterType.IsByRef)
                {
                    // strip ByRefType off the parameter (the method already has ByRef in the signature)
                    parameterType = ((ByRefType)parameterType).ParameterType;
                }

                if (parameterType.IsPointer || parameterType.IsFunctionPointer)
                {
                    // For pointer typed parameters, instantiate the method over IntPtr
                    parameterType = context.GetWellKnownType(WellKnownType.IntPtr);
                }
                else if (parameterType.IsDefType)
                {
                    // TODO: optimize enum types with no default value
                    // DefType* paramDefType = parameterType->as<DefType> ();
                    // // If the invoke method takes an enum as an input paramter and there is no default value for
                    // // that paramter, we don't need to specialize on the exact enum type (we only need to specialize
                    // // on the underlying integral type of the enum.)
                    // if (paramDefType && (!IsPdHasDefault(methodToInvoke->Parameters()[index].Attributes())) && paramDefType->IsEnum())
                    // {
                    //     CorElementType underlyingElemType = paramDefType->InternalElementType();
                    //     parameterType = paramDefType->GetLoaderContext()->GetElementType(underlyingElemType);
                    // }
                }

                instantiation[i] = parameterType;
            }

            if (!sig.ReturnType.IsVoid)
            {
                TypeDesc returnType = sig.ReturnType;
                Debug.Assert(!returnType.IsByRef);

                // If the invoke method return an object reference, we don't need to specialize on the
                // exact type of the object reference, as the behavior is not different.
                if ((returnType.IsDefType && !returnType.IsValueType) || returnType.IsArray)
                {
                    returnType = context.GetWellKnownType(WellKnownType.Object);
                }

                instantiation[sig.Length] = returnType;
            }

            return(context.GetInstantiatedMethod(thunk, new Instantiation(instantiation)));
        }