[corlib] ModuleBuilder pseudo-token lookup needs to use references insteads of logica...
[mono.git] / mcs / class / corlib / System.Reflection.Emit / ModuleBuilder.cs
index d137414ff5c2a036e880216e9ef2d7d332071155..2e985180ef549a1f9daac1d89129ded9b73a354b 100644 (file)
@@ -62,12 +62,14 @@ namespace System.Reflection.Emit {
                private FieldBuilder[] global_fields;
                bool is_main;
                private MonoResource[] resources;
+               private IntPtr unparented_classes;
                #endregion
 #pragma warning restore 169, 414
                
                private TypeBuilder global_type;
                private Type global_type_created;
-               Hashtable name_cache;
+               // name_cache keys are display names
+               Dictionary<TypeName, TypeBuilder> name_cache;
                Dictionary<string, int> us_string_cache;
                private int[] table_indexes;
                bool transient;
@@ -75,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);
 
@@ -90,7 +94,7 @@ namespace System.Reflection.Emit {
                        guid = Guid.FastNewGuidArray ();
                        // guid = Guid.NewGuid().ToByteArray ();
                        table_idx = get_next_table_index (this, 0x00, true);
-                       name_cache = new Hashtable ();
+                       name_cache = new Dictionary<TypeName, TypeBuilder> ();
                        us_string_cache = new Dictionary<string, int> (512);
 
                        basic_init (this);
@@ -105,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);
@@ -117,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 () {
@@ -262,24 +286,27 @@ namespace System.Reflection.Emit {
                private TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, Type[] interfaces, PackingSize packingSize, int typesize) {
                        if (name == null)
                                throw new ArgumentNullException ("fullname");
-                       if (name_cache.ContainsKey (name))
+                       TypeIdentifier ident = TypeIdentifiers.FromInternal (name);
+                       if (name_cache.ContainsKey (ident))
                                throw new ArgumentException ("Duplicate type name within an assembly.");
                        TypeBuilder res = new TypeBuilder (this, name, attr, parent, interfaces, packingSize, typesize, null);
                        AddType (res);
 
-                       name_cache.Add (name, res);
+                       name_cache.Add (ident, res);
                        
                        return res;
                }
 
-               internal void RegisterTypeName (TypeBuilder tb, string name)
+               internal void RegisterTypeName (TypeBuilder tb, TypeName name)
                {
                        name_cache.Add (name, tb);
                }
                
-               internal TypeBuilder GetRegisteredType (string name)
+               internal TypeBuilder GetRegisteredType (TypeName name)
                {
-                       return (TypeBuilder) name_cache [name];
+                       TypeBuilder result = null;
+                       name_cache.TryGetValue (name, out result);
+                       return result;
                }
 
                [ComVisible (true)]
@@ -304,13 +331,14 @@ namespace System.Reflection.Emit {
                }
 
                public EnumBuilder DefineEnum( string name, TypeAttributes visibility, Type underlyingType) {
-                       if (name_cache.Contains (name))
+                       TypeIdentifier ident = TypeIdentifiers.FromInternal (name);
+                       if (name_cache.ContainsKey (ident))
                                throw new ArgumentException ("Duplicate type name within an assembly.");
 
                        EnumBuilder eb = new EnumBuilder (this, name, visibility, underlyingType);
                        TypeBuilder res = eb.GetTypeBuilder ();
                        AddType (res);
-                       name_cache.Add (name, res);
+                       name_cache.Add (ident, res);
                        return eb;
                }
 
@@ -324,48 +352,36 @@ namespace System.Reflection.Emit {
                        return GetType (className, false, ignoreCase);
                }
 
-               private TypeBuilder search_in_array (TypeBuilder[] arr, int validElementsInArray, string className) {
+               private TypeBuilder search_in_array (TypeBuilder[] arr, int validElementsInArray, TypeName className) {
                        int i;
                        for (i = 0; i < validElementsInArray; ++i) {
-                               if (String.Compare (className, arr [i].FullName, true, CultureInfo.InvariantCulture) == 0) {
+                               if (String.Compare (className.DisplayName, arr [i].FullName, true, CultureInfo.InvariantCulture) == 0) {
                                        return arr [i];
                                }
                        }
                        return null;
                }
 
-               private TypeBuilder search_nested_in_array (TypeBuilder[] arr, int validElementsInArray, string className) {
+               private TypeBuilder search_nested_in_array (TypeBuilder[] arr, int validElementsInArray, TypeName className) {
                        int i;
                        for (i = 0; i < validElementsInArray; ++i) {
-                               if (String.Compare (className, arr [i].Name, true, CultureInfo.InvariantCulture) == 0)
+                               if (String.Compare (className.DisplayName, arr [i].Name, true, CultureInfo.InvariantCulture) == 0)
                                        return arr [i];
                        }
                        return null;
                }
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private static extern Type create_modified_type (TypeBuilder tb, string modifiers);
-
-               static readonly char [] type_modifiers = {'&', '[', '*'};
-
-               private TypeBuilder GetMaybeNested (TypeBuilder t, string className) {
-                       int subt;
-                       string pname, rname;
+               private TypeBuilder GetMaybeNested (TypeBuilder t, IEnumerable<TypeName> nested) {
+                       TypeBuilder result = t;
 
-                       subt = className.IndexOf ('+');
-                       if (subt < 0) {
-                               if (t.subtypes != null)
-                                       return search_nested_in_array (t.subtypes, t.subtypes.Length, className);
-                               return null;
-                       }
-                       if (t.subtypes != null) {
-                               pname = className.Substring (0, subt);
-                               rname = className.Substring (subt + 1);
-                               TypeBuilder result = search_nested_in_array (t.subtypes, t.subtypes.Length, pname);
-                               if (result != null)
-                                       return GetMaybeNested (result, rname);
+                       foreach (TypeName pname in nested) {
+                               if (result.subtypes == null)
+                                       return null;
+                               result = search_nested_in_array(result.subtypes, result.subtypes.Length, pname);
+                               if (result == null)
+                                       return null;
                        }
-                       return null;
+                       return result;
                }
 
                [ComVisible (true)]
@@ -376,41 +392,47 @@ namespace System.Reflection.Emit {
                        if (className.Length == 0)
                                throw new ArgumentException ("className");
 
-                       int subt;
-                       string orig = className;
-                       string modifiers;
                        TypeBuilder result = null;
 
                        if (types == null && throwOnError)
                                throw new TypeLoadException (className);
 
-                       subt = className.IndexOfAny (type_modifiers);
-                       if (subt >= 0) {
-                               modifiers = className.Substring (subt);
-                               className = className.Substring (0, subt);
-                       } else
-                               modifiers = null;
+                       TypeSpec ts = TypeSpec.Parse (className);
 
                        if (!ignoreCase) {
-                               result =  name_cache [className] as TypeBuilder;
+                               var displayNestedName = ts.TypeNameWithoutModifiers();
+                               name_cache.TryGetValue (displayNestedName, out result);
                        } else {
-                               subt = className.IndexOf ('+');
-                               if (subt < 0) {
-                                       if (types != null)
-                                               result = search_in_array (types, num_types,  className);
-                               } else {
-                                       string pname, rname;
-                                       pname = className.Substring (0, subt);
-                                       rname = className.Substring (subt + 1);
-                                       result = search_in_array (types, num_types, pname);
-                                       if (result != null)
-                                               result = GetMaybeNested (result, rname);
+                               if (types != null)
+                                       result = search_in_array (types, num_types,  ts.Name);
+                               if (!ts.IsNested && result != null) {
+                                       result = GetMaybeNested (result, ts.Nested);
                                }
                        }
                        if ((result == null) && throwOnError)
-                               throw new TypeLoadException (orig);
-                       if (result != null && (modifiers != null)) {
-                               Type mt = create_modified_type (result, modifiers);
+                               throw new TypeLoadException (className);
+                       if (result != null && (ts.HasModifiers || ts.IsByRef)) {
+                               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;
@@ -586,6 +608,14 @@ namespace System.Reflection.Emit {
 
                        return new MethodToken (GetToken (method));
                }
+               
+               public MethodToken GetMethodToken (MethodInfo method, IEnumerable<Type> optionalParameterTypes)
+               {
+                       if (method == null)
+                               throw new ArgumentNullException ("method");
+
+                       return new MethodToken (GetToken (method, optionalParameterTypes));
+               }
 
                public MethodToken GetArrayMethodToken (Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
                {
@@ -597,17 +627,23 @@ namespace System.Reflection.Emit {
                {
                        if (con == null)
                                throw new ArgumentNullException ("con");
-                       if (con.DeclaringType.Module != this)
-                               throw new InvalidOperationException ("The constructor is not in this module");
+
                        return new MethodToken (GetToken (con));
                }
+               
+               public MethodToken GetConstructorToken (ConstructorInfo constructor, IEnumerable<Type> optionalParameterTypes)
+               {
+                       if (constructor == null)
+                               throw new ArgumentNullException ("constructor");
+
+                       return new MethodToken (GetToken (constructor, optionalParameterTypes));
+               }
 
                public FieldToken GetFieldToken (FieldInfo field)
                {
                        if (field == null)
                                throw new ArgumentNullException ("field");
-                       if (field.DeclaringType.Module != this)
-                               throw new InvalidOperationException ("The method is not in this module");
+
                        return new FieldToken (GetToken (field));
                }
 
@@ -668,15 +704,101 @@ 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);
+
+                       var optParamTypes = new List<Type> (opt_param_types);
+                       return  getMethodToken (this, method, optParamTypes.ToArray ());
+               }
+               
                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);
                }
 
@@ -691,18 +813,103 @@ namespace System.Reflection.Emit {
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                internal extern void RegisterToken (object obj, int token);
 
+               /*
+                * Returns MemberInfo registered with the given token.
+                */
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal extern object GetRegisteredToken (int token);
+
                internal TokenGenerator GetTokenGenerator () {
                        if (token_gen == null)
                                token_gen = new ModuleBuilderTokenGenerator (this);
                        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)
@@ -714,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 ();
 
@@ -874,6 +1083,20 @@ namespace System.Reflection.Emit {
                                return m;
                }
 
+               internal MemberInfo ResolveOrGetRegisteredToken (int metadataToken, Type [] genericTypeArguments, Type [] genericMethodArguments)
+               {
+                       ResolveTokenError error;
+                       MemberInfo m = ResolveMemberToken (_impl, metadataToken, ptrs_from_types (genericTypeArguments), ptrs_from_types (genericMethodArguments), out error);
+                       if (m != null)
+                               return m;
+
+                       m = GetRegisteredToken (metadataToken) as MemberInfo;
+                       if (m == null)
+                               throw resolve_token_exception (metadataToken, error, "MemberInfo");
+                       else
+                               return m;
+               }
+
                public override MethodBase ResolveMethod (int metadataToken, Type [] genericTypeArguments, Type [] genericMethodArguments) {
                        ResolveTokenError error;