[corlib] ModuleBuilder pseudo-token lookup needs to use references insteads of logica...
[mono.git] / mcs / class / corlib / System.Reflection.Emit / ModuleBuilder.cs
index d6c39114f16ef3da670dd957008a1c592b08af79..2e985180ef549a1f9daac1d89129ded9b73a354b 100644 (file)
@@ -62,6 +62,7 @@ namespace System.Reflection.Emit {
                private FieldBuilder[] global_fields;
                bool is_main;
                private MonoResource[] resources;
+               private IntPtr unparented_classes;
                #endregion
 #pragma warning restore 169, 414
                
@@ -76,6 +77,8 @@ namespace System.Reflection.Emit {
                Hashtable resource_writers;
                ISymbolWriter symbolWriter;
 
+               static bool has_warned_about_symbolWriter;
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private static extern void basic_init (ModuleBuilder ab);
 
@@ -106,11 +109,22 @@ namespace System.Reflection.Emit {
 
                        if (emitSymbolInfo) {
                                Assembly asm = Assembly.LoadWithPartialName ("Mono.CompilerServices.SymbolWriter");
-                               if (asm == null)
-                                       throw new TypeLoadException ("The assembly for default symbol writer cannot be loaded");
 
-                               Type t = asm.GetType ("Mono.CompilerServices.SymbolWriter.SymbolWriterImpl", true);
-                               symbolWriter = (ISymbolWriter) Activator.CreateInstance (t, new object[] { this });
+                               Type t = null;
+                               if (asm != null)
+                                       t = asm.GetType ("Mono.CompilerServices.SymbolWriter.SymbolWriterImpl");
+
+                               if (t == null) {
+                                       WarnAboutSymbolWriter ("Failed to load the default Mono.CompilerServices.SymbolWriter assembly");
+                               } else {
+                                       try {
+                                               symbolWriter = (ISymbolWriter) Activator.CreateInstance (t, new object[] { this });
+                                       } catch (System.MissingMethodException) {
+                                               WarnAboutSymbolWriter ("The default Mono.CompilerServices.SymbolWriter is not available on this platform");                                     
+                                               return;
+                                       }
+                               }
+                               
                                string fileName = fqname;
                                if (assemblyb.AssemblyDir != null)
                                        fileName = Path.Combine (assemblyb.AssemblyDir, fileName);
@@ -118,6 +132,15 @@ namespace System.Reflection.Emit {
                        }
                }
 
+               static void WarnAboutSymbolWriter (string message) 
+               {
+                       if (has_warned_about_symbolWriter)
+                               return;
+
+                       has_warned_about_symbolWriter = true;
+                       Console.Error.WriteLine ("WARNING: {0}", message);
+               }
+
                public override string FullyQualifiedName {get { return fqname;}}
 
                public bool IsTransient () {
@@ -348,9 +371,6 @@ namespace System.Reflection.Emit {
                        return null;
                }
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private static extern Type create_modified_type (TypeBuilder tb, string modifiers);
-
                private TypeBuilder GetMaybeNested (TypeBuilder t, IEnumerable<TypeName> nested) {
                        TypeBuilder result = t;
 
@@ -392,8 +412,27 @@ namespace System.Reflection.Emit {
                        if ((result == null) && throwOnError)
                                throw new TypeLoadException (className);
                        if (result != null && (ts.HasModifiers || ts.IsByRef)) {
-                               string modifiers = ts.ModifierString ();
-                               Type mt = create_modified_type (result, modifiers);
+                               Type mt = result;
+                               if (result is TypeBuilder) {
+                                       var tb = result as TypeBuilder;
+                                       if (tb.is_created)
+                                               mt = tb.CreateType ();
+                               }
+                               foreach (var mod in ts.Modifiers) {
+                                       if (mod is PointerSpec)
+                                               mt = mt.MakePointerType ();
+                                       else if (mod is ArraySpec) {
+                                               var spec = mod as ArraySpec;
+                                               if (spec.IsBound)
+                                                       return null;
+                                               if (spec.Rank == 1)
+                                                       mt = mt.MakeArrayType ();
+                                               else
+                                                       mt = mt.MakeArrayType (spec.Rank);
+                                       }
+                               }
+                               if (ts.IsByRef)
+                                       mt = mt.MakeByRefType ();
                                result = mt as TypeBuilder;
                                if (result == null)
                                        return mt;
@@ -665,15 +704,91 @@ namespace System.Reflection.Emit {
                        return result;
                }
 
+               static int typeref_tokengen =  0x01ffffff;
+               static int typedef_tokengen =  0x02ffffff;
+               static int typespec_tokengen =  0x1bffffff;
+               static int memberref_tokengen =  0x0affffff;
+               static int methoddef_tokengen =  0x06ffffff;
+               Dictionary<MemberInfo, int> inst_tokens, inst_tokens_open;
+
+               //
+               // Assign a pseudo token to the various TypeBuilderInst objects, so the runtime
+               // doesn't have to deal with them.
+               // For Save assemblies, the tokens will be fixed up later during Save ().
+               // For Run assemblies, the tokens will not be fixed up, so the runtime will
+               // still encounter these objects, it will resolve them by calling their
+               // RuntimeResolve () methods.
+               //
+               int GetPseudoToken (MemberInfo member, bool create_open_instance)
+               {
+                       int token;
+                       var dict = create_open_instance ? inst_tokens_open : inst_tokens;
+                       if (dict == null) {
+                               dict = new Dictionary<MemberInfo, int> (ReferenceEqualityComparer<MemberInfo>.Instance);
+                               if (create_open_instance)
+                                       inst_tokens_open = dict;
+                               else
+                                       inst_tokens = dict;
+                       } else if (dict.TryGetValue (member, out token)) {
+                               return token;
+                       }
+
+                       // Count backwards to avoid collisions with the tokens
+                       // allocated by the runtime
+                       if (member is TypeBuilderInstantiation || member is SymbolType)
+                               token = typespec_tokengen --;
+                       else if (member is FieldOnTypeBuilderInst)
+                               token = memberref_tokengen --;
+                       else if (member is ConstructorOnTypeBuilderInst)
+                               token = memberref_tokengen --;
+                       else if (member is MethodOnTypeBuilderInst)
+                               token = memberref_tokengen --;
+                       else if (member is FieldBuilder)
+                               token = memberref_tokengen --;
+                       else if (member is TypeBuilder) {
+                               if (create_open_instance && (member as TypeBuilder).ContainsGenericParameters)
+                                       token = typespec_tokengen --;
+                               else if (member.Module == this)
+                                       token = typedef_tokengen --;
+                               else
+                                       token = typeref_tokengen --;
+                       } else if (member is ConstructorBuilder) {
+                               if (member.Module == this && !(member as ConstructorBuilder).TypeBuilder.ContainsGenericParameters)
+                                       token = methoddef_tokengen --;
+                               else
+                                       token = memberref_tokengen --;
+                       } else if (member is MethodBuilder) {
+                               var mb = member as MethodBuilder;
+                               if (member.Module == this && !mb.TypeBuilder.ContainsGenericParameters && !mb.IsGenericMethodDefinition)
+                                       token = methoddef_tokengen --;
+                               else
+                                       token = memberref_tokengen --;
+                       } else if (member is GenericTypeParameterBuilder) {
+                               token = typespec_tokengen --;
+                       } else
+                               throw new NotImplementedException ();
+
+                       dict [member] = token;
+                       RegisterToken (member, token);
+                       return token;
+               }
+
                internal int GetToken (MemberInfo member) {
+                       if (member is ConstructorBuilder || member is MethodBuilder)
+                               return GetPseudoToken (member, false);
                        return getToken (this, member, true);
                }
 
                internal int GetToken (MemberInfo member, bool create_open_instance) {
+                       if (member is TypeBuilderInstantiation || member is FieldOnTypeBuilderInst || member is ConstructorOnTypeBuilderInst || member is MethodOnTypeBuilderInst || member is SymbolType || member is FieldBuilder || member is TypeBuilder || member is ConstructorBuilder || member is MethodBuilder || member is GenericTypeParameterBuilder)
+                               return GetPseudoToken (member, create_open_instance);
                        return getToken (this, member, create_open_instance);
                }
 
                internal int GetToken (MethodBase method, IEnumerable<Type> opt_param_types) {
+                       if (method is ConstructorBuilder || method is MethodBuilder)
+                               return GetPseudoToken (method, false);
+
                        if (opt_param_types == null)
                                return getToken (this, method, true);
 
@@ -682,6 +797,8 @@ namespace System.Reflection.Emit {
                }
                
                internal int GetToken (MethodBase method, Type[] opt_param_types) {
+                       if (method is ConstructorBuilder || method is MethodBuilder)
+                               return GetPseudoToken (method, false);
                        return getMethodToken (this, method, opt_param_types);
                }
 
@@ -708,12 +825,91 @@ namespace System.Reflection.Emit {
                        return token_gen;
                }
 
+               // Called from the runtime to return the corresponding finished reflection object
+               internal static object RuntimeResolve (object obj) {
+                       if (obj is MethodBuilder)
+                               return (obj as MethodBuilder).RuntimeResolve ();
+                       if (obj is ConstructorBuilder)
+                               return (obj as ConstructorBuilder).RuntimeResolve ();
+                       if (obj is FieldBuilder)
+                               return (obj as FieldBuilder).RuntimeResolve ();
+                       if (obj is GenericTypeParameterBuilder)
+                               return (obj as GenericTypeParameterBuilder).RuntimeResolve ();
+                       if (obj is FieldOnTypeBuilderInst)
+                               return (obj as FieldOnTypeBuilderInst).RuntimeResolve ();
+                       if (obj is MethodOnTypeBuilderInst)
+                               return (obj as MethodOnTypeBuilderInst).RuntimeResolve ();
+                       if (obj is ConstructorOnTypeBuilderInst)
+                               return (obj as ConstructorOnTypeBuilderInst).RuntimeResolve ();
+                       if (obj is Type)
+                               return (obj as Type).RuntimeResolve ();
+                       throw new NotImplementedException (obj.GetType ().FullName);
+               }
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private static extern void build_metadata (ModuleBuilder mb);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern void WriteToFile (IntPtr handle);
 
+               void FixupTokens (Dictionary<int, int> token_map, Dictionary<int, MemberInfo> member_map, Dictionary<MemberInfo, int> inst_tokens,
+                                                 bool open) {
+                       foreach (var v in inst_tokens) {
+                               var member = v.Key;
+                               var old_token = v.Value;
+                               MemberInfo finished = null;
+
+                               // Construct the concrete reflection object corresponding to the
+                               // TypeBuilderInst object, and request a token for it instead.
+                               if (member is TypeBuilderInstantiation || member is SymbolType) {
+                                       finished = (member as Type).RuntimeResolve ();
+                               } else if (member is FieldOnTypeBuilderInst) {
+                                       finished = (member as FieldOnTypeBuilderInst).RuntimeResolve ();
+                               } else if (member is ConstructorOnTypeBuilderInst) {
+                                       finished = (member as ConstructorOnTypeBuilderInst).RuntimeResolve ();
+                               } else if (member is MethodOnTypeBuilderInst) {
+                                       finished = (member as MethodOnTypeBuilderInst).RuntimeResolve ();
+                               } else if (member is FieldBuilder) {
+                                       finished = (member as FieldBuilder).RuntimeResolve ();
+                               } else if (member is TypeBuilder) {
+                                       finished = (member as TypeBuilder).RuntimeResolve ();
+                               } else if (member is ConstructorBuilder) {
+                                       finished = (member as ConstructorBuilder).RuntimeResolve ();
+                               } else if (member is MethodBuilder) {
+                                       finished = (member as MethodBuilder).RuntimeResolve ();
+                               } else if (member is GenericTypeParameterBuilder) {
+                                       finished = (member as GenericTypeParameterBuilder).RuntimeResolve ();
+                               } else {
+                                       throw new NotImplementedException ();
+                               }
+
+                               int new_token = GetToken (finished, open);
+                               token_map [old_token] = new_token;
+                               member_map [old_token] = finished;
+                               // Replace the token mapping in the runtime so it points to the new object
+                               RegisterToken (finished, old_token);
+                       }
+               }
+
+               //
+               // Fixup the pseudo tokens assigned to the various SRE objects
+               //
+               void FixupTokens ()
+               {
+                       var token_map = new Dictionary<int, int> ();
+                       var member_map = new Dictionary<int, MemberInfo> ();
+                       if (inst_tokens != null)
+                               FixupTokens (token_map, member_map, inst_tokens, false);
+                       if (inst_tokens_open != null)
+                               FixupTokens (token_map, member_map, inst_tokens_open, true);
+
+                       // Replace the tokens in the IL stream
+                       if (types != null) {
+                               for (int i = 0; i < num_types; ++i)
+                                       types [i].FixupTokens (token_map, member_map);
+                       }
+               }
+
                internal void Save ()
                {
                        if (transient && !is_main)
@@ -725,6 +921,8 @@ namespace System.Reflection.Emit {
                                                throw new NotSupportedException ("Type '" + types [i].FullName + "' was not completed.");
                        }
 
+                       FixupTokens ();
+
                        if ((global_type != null) && (global_type_created == null))
                                global_type_created = global_type.CreateType ();