Merge pull request #495 from nicolas-raoul/fix-for-issue2907-with-no-formatting-changes
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / CodeGenerator.cs
index d26c4a2ea8cb417839d517ec452f07b13ec662b5..fd38471644b2d7ec9f2e23c0e5273b920ceb9dac 100644 (file)
@@ -5,38 +5,67 @@
 //
 // (C) 2004 Novell, Inc
 
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if !FULL_AOT_RUNTIME
 using System;
 using System.IO;
 using System.Collections;
 using System.Runtime.Serialization;
 using System.Reflection;
 using System.Reflection.Emit;
+using System.Globalization;
 
 namespace System.Runtime.Serialization.Formatters.Binary
 {
        internal class CodeGenerator
        {
                // Code generation
+
+               static object monitor = new object ();
                
                static ModuleBuilder _module;
                
-               static public Type GenerateMetadataType (Type type, StreamingContext context)
+               static CodeGenerator ()
                {
-                       if (_module == null)
-                       {
-                               lock (typeof (ObjectWriter))
-                               {
-                                       if (_module == null) {
-                                               AppDomain myDomain = System.Threading.Thread.GetDomain();
-                                               AssemblyName myAsmName = new AssemblyName();
-                                               myAsmName.Name = "__MetadataTypes";
-                                          
-                                               AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly (myAsmName, AssemblyBuilderAccess.Run);
-                                               _module = myAsmBuilder.DefineDynamicModule("__MetadataTypesModule", true);
-                                       }
-                               }
+                       AppDomain myDomain = System.Threading.Thread.GetDomain();
+                       AssemblyName myAsmName = new AssemblyName();
+                       myAsmName.Name = "__MetadataTypes";
+                  
+                       AssemblyBuilder myAsmBuilder = myDomain.DefineInternalDynamicAssembly (myAsmName, AssemblyBuilderAccess.Run);
+                       _module = myAsmBuilder.DefineDynamicModule("__MetadataTypesModule", false);
+               }
+               
+               static public Type GenerateMetadataType (Type type, StreamingContext context) {
+                       /* SRE is not thread safe */
+                       lock (monitor) {
+                               return GenerateMetadataTypeInternal (type, context);
                        }
-                       
+               }
+
+               static public Type GenerateMetadataTypeInternal (Type type, StreamingContext context)
+               {               
                        string name = type.Name + "__TypeMetadata";
                        string sufix = "";
                        int n = 0;
@@ -47,7 +76,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                
                        MemberInfo[] members = FormatterServices.GetSerializableMembers (type, context);
                        
-                       TypeBuilder typeBuilder = _module.DefineType (name, TypeAttributes.Public, typeof(TypeMetadata));
+                       TypeBuilder typeBuilder = _module.DefineType (name, TypeAttributes.Public, typeof(ClrTypeMetadata));
 
                        Type[] parameters;
                        MethodBuilder method;
@@ -56,10 +85,10 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        // *********************
                        //      METHOD public constructor (Type t): base (t);
                        
-                       parameters = new Type[0];
+                       parameters = Type.EmptyTypes;
 
-               ConstructorBuilder ctor = typeBuilder.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard, parameters);
-                       ConstructorInfo baseCtor = typeof(TypeMetadata).GetConstructor (new Type[] { typeof(Type) });
+                       ConstructorBuilder ctor = typeBuilder.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard, parameters);
+                       ConstructorInfo baseCtor = typeof(ClrTypeMetadata).GetConstructor (new Type[] { typeof(Type) });
                        gen = ctor.GetILGenerator();
 
                        gen.Emit (OpCodes.Ldarg_0);
@@ -95,9 +124,9 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        typeBuilder.DefineMethodOverride (method, typeof(TypeMetadata).GetMethod ("WriteAssemblies"));
                        
                        // *********************
-                       // METHOD public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer);
+                       // METHOD public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes);
                        
-                       parameters = new Type[] { typeof(ObjectWriter), typeof(BinaryWriter) };
+                       parameters = new Type[] { typeof(ObjectWriter), typeof(BinaryWriter), typeof(bool) };
                        method = typeBuilder.DefineMethod ("WriteTypeData", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), parameters);
                        gen = method.GetILGenerator();
                        
@@ -111,14 +140,14 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        {
                                // EMIT writer.Write (name);
                                gen.Emit (OpCodes.Ldarg_2);
-                               
-                               if (field.DeclaringType == type)
-                                       gen.Emit (OpCodes.Ldstr, field.Name);
-                               else
-                                       gen.Emit (OpCodes.Ldstr, field.DeclaringType.Name + "+" + field.Name);
+                               gen.Emit (OpCodes.Ldstr, field.Name);
                                EmitWrite (gen, typeof(string));
                        }
 
+                       Label falseLabel = gen.DefineLabel ();
+                       gen.Emit (OpCodes.Ldarg_3);
+                       gen.Emit (OpCodes.Brfalse, falseLabel);
+                                       
                        // Types of fields
                        foreach (FieldInfo field in members)
                        {
@@ -134,6 +163,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                // EMIT ow.WriteTypeSpec (writer, field.FieldType);
                                EmitWriteTypeSpec (gen, field.FieldType, field.Name);
                        }
+                       gen.MarkLabel(falseLabel);
                        
                        gen.Emit(OpCodes.Ret);
                        typeBuilder.DefineMethodOverride (method, typeof(TypeMetadata).GetMethod ("WriteTypeData"));
@@ -168,7 +198,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                {
                                        gen.Emit (OpCodes.Ldarg_2);
                                        gen.Emit (lload, localBuilder);
-                                       if (ftype == typeof(DateTime) || ftype == typeof(TimeSpan))
+                                       if (ftype == typeof(DateTime) || ftype == typeof(TimeSpan) || ftype == typeof(decimal))
                                                gen.Emit (OpCodes.Ldflda, field);
                                        else
                                                gen.Emit (OpCodes.Ldfld, field);
@@ -226,14 +256,14 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                if (t == typeof(Enum))
                                        ig.Emit (OpCodes.Ldind_Ref);
                                else
-                                       LoadFromPtr (ig, t.UnderlyingSystemType);
+                                       LoadFromPtr (ig, EnumToUnderlying (t));
                        } else if (t.IsValueType)
                                ig.Emit (OpCodes.Ldobj, t);
                        else
                                ig.Emit (OpCodes.Ldind_Ref);
                }
 
-               public static void EmitWriteTypeSpec (ILGenerator gen, Type type, string member)
+               static void EmitWriteTypeSpec (ILGenerator gen, Type type, string member)
                {
                        // WARNING Keep in sync with WriteTypeSpec
                        
@@ -300,7 +330,6 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                case TypeCode.Boolean:
                                case TypeCode.Byte:
                                case TypeCode.Char:
-                               case TypeCode.Decimal:
                                case TypeCode.Double:
                                case TypeCode.Int16:
                                case TypeCode.Int32:
@@ -314,8 +343,15 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                        EmitWrite (gen, type);
                                        break;
 
+                               case TypeCode.Decimal:
+                                       // writer.Write (val.ToString (CultureInfo.InvariantCulture));
+                                       gen.EmitCall (OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod(), null);
+                                       gen.EmitCall (OpCodes.Call, typeof(Decimal).GetMethod("ToString", new Type[] {typeof(IFormatProvider)}), null);
+                                       EmitWrite (gen, typeof(string));
+                                       break;
+                                       
                                case TypeCode.DateTime: 
-                                       gen.EmitCall (OpCodes.Call, typeof(DateTime).GetProperty("Ticks").GetGetMethod(), null);
+                                       gen.EmitCall (OpCodes.Call, typeof(DateTime).GetMethod("ToBinary", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), null);
                                        EmitWrite (gen, typeof(long));
                                        break;
                                        
@@ -329,6 +365,41 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                        break;
                        }
                }
+               
+               //
+               // This is needed, because enumerations from assemblies
+               // do not report their underlyingtype, but they report
+               // themselves
+               //
+               public static Type EnumToUnderlying (Type t)
+               {
+                       TypeCode tc = Type.GetTypeCode (t);
+       
+                       switch (tc){
+                       case TypeCode.Boolean:
+                               return typeof (bool);
+                       case TypeCode.Byte:
+                               return typeof (byte);
+                       case TypeCode.SByte:
+                               return typeof (sbyte);
+                       case TypeCode.Char:
+                               return typeof (char);
+                       case TypeCode.Int16:
+                               return typeof (short);
+                       case TypeCode.UInt16:
+                               return typeof (ushort);
+                       case TypeCode.Int32:
+                               return typeof (int);
+                       case TypeCode.UInt32:
+                               return typeof (uint);
+                       case TypeCode.Int64:
+                               return typeof (long);
+                       case TypeCode.UInt64:
+                               return typeof (ulong);
+                       }
+                       throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
+               }
        }
  }
  
+#endif