public static MethodInfo ResolveEntryPoint(Assembly assembly, Cci.IMethodReference method, EmitContext context) { var containingType = method.GetContainingType(context); Debug.Assert(containingType is Cci.INamespaceTypeReference); var type = ResolveType(assembly, (Cci.INamespaceTypeReference)containingType); return type.GetMethod(method.Name, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); }
private MethodRef MakeMethodRef(Cci.IMethodReference methodRef, Cci.ISpecializedMethodReference specializedRef, bool isConstructor) { Type declaringType = ResolveType(methodRef.GetContainingType(_context)); MethodBase unspecializedDefinition = null; if (specializedRef != null) { // resolvemethod unspecializedDefinition = isConstructor ? ResolveConstructor(specializedRef.UnspecializedVersion) : ResolveMethod(specializedRef.UnspecializedVersion); } var m = new MethodRef(declaringType, methodRef.Name, GetManagedCallingConvention(methodRef.CallingConvention), unspecializedDefinition, GetExtraParameterTypes(methodRef)); Type[] genericParameters; ParameterInfo[] parameters; ParameterInfo returnParameter; if (unspecializedDefinition != null) { if (isConstructor) { returnParameter = new SimpleParameterInfo(unspecializedDefinition, 0, typeof(void)); } else { returnParameter = ((MethodInfo)unspecializedDefinition).ReturnParameter; } // TODO(tomat): change containing method? genericParameters = unspecializedDefinition.GetGenericArguments(); parameters = unspecializedDefinition.GetParameters(); } else { MakeMethodParameters(m, methodRef, out genericParameters, out parameters, out returnParameter); } m.InitializeParameters(genericParameters, parameters, returnParameter); return m; }
private MethodBase ResolveConstructor(Cci.IMethodReference methodRef) { Debug.Assert(!methodRef.IsGeneric); // A method ref to a varargs method is always resolved as an entry in the method // ref table, never in the method def table, *even if the method is locally declared.* // (We could in theory resolve it as a method def if there were no extra arguments, // but in practice we do not.) var methodDef = (Cci.IMethodDefinition)methodRef.AsDefinition(_context); if (methodDef != null && IsLocal(methodRef.GetContainingType(_context)) && !methodRef.AcceptsExtraArguments) { return _constructorBuilders[methodDef]; } MethodBase result; if (_methodRefs.TryGetValue(methodRef, out result)) { return result; } Debug.Assert(methodRef.AsGenericMethodInstanceReference == null); Cci.ISpecializedMethodReference specializedRef = methodRef.AsSpecializedMethodReference; if (specializedRef != null && IsLocal(specializedRef.UnspecializedVersion.GetContainingType(_context))) { // get declaring type (TypeBuilder or TypeBuilderInstantiation since it's defined in the module being built): Type declaringType = ResolveType(methodRef.GetContainingType(_context)); ConstructorBuilder ctorBuilder = _constructorBuilders[(Cci.IMethodDefinition)specializedRef.UnspecializedVersion.AsDefinition(_context)]; result = TypeBuilder.GetConstructor(declaringType, ctorBuilder); } else { result = MakeMethodRef(methodRef, specializedRef, isConstructor: true); } _methodRefs.Add(methodRef, result); return result; }
private MethodInfo ResolveMethod(Cci.IMethodReference methodRef) { var methodDef = (Cci.IMethodDefinition)methodRef.AsDefinition(_context); // A method ref to a varargs method is always resolved as an entry in the method // ref table, never in the method def table, *even if the method is locally declared.* // (We could in theory resolve it as a method def if there were no extra arguments, // but in practice we do not.) if (methodDef != null && IsLocal(methodRef.GetContainingType(_context)) && !methodRef.AcceptsExtraArguments) { return _methodBuilders[methodDef]; } MethodBase methodBase; if (_methodRefs.TryGetValue(methodRef, out methodBase)) { return (MethodInfo)methodBase; } MethodInfo result; Cci.ISpecializedMethodReference specializedRef = methodRef.AsSpecializedMethodReference; Cci.IGenericMethodInstanceReference genericRef = methodRef.AsGenericMethodInstanceReference; if (specializedRef != null && IsLocal(specializedRef.UnspecializedVersion.GetContainingType(_context))) { // get declaring type (TypeBuilder or TypeBuilderInstantiation since it's defined in the module being built): Type type = ResolveType(specializedRef.GetContainingType(_context)); MethodBuilder methodBuilder = _methodBuilders[(Cci.IMethodDefinition)specializedRef.UnspecializedVersion.AsDefinition(_context)]; MethodInfo methodOnTypeBuilder = TypeBuilder.GetMethod(type, methodBuilder); if (genericRef != null) { Type[] typeArgs = genericRef.GetGenericArguments(_context).Select(arg => ResolveType(arg)).ToArray(); result = methodOnTypeBuilder.MakeGenericMethod(typeArgs); } else { result = methodOnTypeBuilder; } } else if (genericRef != null) { MethodInfo genericMethod = ResolveMethod(genericRef.GetGenericMethod(_context)); Type[] typeArgs = genericRef.GetGenericArguments(_context).Select((arg) => ResolveType(arg)).ToArray(); if (genericMethod is MethodRef) { result = new MethodSpec(genericMethod, typeArgs); } else { result = genericMethod.MakeGenericMethod(typeArgs); } } else { result = MakeMethodRef(methodRef, specializedRef, isConstructor: false); } _methodRefs.Add(methodRef, result); return result; }
private FieldInfo ResolveField(Cci.IFieldReference fieldRef) { var fieldDef = fieldRef.GetResolvedField(_context); if (fieldDef != null && IsLocal(fieldRef.GetContainingType(_context))) { return _fieldBuilders[fieldDef]; } FieldInfo result; if (_fieldRefs.TryGetValue(fieldRef, out result)) { return result; } Type declaringType = ResolveType(fieldRef.GetContainingType(_context)); Cci.ISpecializedFieldReference specializedRef = fieldRef.AsSpecializedFieldReference; if (specializedRef != null) { if (IsLocal(specializedRef.UnspecializedVersion.GetContainingType(_context))) { // declaring type is TypeBuilder or TypeBuilderInstantiation since it's defined in the module being built: FieldBuilder fieldBuilder = _fieldBuilders[(Cci.IFieldDefinition)specializedRef.UnspecializedVersion.AsDefinition(_context)]; result = TypeBuilder.GetField(declaringType, fieldBuilder); } else { FieldInfo unspecializedDefinition = ResolveField(specializedRef.UnspecializedVersion); result = new FieldRef(declaringType, fieldRef.Name, unspecializedDefinition.FieldType); } } else { GenericContext genericContext; if (declaringType.IsGenericTypeDefinition) { genericContext = new GenericContext(declaringType.GetGenericArguments(), Type.EmptyTypes); } else { genericContext = default(GenericContext); } // TODO: modifiers? Type fieldType = ResolveType(fieldRef.GetType(_context), genericContext); result = new FieldRef(declaringType, fieldRef.Name, fieldType); } _fieldRefs.Add(fieldRef, result); return result; }
/// <summary> /// The main worker. Emits all types. /// </summary> /// <param name="entryPoint">An entry point to resolve and return. This could be an arbitrary method, not just PE entry point.</param> /// <param name="cancellationToken">Token used to cancel the operation.</param> /// <returns>The entry point or null if there is none.</returns> /// <exception cref="NotSupportedException">Reflection.Emit doesn't support the feature being emitted.</exception> private MethodInfo EmitWorker(Cci.IMethodReference entryPoint, CancellationToken cancellationToken) { // types and nesting: foreach (var typeDef in _module.GetTopLevelTypes(_context)) { // global type (TODO: detect properly) if (typeDef.Name == "<Module>") { continue; } DefineTypeRecursive(typeDef, containingTypeBuilder: null); } cancellationToken.ThrowIfCancellationRequested(); // Base types: we need to define them before defining fields. // Field definition creates a signature, which might ask whether a type builder is a value type. // The implementation of Type.IsValueType calls IsSubclassOf(System.ValueType). foreach (var definedType in _typeBuilders) { var typeDef = definedType.Key; var typeBuilder = definedType.Value; var baseClass = typeDef.GetBaseClass(_context); if (baseClass != null) { // base type must be loaded before the type: typeBuilder.SetParent(ResolveType(baseClass, dependentType: typeBuilder, valueTypeDependency: false)); } } foreach (var genericParameter in _genericParameterBuilders) { var gpBuilder = genericParameter.Value; var typeParameter = (Cci.IGenericTypeParameter)genericParameter.Key; if (typeParameter.AsGenericTypeParameter != null) { DefineGenericParameterConstraints(gpBuilder, typeParameter); } } // inheritance, generic type parameters, fields, methods, constructors (need types, base types): foreach (var definedType in _typeBuilders) { DefineFieldsAndMethods(definedType.Value, definedType.Key); } // TODO: define methods and fields of global type // parameter names and custom attributes (needs all members and types): foreach (var method in _methodBuilders) { var methodDef = method.Key; var methodBuilder = method.Value; DefineParameters(methodBuilder, null, methodDef); EmitCustomAttributes(methodBuilder, methodDef.GetAttributes(_context)); } foreach (var ctor in _constructorBuilders) { var ctorDef = ctor.Key; var ctorBuilder = ctor.Value; DefineParameters(null, ctorBuilder, ctorDef); EmitCustomAttributes(ctorBuilder, ctorDef.GetAttributes(_context)); } foreach (var field in _fieldBuilders) { var fieldDef = field.Key; var fieldBuilder = field.Value; // Constant: Assign field literals after all fields have been defined. // TypeBuilder that represents an enum determines its underlying type based upon the first (and only) instance field type (__value). // So we need to define all the fields first and then assign their literal values. var constant = fieldDef.GetCompileTimeValue(_context); if (constant != null) { // TODO(tomat): This fails for enum fields if the enum is a nested type in a generic type (TypeBuilderInstantiation throws in IsSubclassOf) fieldBuilder.SetConstant(constant.Value); } EmitCustomAttributes(fieldBuilder, fieldDef.GetAttributes(_context)); } // define generic parameter custom attributes (needs all types, methods and constructors defined): foreach (var genericParameter in _genericParameterBuilders) { EmitCustomAttributes(genericParameter.Value, ((Cci.IGenericParameter)genericParameter.Key).GetAttributes(_context)); } cancellationToken.ThrowIfCancellationRequested(); // bodies (IL may need a method token of a generic method, which bakes its generic parameters -> we need to emit generic parameters first) foreach (var method in _methodBuilders) { if (Cci.Extensions.HasBody(method.Key)) { EmitMethodBody(method.Value, null, method.Key.GetBody(_context)); } } foreach (var ctor in _constructorBuilders) { if (Cci.Extensions.HasBody(ctor.Key)) { EmitMethodBody(null, ctor.Value, ctor.Key.GetBody(_context)); } } // base type, implemented interfaces, generic parameters // member relationships, properties, events, custom attributes (needs attribute constructors, all members): foreach (var definedType in _typeBuilders) { FinishType(definedType.Value, definedType.Key); } // module and assembly attributes: EmitCustomAttributes(_builder, _module.ModuleAttributes); EmitCustomAttributes((AssemblyBuilder)_builder.Assembly, _module.AssemblyAttributes); cancellationToken.ThrowIfCancellationRequested(); // order types to satisfy dependencies: IEnumerable<TypeBuilder> orderedTypeBuilders = OrderTypeBuilders(); if (orderedTypeBuilders == null) { throw new NotSupportedException("Ref.Emit limitation: cycle in type dependencies"); } // create types and entry point: MethodInfo resolvedEntryPoint = null; Type entryPointType = null; if (entryPoint != null) { entryPointType = ResolveType(entryPoint.GetContainingType(_context)); } foreach (var typeBuilder in orderedTypeBuilders) { Type type = null; // TODO (tomat): we should test for features not allowed in a collectible assembly upfront // rather than waiting for an exception to happen. try { type = typeBuilder.CreateType(); // TODO (tomat): this is very strange, the TypeLoadException is swallowed when VS debugger is attached // and the execution continues with type == null. See bug DevDiv2\DevDiv bug 391550. if (type == null) { throw new NotSupportedException("Ref.Emit limitation"); } } catch (TypeLoadException e) { throw new NotSupportedException("Ref.Emit limitation: " + e.Message); } if (typeBuilder == entryPointType) { resolvedEntryPoint = (MethodInfo)ResolveRuntimeMethodOrConstructor(type, entryPoint, isConstructor: false); } cancellationToken.ThrowIfCancellationRequested(); } // PE entry point: if (_module.EntryPoint != null) { Debug.Assert(_module.EntryPoint == entryPoint); ((AssemblyBuilder)_builder.Assembly).SetEntryPoint(resolvedEntryPoint); } Debug.Assert(entryPoint == null || resolvedEntryPoint != null); return resolvedEntryPoint; }