2002-11-08 Miguel de Icaza <miguel@ximian.com>
authorMiguel de Icaza <miguel@gnome.org>
Fri, 8 Nov 2002 08:42:57 +0000 (08:42 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Fri, 8 Nov 2002 08:42:57 +0000 (08:42 -0000)
* typemanager.cs (LookupType): Added a negative-hit hashtable for
the Type lookups, as we perform quite a number of lookups on
non-Types.  This can be removed once we can deterministically tell
whether we have a type or a namespace in advance.

But this might require special hacks from our corlib.

* TODO: updated.

* ecore.cs (TryImplicitIntConversion): Handle conversions to float
and double which avoids a conversion from an integer to a double.

svn path=/trunk/mcs/; revision=8882

mcs/mcs/ChangeLog
mcs/mcs/TODO
mcs/mcs/decl.cs
mcs/mcs/driver.cs
mcs/mcs/ecore.cs
mcs/mcs/typemanager.cs

index 0a949e44181147c5dd2e679418826d98a8926fb2..da31adb6bee2bfb9da8da6630011312b05f78959 100755 (executable)
@@ -1,5 +1,17 @@
 2002-11-08  Miguel de Icaza  <miguel@ximian.com>
 
+       * typemanager.cs (LookupType): Added a negative-hit hashtable for
+       the Type lookups, as we perform quite a number of lookups on
+       non-Types.  This can be removed once we can deterministically tell
+       whether we have a type or a namespace in advance.
+
+       But this might require special hacks from our corlib.
+
+       * TODO: updated.
+
+       * ecore.cs (TryImplicitIntConversion): Handle conversions to float
+       and double which avoids a conversion from an integer to a double.
+
        * expression.cs: tiny optimization, avoid calling IsConstant,
        because it effectively performs the lookup twice.
 
index ef8d147e49047563d84787f4420535d5f0ab3f08..425ba33d379291e7652236235a069c7b4feca3f4 100644 (file)
@@ -1,3 +1,167 @@
+Notes on memory allocation
+--------------------------
+
+       A run of the AllocationProfile shows that the compiler allocates roughly
+       30 megabytes of strings.  From those, 20 megabytes come from
+       LookupType.  
+
+       See the notes on current_container problems below on memory usage.  
+
+GetNamespaces
+-------------
+
+       Obtaining the list of namespaces is an expensive process because
+       Reflection.Emit does not provide a quick way of pulling the data out,
+       and it is too slow to load it.
+
+       Calling GetNamespaces on my machine (1Ghz):
+
+               * Takes half a second with the standard assemblies (corlib + System);
+                 Fetching the types from it takes 0.0028650 seconds. 
+
+               * Loading the top 10 largest assemblies we ship with Mono makes MCS take 
+                 8 seconds to startup the first time, subsequent invocations take 2 seconds.
+
+                 Fetching all the types (Assembly.GetTypes ()) for all the assemblies takes
+                 0.0069170 seconds.
+
+       So pulling all the types takes very little time, maybe we should look into our
+       Hashtable implementation to make it more optimal.
+
+       This prohibits re-writting SimpleName to take advantage of
+       knowing the namespace names in advance.  Knowing the namespaces in advance
+       would allow me to reduce the guesswork in which we are currently engaged
+       to find a type definition.
+
+LookupTypeReflection:
+---------------------
+
+       With something like `System.Object', LookupTypeReflection will be called
+       twice: once to find out that `System' is not a type and once
+       for System.Object.
+
+       This is required because System.Reflection requires that the type/nested types are
+       not separated by a dot but by a plus sign.
+
+       A nested class would be My+Class (My being the toplevel, Class the nested one).
+
+       It is interesting to look at the most called lookups when bootstrapping MCS:
+
+    647        LTR: ArrayList
+    713        LTR: System.Globalization
+    822        LTR: System.Object+Expression
+    904        LTR: Mono.CSharp.ArrayList
+    976        LTR: System.Runtime.CompilerServices
+    999        LTR: Type
+   1118        LTR: System.Runtime
+   1208        LTR: Mono.CSharp.Type
+   1373        LTR: Mono.Languages
+   1599        LTR: System.Diagnostics
+   2036        LTR: System.Text
+   2302        LTR: System.Reflection.Emit
+   2515        LTR: System.Collections
+   4527        LTR: System.Reflection
+  22273        LTR: Mono.CSharp
+  24245        LTR: System
+  27005        LTR: Mono
+
+       Analysis:
+               The top 9 lookups are done for things which are not types.
+
+               Mono.CSharp.Type happens to be a common lookup: the class Type
+               used heavily in the compiler in the default namespace.
+
+               RED FLAG:
+
+               Then `Type' is looked up alone a lot of the time, this happens
+               in parameter declarations and am not entirely sure that this is
+               correct (FindType will pass to LookupInterfaceOrClass a the current_type.FullName,
+               which for some reason is null!).  This seems to be a problem with a lost
+               piece of context during FindType.
+
+               System.Object is also used a lot as a toplevel class, and we assume it will
+               have children, we should just shortcut this.
+
+       Adding a cache and adding a catch for `System.Object' to flag that it wont be the
+       root of a hierarchy reduced the MCS bootstrap time from 10.22 seconds to 8.90 seconds.
+
+Ideas:
+------
+
+       Instead of the hack that *knows* about System.Object not having any children classes,
+       we should just make it simple for a probe to know that there is no need for it.
+
+The use of DottedName
+---------------------
+
+       We could probably use a different system to represent names, like this:
+
+       class Name {
+               string simplename;
+               Name parent;
+       }
+
+       So `System.ComponentModel' becomes:
+
+               x: (System, null)
+               y: (ComponentModel, x)
+
+       The problem is that we would still need to construct the name to pass to
+       GetType.
+
+current_container/current_namespace and the DeclSpace
+-----------------------------------------------------
+
+       We are storing fully qualified names in the DeclSpace instead of the node,
+       this is because `current_namespace' (Namepsace) is not a DeclSpace like
+       `current_container'.
+
+       The reason for storing the full names today is this:
+
+       namespace X {
+               class Y {
+               }
+       }
+
+       namespace A {
+               class Y {
+               }
+       }
+
+       The problem is that we only use the namespace stack to track the "prefix"
+       for typecontainers, but they are not typecontainers themselves, so we have
+       to use fully qualified names, because both A.X and A.Y would be entered
+       in the toplevel type container.  If we use the short names, there would be
+       a name clash.
+
+       To fix this problem, we have to make namespaces DeclSpaces.
+
+       The full size, contrasted with the size that could be stored is:
+               corlib:
+                       Size of strings held: 368901
+                       Size of strings short: 147863
+
+               System:
+                       Size of strings held: 212677
+                       Size of strings short: 97521
+               
+               System.XML:
+                       Size of strings held: 128055
+                       Size of strings short: 35782
+               
+               System.Data:
+                       Size of strings held: 117896
+                       Size of strings short: 36153
+               
+               System.Web:
+                       Size of strings held: 194527
+                       Size of strings short: 58064
+               
+               System.Windows.Forms:
+                       Size of strings held: 220495
+                       Size of strings short: 64923
+
+       
 TODO:
 
        1. Create a "partial" emit context for each TypeContainer..
@@ -28,9 +192,6 @@ readonly variables and ref/out
 BUGS
 ----
 
-* We suck at reporting what turns out to be error -6.  Use the standard error message
-  instead.
-
 * Check for Final when overriding, if the parent is Final, then we cant
   allow an override.
 
@@ -71,13 +232,6 @@ BUGS
 PENDING TASKS
 -------------
 
-* IMprove error handling here:
-
-       public static Process ()
-
-       THat assumes that it is a constructor, check if its the same name
-       as the class, if not report a different error than the one we use now.
-
 * Merge test 89 and test-34
 
 * Revisit
@@ -85,11 +239,6 @@ PENDING TASKS
        Primary-expression, as it has now been split into 
        non-array-creation-expression and array-creation-expression.
                
-* Static flow analysis
-
-       Required to warn about reachability of code and definite
-       assignemt as well as missing returns on functions.
-
 * Code cleanup
 
        The information when registering a method in InternalParameters
@@ -105,9 +254,6 @@ PENDING TASKS
 
 * Make sure that we are pinning the right variable
 
-* Maybe track event usage?  Currently I am not tracking these, although they
-  are fields.
-
 * Merge tree.cs, rootcontext.cs
 
 OPTIMIZATIONS
@@ -135,6 +281,15 @@ OPTIMIZATIONS
 
        We should get rid of the Localtemporary there for some cases
 
+       This turns out to be very complex, at least for the post-version,
+       because this case:
+
+               a = i++
+
+       To produce optimal code, it is necessary for UnaryMutator to know 
+       that it is being assigned to a variable (the way the stack is laid
+       out using dup requires the store to happen inside UnaryMutator).
+
 * Emitcontext
 
        Do we really need to instanciate this variable all the time?
@@ -142,13 +297,6 @@ OPTIMIZATIONS
        It could be static for all we care, and just use it for making
        sure that there are no recursive invocations on it.
 
-* ConvertImplicit
-
-       Currently ConvertImplicit will not catch things like:
-
-       - IntLiteral in a float context to generate a -FloatLiteral.
-       Instead it will perform an integer load followed by a conversion.
-
 * Tests
 
        Write tests for the various reference conversions.  We have
@@ -180,8 +328,6 @@ OPTIMIZATIONS
        If the types are the same, there is no need to compute the unionset,
        we can just use the list from one of the types.
 
-* Factor all the FindMembers in all the FindMembers providers.
-
 * Factor the lookup code for class declarations an interfaces
   (interface.cs:GetInterfaceByName)
 
index a18ced8b8e58eb8e4a156c3e42609a90bf316edc..471e9c5e4ec45547ec4755e5e559d9f3056faafb 100755 (executable)
@@ -260,6 +260,9 @@ namespace Mono.CSharp {
                        return AdditionResult.Success;
                }
 
+               public static int length;
+               public static int small;
+               
                /// <summary>
                ///   Introduce @name into this declaration space and
                ///   associates it with the object @o.  Note that for
@@ -268,6 +271,13 @@ namespace Mono.CSharp {
                protected void DefineName (string name, object o)
                {
                        defined_names.Add (name, o);
+
+#if DEBUGME
+                       int p = name.LastIndexOf (".");
+                       int l = name.Length;
+                       length += l;
+                       small += l -p;
+#endif
                }
 
                /// <summary>
@@ -399,6 +409,7 @@ namespace Mono.CSharp {
 
                        int errors = Report.Errors;
                        Expression d = e.Resolve (type_resolve_ec, ResolveFlags.Type);
+                       
                        if (d == null || d.eclass != ExprClass.Type){
                                if (!silent && errors == Report.Errors){
                                        Report.Error (246, loc, "Cannot find type `"+ e.ToString () +"'");
@@ -419,6 +430,7 @@ namespace Mono.CSharp {
                                type_resolve_ec = GetTypeResolveEmitContext (parent, loc);
 
                        Expression d = e.Resolve (type_resolve_ec, ResolveFlags.Type);
+                        
                        if (d == null || d.eclass != ExprClass.Type){
                                if (!silent){
                                        Report.Error (246, loc, "Cannot find type `"+ e +"'");
@@ -489,7 +501,7 @@ namespace Mono.CSharp {
 
                                while (current_type != null) {
                                        string pre = current_type.FullName;
-                                       
+
                                        t = LookupInterfaceOrClass (pre, name, out error);
                                        if (error)
                                                return null;
index e3e5a2faafb6f799160d28576b56f9515d1133ce..0ee3a3a8881ab0ed8541b62318b871e2c2ed51ae 100755 (executable)
@@ -1201,6 +1201,17 @@ namespace Mono.CSharp
 
                        TypeManager.AddModule (CodeGen.ModuleBuilder);
 
+#if DEBUGME
+                       DateTime start = DateTime.Now;
+                       TypeManager.GetNamespaces ();
+                       DateTime end = DateTime.Now;
+                       Console.WriteLine ("Loading namespaces: " + (end - start));
+                       start = DateTime.Now;
+                       TypeManager.GetAllTypes ();
+                       end = DateTime.Now;
+                       Console.WriteLine ("Getting Types: " + (end - start));
+#endif
+                       
                        //
                        // Before emitting, we need to get the core
                        // types emitted from the user defined types
@@ -1355,6 +1366,10 @@ namespace Mono.CSharp
                                return false;
                        }
 
+#if DEBUGME
+                       Console.WriteLine ("Size of strings held: " + DeclSpace.length);
+                       Console.WriteLine ("Size of strings short: " + DeclSpace.small);
+#endif
                        return (Report.Errors == 0);
                }
 
index 456dce88c741bdd0cc17575b37c6c51d08bd7bf0..56ec8066877aab47085f88d0b61cf9264daa2b12 100755 (executable)
@@ -1717,7 +1717,10 @@ namespace Mono.CSharp {
                                //
                                if (value >= 0)
                                        return new ULongConstant ((ulong) value);
-                       }
+                       } else if (target_type == TypeManager.double_type)
+                               return new DoubleConstant ((double) value);
+                       else if (target_type == TypeManager.float_type)
+                               return new FloatConstant ((float) value);
                        
                        if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
                                Type underlying = TypeManager.EnumToUnderlying (target_type);
index 0002dd1da443ba329926453c44b1593fe3a2605d..a99a2d51d96682ad02761bf75ef1003840731d97 100755 (executable)
@@ -9,6 +9,14 @@
 // (C) 2001 Ximian, Inc (http://www.ximian.com)
 //
 //
+
+//
+// We will eventually remove the SIMPLE_SPEEDUP, and should never change 
+// the behavior of the compilation.  This can be removed if we rework
+// the code to get a list of namespaces available.
+//
+#define SIMPLE_SPEEDUP
+
 using System;
 using System.Globalization;
 using System.Collections;
@@ -478,6 +486,8 @@ public class TypeManager {
                return null;
        }
 
+       static Hashtable negative_hits = new Hashtable ();
+       
        //
        // This function is used when you want to avoid the lookups, and want to go
        // directly to the source.  This will use the cache.
@@ -517,6 +527,11 @@ public class TypeManager {
                if (t != null)
                        return t;
 
+#if SIMPLE_SPEEDUP
+               if (negative_hits.Contains (name))
+                       return null;
+#endif
+               
                //
                // Optimization: ComposedCast will work with an existing type, and might already have the
                // full name of the type, so the full system lookup can probably be avoided.
@@ -539,6 +554,13 @@ public class TypeManager {
                                types [name] = t;
                                return t;
                        } 
+
+                       //
+                       // We know that System.Object does not have children, and since its the parent of 
+                       // all the objects, it always gets probbed for inner classes. 
+                       //
+                       if (top_level_type == "System.Object")
+                               return null;
                        
                        string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
                        t = LookupTypeDirect (newt);
@@ -546,6 +568,10 @@ public class TypeManager {
                                types [newt] = t;
                        return t;
                }
+
+#if SIMPLE_SPEEDUP
+               negative_hits [name] = true;
+#endif
                return null;
        }
 
@@ -575,8 +601,24 @@ public class TypeManager {
                                namespaces [ns] = ns;
                        }
                }
+               Console.WriteLine ("Namespaces: " + namespaces.Count);
                return namespaces;
        }
+
+       public static void GetAllTypes ()
+       {
+               Hashtable namespaces = new Hashtable ();
+
+               foreach (Assembly a in assemblies){
+                       foreach (Type t in a.GetTypes ()){
+                       }
+               }
+
+               foreach (ModuleBuilder mb in modules){
+                       foreach (Type t in mb.GetTypes ()){
+                       }
+               }
+       }
        
        /// <summary>
        ///   Returns the C# name of a type if possible, or the full type name otherwise