New test.
[mono.git] / mcs / ilasm / codegen / PeapiTypeRef.cs
index 2c504e7aaf44f5823277d39a4e10030237cb3ba2..704ba2df08699924cbae80fbe0e3d0a1a93ed0fd 100644 (file)
@@ -12,30 +12,51 @@ using System;
 using System.Collections;
 
 namespace Mono.ILASM {
+        public class Pair {
+                private PEAPI.Type type;
+                private string sig;
+
+                public Pair (PEAPI.Type type, string sig)
+                {
+                        this.type = type;
+                        this.sig = sig;
+                }
+
+                public override int GetHashCode ()
+                {
+                        return type.GetHashCode () ^ sig.GetHashCode (); 
+                }
+
+                public override bool Equals (Object o)
+                {
+                        Pair p = o as Pair;
+
+                        if (p == null)
+                                return false;
+                        
+                        return (p.type == this.type && p.sig == this.sig);
+                }
+        }
 
         public class PeapiTypeRef  {
 
                 private PEAPI.Type peapi_type;
-                private string full_name;
                 private bool is_pinned;
                 private bool is_array;
                 private bool is_ref;
                 private bool use_type_spec;
 
-                public PeapiTypeRef (PEAPI.Type peapi_type, string full_name)
+                private static Hashtable type_table = new Hashtable ();
+
+                public PeapiTypeRef (PEAPI.Type peapi_type)
                 {
                         this.peapi_type = peapi_type;
-                        this.full_name = full_name;
                         is_pinned = false;
                         is_array = false;
                         is_ref = false;
                         use_type_spec = false;
                 }
 
-                public string FullName {
-                        get { return full_name; }
-                }
-
                 public bool IsPinned {
                         get { return is_pinned; }
                 }
@@ -58,87 +79,138 @@ namespace Mono.ILASM {
 
                 public void MakeArray ()
                 {
+                        PEAPI.Type type;
+
                         use_type_spec = true;
+                        is_array = true;
 
-                        if (peapi_type is PEAPI.Class) {
-                                PEAPI.Class klass = (PEAPI.Class) peapi_type;
-                                peapi_type = klass.GetZeroBasedArray ();
-                        } else {
-                                peapi_type = new PEAPI.ZeroBasedArray (peapi_type);
+                        Pair p = new Pair (peapi_type, "[]");
+                        type = type_table [p] as PEAPI.Type;
+                        if (type == null) {
+                                type = new PEAPI.ZeroBasedArray (peapi_type);
+                                type_table [p] = type;
                         }
-                        full_name += "[]";
-                        is_array = true;
+                        peapi_type = type;
                 }
 
                 public void MakeBoundArray (ArrayList bound_list)
                 {
                         use_type_spec = true;
+                        is_array = true;
 
                         int dimen = bound_list.Count;
                         int[] lower_array = new int[dimen];
                         int[] size_array = new int[dimen];
-                        bool lower_set = false;
-                        bool size_set = false;
-                        bool prev_lower_set = true;
-                        bool prev_size_set = true;
+                        int [] lobounds = null;
+                        int [] sizes = null;
+                        int num_lower, num_sizes;
+                        string sigmod = "";
+                        PEAPI.Type type;
+                        Pair p;
+
+                        sigmod += "[";
+                        for (int i=0; i<bound_list.Count; i++) {
+                                DictionaryEntry e = (DictionaryEntry) bound_list [i];
+                                if (e.Key != TypeRef.Ellipsis)
+                                        sigmod += e.Key;
+                                sigmod += "...";
+                                if (e.Value != TypeRef.Ellipsis)
+                                        sigmod += e.Value;
+                                if (i + 1 < bound_list.Count)
+                                        sigmod += ", ";
+                        }
+                        sigmod += "]";
 
+                        p = new Pair (peapi_type, sigmod);
+                        type = type_table [p] as PEAPI.Type;
+                        if (type != null) {
+                                peapi_type = type;
+                                return;
+                        }
+
+                        num_sizes = num_lower = 0;
                         // TODO: There should probably be an error reported if
                         // something like [3...,3...5] is done
                         for (int i=0; i<dimen; i++) {
-                                DictionaryEntry bound = (DictionaryEntry) bound_list[i];
-
-                                if (bound.Key != null && prev_lower_set) {
-                                        lower_array[i] = (int) bound.Key;
-                                        lower_set = true;
-                                } else {
-                                        prev_lower_set = false;
+                                if (bound_list [i] == null)
+                                        continue;
+                                        
+                                DictionaryEntry bound = (DictionaryEntry) bound_list [i];
+                                
+                                if (bound.Key != TypeRef.Ellipsis) {
+                                        /* Lower bound specified */
+                                        lower_array [i] = (int) bound.Key;
+                                        num_lower = i + 1;
                                 }
-                                if (bound.Value != null && prev_size_set) {
-                                        size_array[i] = (int) bound.Value;
-                                        size_set = true;
-                                } else {
-                                        prev_size_set = false;
+                                if (bound.Value != TypeRef.Ellipsis) {
+                                        size_array [i] = (int) bound.Value;
+                                        if (bound.Key != TypeRef.Ellipsis)
+                                                /* .Value is Upper bound eg [1...5] */
+                                                size_array [i] -= lower_array [i] - 1;
+                                        num_sizes = i + 1;
                                 }
                         }
-                        if (lower_set && size_set) {
-                                peapi_type = new PEAPI.BoundArray (peapi_type,
-                                                (uint) dimen, lower_array, size_array);
-                        } else if (size_set) {
-                                peapi_type = new PEAPI.BoundArray (peapi_type,
-                                                (uint) dimen, size_array);
-                        } else {
-                                peapi_type = new PEAPI.BoundArray (peapi_type, (uint) dimen);
+
+                        if (num_lower > 0) {
+                                lobounds = new int [num_lower];
+                                Array.Copy (lower_array, lobounds, num_lower);
                         }
-                        /// TODO: Proper full names
-                        full_name += "[][]";
-                        is_array = true;
+
+                        if (num_sizes > 0) {
+                                sizes = new int [num_sizes];
+                                Array.Copy (size_array, sizes, num_sizes);
+                        }
+
+                        peapi_type = new PEAPI.BoundArray (peapi_type,
+                                                (uint) dimen, lobounds, sizes);
+                        type_table [p] = peapi_type;
                 }
 
                 public void MakeManagedPointer ()
                 {
+                        PEAPI.Type type;
                         use_type_spec = true;
-
-                        peapi_type = new PEAPI.ManagedPointer (peapi_type);
-                        full_name += "&";
                         is_ref = true;
+
+                        Pair p = new Pair (peapi_type, "&");
+                        type = type_table [p] as PEAPI.Type;
+                        if (type == null) {
+                                type = new PEAPI.ManagedPointer (peapi_type);
+                                type_table [p] = type;
+                        }
+                        peapi_type = type;
                 }
 
                 public void MakeUnmanagedPointer ()
                 {
+                        PEAPI.Type type;
                         use_type_spec = true;
 
-                        peapi_type = new PEAPI.UnmanagedPointer (peapi_type);
-                        full_name += "*";
+                        Pair p = new Pair (peapi_type, "*");
+                        type = type_table [p] as PEAPI.Type;
+                        if (type == null) {
+                                type = new PEAPI.UnmanagedPointer (peapi_type);
+                                type_table [p] = type;
+                        }
+                        peapi_type = type;
                 }
 
                 public void MakeCustomModified (CodeGen code_gen, PEAPI.CustomModifier modifier,
-                                IClassRef klass)
+                                BaseClassRef klass)
                 {
-                        use_type_spec = true;
+                       PEAPI.Type type;
 
-                        klass.Resolve (code_gen);
-                        peapi_type = new PEAPI.CustomModifiedType (peapi_type,
+                        use_type_spec = true;
+                        
+                        Pair p = new Pair (peapi_type, modifier.ToString ());
+                        type = type_table [p] as PEAPI.Type;
+                        if (type == null) {
+                                klass.Resolve (code_gen);
+                                type = new PEAPI.CustomModifiedType (peapi_type,
                                         modifier, klass.PeapiClass);
+                                type_table [p] = type;
+                        }
+                        peapi_type = type;
                 }
 
                 public void MakePinned ()