//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: mkmar.cs // // Make static marshaller. // using System; using System.Collections; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Xml; using Bartok.MSIL; using System.Reflection; public class mkmar { private static void Usage() { Console.WriteLine("Usage:\n" + " mkmar /in:file.cs /out:file.cs [assemblies]\n"); } public static int Main(string[] args) { ArrayList infiles = new ArrayList(); StreamWriter outfile = null; StreamReader infile = null; if (args.Length == 0) { Usage(); return 0; } for (int i = 0; i < args.Length; i++) { string arg = args[i]; if (arg.Length >= 2 && (arg[0] == '-' || arg[0] == '/')) { string name = null; string value = null; int n = arg.IndexOf(':'); if (n > -1) { name = arg.Substring(1, n - 1).ToLower(); if (n < arg.Length + 1) { value = arg.Substring(n + 1); } } else { name = arg.Substring(1).ToLower(); } bool badArg = false; switch (name) { case "out" : if (value != null) { outfile = new StreamWriter(value); } else { badArg = true; } break; case "in" : if (value != null) { infile = new StreamReader(value); } else { badArg = true; } break; default : badArg = true; break; } if (badArg) { Console.WriteLine("Malformed argument: \"" + arg + "\""); Usage(); return 1; } } else { // This is just an assembly name infiles.Add(arg); } } if (outfile == null) { Console.WriteLine("You must specify the output file."); Usage(); return 1; } if (infile == null) { Console.WriteLine("You must specify the input file."); Usage(); return 1; } if (infiles.Count == 0) { Console.WriteLine("You must specify at least one input file."); Usage(); return 1; } ProcessAssemblies(infiles, infile, outfile); return 0; } private static SortedList used; private static MetaDataResolver resolver; private static TypeInfo tiObject; private static TypeInfo tiString; private static void ProcessAssemblies(ArrayList infiles, TextReader tr, TextWriter tw) { resolver = new MetaDataResolver(infiles, new ArrayList(), new DateTime(), false, false); MetaDataResolver.ResolveCustomAttributes( new MetaDataResolver[]{resolver}); TypeInfo.Add("bool"); TypeInfo.Add("char"); TypeInfo.Add("byte"); TypeInfo.Add("sbyte"); TypeInfo.Add("ushort"); TypeInfo.Add("short"); TypeInfo.Add("uint"); TypeInfo.Add("int"); TypeInfo.Add("ulong"); TypeInfo.Add("long"); tiObject = TypeInfo.Add("object"); tiObject.isParent = true; tiString = TypeInfo.Add("string"); tiObject.isRefType = true; // We must always support null. SortedList spaces = new SortedList(); tw.WriteLine("#define TRACE_CHEAP_STATE"); tw.WriteLine("#if !USE_CLR_REMOTING"); tw.WriteLine("using System;"); tw.WriteLine("using System.Runtime.Serialization;"); tw.WriteLine("using Bartok.Marshal;"); foreach (MetaData metadata in resolver.MetaDataList) { foreach (MetaDataTypeDefinition type in metadata.TypeDefs) { if (IsMarshalType(type) && type.Namespace != "" && !spaces.Contains(type.Namespace)) { spaces.Add(type.Namespace, null); } } } for (int id = 0; id < spaces.Count; id++) { tw.WriteLine("using {0};", spaces.GetKey(id)); } tw.WriteLine(); #if false foreach (MetaData metadata in resolver.MetaDataList) { Console.WriteLine("{0}", metadata.Name); foreach (MetaDataTypeDefinition type in metadata.TypeDefs) { Console.WriteLine(" {0,4} {1}", type.GetHashCode(), type.FullName); } } #endif // We first try to get all of the types from serialized fields // so we have a Signature.Type. foreach (MetaData metadata in resolver.MetaDataList) { foreach (MetaDataTypeDefinition type in metadata.TypeDefs) { if (!IsMarshalType(type)) { continue; } foreach (MetaDataField field in type.Fields) { if (!IsMarshalField(field)) { continue; } TypeInfo.Add(field.Signature.FieldType, "field"); } } } // Then we pick up any [Serializable] classes. foreach (MetaData metadata in resolver.MetaDataList) { foreach (MetaDataTypeDefinition type in metadata.TypeDefs) { if (IsMarshalType(type)) { TypeInfo.Add(type, "serial"); } } } // Last we pick up any enclosing classes. for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { continue; } if (ti.type != null) { MetaDataTypeDefinition md = ti.type; if (md.EnclosingClass != null) { MetaDataTypeDefinition type = md.EnclosingClass; TypeInfo.Add(type, "enclose"); } } } CompleteTypeInfoFields(); tw.WriteLine("// {0} types.", used.Count); tw.WriteLine("// {0:x8}: null", 0); for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { continue; } string attrs = ""; attrs += (ti.type != null) ? "d" : "-"; attrs += (ti.isUsedInField) ? "f" : "-"; attrs += (ti.isParent) ? "p" : "-"; attrs += (ti.isAbstract) ? "a" : "-"; attrs += (ti.isSealed) ? "s" : "-"; attrs += (ti.isOverload) ? "o" : "-"; attrs += (ti.isRefType) ? "r" : "-"; attrs += (ti.isInterface) ? "i" : "-"; attrs += (ti.isEnum) ? "e" : "-"; attrs += (ti.isStruct) ? "s" : "-"; attrs += (ti.isBuiltIn) ? "b" : "-"; attrs += (ti.hasArray != null) ? "v" : "-"; tw.WriteLine("// {0:x8}: {1,-7} {2} {3,4} {4} {5}", id, ti.reason, attrs, ((ti.type != null) ? ti.type.GetHashCode() : 0), ti.kind, ti.isArray ? ":" + ti.arrayOf.kind : ""); } tw.WriteLine("#endif // !USE_CLR_REMOTING"); tw.WriteLine(); string ns = ""; for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { // ignore null. continue; } if (ti.type == null) { continue; } if (ti.isEnclosed) { // We pick up the enclosed types with their outer class. continue; } // need to handle nested classes... if (ns != ti.type.Namespace) { if (ns != "") { tw.WriteLine("}"); // tw.WriteLine(); } ns = ti.type.Namespace; tw.WriteLine("namespace {0} {{", ns); } DoClass(ti, tw); } if (ns != "") { tw.WriteLine("}"); // tw.WriteLine(); } tw.WriteLine(new String('/', 78)); tw.WriteLine("//"); tw.WriteLine("namespace Bartok.Marshal {"); tw.WriteLine("#if !USE_CLR_REMOTING"); tw.WriteLine(" public delegate void CheapWriteDelegate(CheapState __cs, Object __ob);"); tw.WriteLine(" public delegate object CheapReadDelegate(uint __id, CheapState __cs);"); tw.WriteLine("#endif // !USE_CLR_REMOTING"); tw.WriteLine(); tw.WriteLine(" public class CheapState {"); tw.WriteLine("#if !USE_CLR_REMOTING"); tw.WriteLine(" public enum Types {"); tw.WriteLine(" {0,-23} = 0x{1:x8},", "Null", 0); for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { continue; } if (ti.isBuiltIn) { if (ti.isArray) { tw.WriteLine(" {0,-23} = 0x{1:x8},", ToEnumName(ti.arrayOf.kind + "Array"), id); } else { tw.WriteLine(" {0,-23} = 0x{1:x8},", ToEnumName(ti.kind), id); } } } tw.WriteLine(" };"); tw.WriteLine(); for (string line; (line = tr.ReadLine()) != null;) { tw.WriteLine(line); } tw.WriteLine("#endif //!USE_CLR_REMOTING"); tw.WriteLine(" }"); tw.WriteLine("}"); tw.WriteLine(); tw.WriteLine("namespace Bartok.Marshal {"); tw.WriteLine(" public class CheapMarshal {"); tw.WriteLine(" public static int Main()"); tw.WriteLine(" {"); tw.WriteLine(" Console.WriteLine(\"Testing\");"); tw.WriteLine(" CheapState cs = new CheapState(0);"); tw.WriteLine(" Test(cs);"); tw.WriteLine(" return 0;"); tw.WriteLine(" }"); tw.WriteLine(); tw.WriteLine(" static CheapMarshal() {"); tw.WriteLine("#if !USE_CLR_REMOTING"); tw.WriteLine(" System.Collections.Hashtable writeHash = new System.Collections.Hashtable({0});", used.Count + 1); tw.WriteLine(" System.Collections.Hashtable readHash = new System.Collections.Hashtable({0});", used.Count + 1); tw.WriteLine(); tw.WriteLine(" CheapState.writeHash = writeHash;"); tw.WriteLine(" CheapState.readHash = readHash;"); tw.WriteLine(); for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { continue; } if (ti.kind == "object" || ti.isInterface) { tw.WriteLine(" // dropping {0} as interface.", ti.kind); continue; } if (ti.isArray) { tw.WriteLine(" // dropping {0} as array.", ti.kind); continue; } if (ti.isEnum) { tw.WriteLine(" // dropping {0} as enum.", ti.kind); continue; } if (ti.isAbstract && ti.children == null) { tw.WriteLine(" // dropping {0} as abstract without children.", ti.kind); continue; } if (ti.isBuiltIn) { // for now we just drop theses. tw.WriteLine(" // dropping {0} as builtin.", ti.kind); continue; } tw.WriteLine(" writeHash.Add(typeof({0}),", ti.kind); tw.WriteLine(" new CheapWriteDelegate({1}.CheapWriteItem));", ti.kind, ti.kind); if (!ti.isAbstract) { tw.WriteLine(" readHash.Add((uint)0x{0:x8},", ti.id); tw.WriteLine(" new CheapReadDelegate({1}.CheapReadItem));", ti.kind, ti.kind); } else { tw.WriteLine(" // dropping read.{0} as abstract.", ti.kind); } if (ti.hasArray != null) { tw.WriteLine(" writeHash.Add(typeof({0}),", ti.hasArray.kind); tw.WriteLine(" new CheapWriteDelegate({1}.CheapWriteArray));", ti.hasArray.kind, ti.kind); tw.WriteLine(" readHash.Add((uint)0x{0:x8},", ti.hasArray.id); tw.WriteLine(" new CheapReadDelegate({1}.CheapReadArray));", ti.hasArray.kind, ti.kind); } } tw.WriteLine("#endif // !USE_CLR_REMOTING"); tw.WriteLine(" }"); ////////////////////////////////////////////////////////////////////// // tw.WriteLine(" public static void Test(CheapState __cw) {"); tw.WriteLine(" CheapState __cr = new CheapState(__cw);"); for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { // We ignore null here. continue; } if (!ti.isBuiltIn || ti.isRefType) { continue; } if (ti.kind == "bool" || ti.kind == "char") { continue; } tw.WriteLine(" {"); tw.WriteLine(" __cw.Trace(\"Testing {0}\");", ti.kind); tw.WriteLine(" {0} value = 0x77;", ti.kind); tw.WriteLine(" __cw.WriteOpen();"); tw.WriteLine(" __cw.Write(value);"); tw.WriteLine(" __cw.WriteClose();"); tw.WriteLine(" __cw.Trace();"); tw.WriteLine(" __cr.ReadOpen();"); tw.WriteLine(" __cr.Read(out value);"); tw.WriteLine(" __cr.ReadClose();"); tw.WriteLine(" __cr.Trace();"); tw.WriteLine(" Console.WriteLine(\"Testing {0}\");", ti.kind); tw.WriteLine(" }"); continue; } for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { // We ignore null here. continue; } if (ti.isInterface || ti.isAbstract) { continue; } if (ti.isBuiltIn || ti.isArray || !ti.isRefType) { // Base types are handled manually. continue; } tw.WriteLine(" {"); tw.WriteLine(" __cw.Trace(\"Testing {0}\");", ti.kind); tw.WriteLine(" {0} value = new {0}();", ti.kind); tw.WriteLine(" __cw.WriteOpen();"); tw.WriteLine(" {0}.CheapWrite(__cw, value);", ti.kind); tw.WriteLine(" __cw.WriteClose();"); tw.WriteLine(" __cw.Trace();"); tw.WriteLine(" __cr.ReadOpen();"); tw.WriteLine(" {0}.CheapRead(__cr, out value);", ti.kind); tw.WriteLine(" __cr.ReadClose();"); tw.WriteLine(" __cr.Trace();"); tw.WriteLine(" Console.WriteLine(\"Testing {0}\");", ti.kind); tw.WriteLine(" }"); } for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { // We ignore null here. continue; } if (ti.isInterface || ti.isAbstract) { continue; } if (ti.isBuiltIn || ti.isArray || !ti.isRefType) { // Base types are handled manually. continue; } tw.WriteLine(" {"); tw.WriteLine(" __cw.Trace(\"Testing {0}\");", ti.kind); tw.WriteLine(" {0} value = new {0}();", ti.kind); if (ti.fields != null) { foreach (FieldInfo fi in ti.fields) { fi.WriteTestInit(tw); } } tw.WriteLine(" __cw.WriteOpen();"); tw.WriteLine(" {0}.CheapWrite(__cw, value);", ti.kind); tw.WriteLine(" __cw.WriteClose();"); tw.WriteLine(" __cw.Trace();"); tw.WriteLine(" __cr.ReadOpen();"); tw.WriteLine(" {0}.CheapRead(__cr, out value);", ti.kind); tw.WriteLine(" __cr.ReadClose();"); tw.WriteLine(" __cr.Trace();"); tw.WriteLine(" Console.WriteLine(\"Testing {0}\");", ti.kind); tw.WriteLine(" }"); } tw.WriteLine(" {"); tw.WriteLine(" __cw.Trace(\"Testing Linked List\");"); tw.WriteLine(" NullType[] nt = new NullType[4];"); tw.WriteLine(" for (int i = 0; i < nt.Length; i++) {"); tw.WriteLine(" nt[i] = new NullType();"); tw.WriteLine(" nt[i].name = \"nt[\" + i.ToString() + \"]\";"); tw.WriteLine(" nt[i].hashCode = i;"); tw.WriteLine(" }"); tw.WriteLine(" for (int i = 0; i < nt.Length - 1; i++) {"); tw.WriteLine(" nt[i].backEndRep = nt[i+1];"); tw.WriteLine(" }"); tw.WriteLine(" for (int i = 1; i < nt.Length; i++) {"); tw.WriteLine(" nt[i].backEndMangledName = nt[i-1];"); tw.WriteLine(" }"); tw.WriteLine(" "); tw.WriteLine(" __cw.WriteOpen();"); tw.WriteLine(" NullType.CheapWrite(__cw, nt[0]);"); tw.WriteLine(" __cw.WriteClose();"); tw.WriteLine(" __cw.Trace();"); tw.WriteLine(" NullType value = null;"); tw.WriteLine(" __cr.ReadOpen();"); tw.WriteLine(" NullType.CheapRead(__cr, out value);"); tw.WriteLine(" __cr.ReadClose();"); tw.WriteLine(" __cr.Trace();"); tw.WriteLine(" for (int i = 0; value != null; i++) {"); tw.WriteLine(" __cr.Trace(\"{0,2}: {1,-10} : {2,2} : {3} {4}\","); tw.WriteLine(" i, value.name, value.hashCode,"); tw.WriteLine(" value.backEndRep != null ? ((NullType)value.backEndRep).name : \"\","); tw.WriteLine(" value.backEndMangledName != null ? ((NullType)value.backEndMangledName).name : \"\");"); tw.WriteLine(" value = (NullType)value.backEndRep;"); tw.WriteLine(" }"); tw.WriteLine(" __cr.Trace();"); tw.WriteLine(" Console.WriteLine(\"Testing Linked List\");"); tw.WriteLine(" }"); tw.WriteLine(" }"); // end of Test() method. tw.WriteLine(" }"); // end of CheapMarshal class. tw.WriteLine("}"); // end of Bartok.Marshal namespace. tw.Flush(); } private static string ToEnumName(string name) { int pos = name.LastIndexOf('.'); if (pos >= 0) { return Char.ToUpper(name[pos + 1]) + name.Substring(pos + 2); } return Char.ToUpper(name[0]) + name.Substring(1); } private static void DoClass(TypeInfo ti, TextWriter tw) { int id = ti.id; MetaDataTypeDefinition type = ti.type; if (ti.isEnum) { tw.WriteLine(" public enum {0} {{ // {1}", type.Name, type.FullName); tw.WriteLine(" VALUE = 0,"); tw.WriteLine(" }"); return; } if (ti.isOverload) { tw.WriteLine(" // is child class"); } if (ti.isParent) { tw.WriteLine(" // is parent class"); foreach (TypeInfo ci in ti.children) { tw.WriteLine(" // child {0}", ci.kind); } foreach (TypeInfo ci in ti.descendants) { tw.WriteLine(" // des {0}", ci.kind); } } if (ti.isStruct) { tw.WriteLine(" public struct {0} {{ // {1}", type.Name, type.FullName); } else if (ti.isInterface) { if (ti.isOverload) { // else if (type.Extends != null && type.Extends.FullName != "System.Object") tw.WriteLine(" public interface {0} : {1} {{ // {2}", type.Name, type.Extends.FullName, type.FullName); } else { tw.WriteLine(" public interface {0} {{ // {1}", type.Name, type.FullName); } tw.WriteLine(" }"); tw.WriteLine(); return; } else { if (ti.isOverload) { // else if (type.Extends != null && type.Extends.FullName != "System.Object") tw.WriteLine(" public {0}class {1} : {2} {{ // {3}", ti.isAbstract ? "abstract " : "", type.Name, type.Extends.FullName, type.FullName); } else { tw.WriteLine(" public {0}class {1} : Object {{ // {2}", ti.isAbstract ? "abstract " : "", type.Name, type.FullName); } } string vlabel = ""; if (ti.isOverload) { vlabel = "override "; } else if (ti.isParent) { vlabel = "virtual "; } FieldInfo[] fields = ti.fields; //////////////////////////////////////// Null Constructor for Testing. // if (!ti.isStruct && !ti.isAbstract) { tw.WriteLine(" // For Testing."); tw.WriteLine(" public {0}() {{", type.Name); tw.WriteLine(" }"); } tw.WriteLine(" // For Testing."); for (int i = 0; i < fields.Length; i++) { tw.WriteLine(" public {0} {1};", fields[i].Type.kind, fields[i].Name); } tw.WriteLine(); //////////////////////////////////////////////////////////// Core Constructor. // if (ti.isAbstract && ti.children == null) { // Abort early since class exists only to hold inner types... if (ti.inner != null) { tw.WriteLine(); foreach (TypeInfo inner in ti.inner) { DoClass(inner, tw); } } tw.WriteLine(" }"); tw.WriteLine(); return; } tw.WriteLine("#if !USE_CLR_REMOTING"); if (ti.isAbstract) { tw.WriteLine(" public {0}() {{", type.Name); tw.WriteLine(" }"); tw.WriteLine(); } if (ti.isOverload) { tw.WriteLine(" private {0}(uint __id, CheapState __cs)", type.Name); tw.WriteLine(" : base(__cs) {"); } else { tw.WriteLine(" private {0}(uint __id, CheapState __cs) {{", type.Name); } tw.WriteLine(" if (__id != 0x{0:x8}) {{", ti.id); tw.WriteLine(" throw new Exception(\"__id != Type(0x{0:x8}) for {1}\");", ti.id, type.FullName); tw.WriteLine(" }"); if (!ti.isOverload && !ti.isStruct) { tw.WriteLine(" __cs.AddPtr(this, 0x{0:x8});", ti.id); } bool hadEv = false; bool hadOb = false; for (int i = 0; i < fields.Length; i++) { TypeInfo fi = fields[i].Type; if (fi.isInterface) { if (!hadOb) { tw.WriteLine(" object __ob;"); hadOb = true; } tw.WriteLine(" __cs.Read(out __ob);"); tw.WriteLine(" {0} = ({1})__ob;", fields[i].Name, fi.kind); } else if (fi.isArray) { if (fi.arrayOf.type != null) { tw.WriteLine(" {0}.CheapRead(__cs, out {1}); // {2}", fi.arrayOf.kind, fields[i].Name, fi.kind); } else { tw.WriteLine(" __cs.Read(out {0}); // {1}", fields[i].Name, fi.kind); } } else if (fi.isEnum) { if (!hadEv) { tw.WriteLine(" uint __ev;"); hadEv = true; } tw.WriteLine(" __cs.Read(out __ev); // {0}", fi.kind); tw.WriteLine(" {0} = unchecked(({1})__ev);", fields[i].Name, fi.kind); } else if (fi.type != null) { tw.WriteLine(" {0}.CheapRead(__cs, out {1});", fi.kind, fields[i].Name); } else { // It is a builtin. tw.WriteLine(" __cs.Read(out {0}); // {1}", fields[i].Name, fi.kind); } } tw.WriteLine(" __cs.ReadTypeEnd(0x{0:x8});", ti.id); tw.WriteLine(" }"); tw.WriteLine(); ////////////////////////////////////////////////////////////////////// // if (!ti.isStruct) { tw.WriteLine(" {0}{1}(CheapState __cs)", ti.isSealed ? "private " : "protected ", type.Name); tw.WriteLine(" : this(__cs.ReadType(0x{0:x8}), __cs) {{", ti.id); tw.WriteLine(" }"); tw.WriteLine(); } if (ti.isStruct) { tw.WriteLine(" private void CheapWrite(CheapState __cs) {"); } else { tw.WriteLine(" {0}{1}void CheapWrite(CheapState __cs) {{", (ti.isSealed && !ti.isOverload) ? "private " : "protected ", vlabel); } tw.WriteLine(" __cs.WriteType(0x{0:x8}); ", ti.id); if (ti.isOverload) { tw.WriteLine(" base.CheapWrite(__cs);"); } for (int i = 0; i < fields.Length; i++) { TypeInfo fi = fields[i].Type; if (fi.isInterface) { tw.WriteLine(" __cs.Write((object){0}); // {1}", fields[i].Name, fi.kind); } else if (fi.isArray) { if (fi.arrayOf.type != null) { tw.WriteLine(" {0}.CheapWrite(__cs, {1}); // {2}", fi.arrayOf.kind, fields[i].Name, fi.kind); } else { tw.WriteLine(" __cs.Write({0}); // {1}", fields[i].Name, fi.kind); } } else if (fi.isEnum) { tw.WriteLine(" __cs.Write(unchecked((uint){0})); // {1}", fields[i].Name, fi.kind); } else if (fi.type != null) { tw.WriteLine(" {0}.CheapWrite(__cs, {1}); // {2}", fi.kind, fields[i].Name, fi.kind); } else { // It is a builtin. tw.WriteLine(" __cs.Write({0}); // {1}", fields[i].Name, fi.kind); } } tw.WriteLine(" __cs.WriteTypeEnd(0x{0:x8}); ", ti.id); tw.WriteLine(" }"); tw.WriteLine(); tw.WriteLine(" public static {0}void CheapWriteItem(CheapState __cs, Object __ob) {{", ti.isOverload ? "new " : ""); tw.WriteLine(" CheapWrite(__cs, ({0})__ob);", type.Name); tw.WriteLine(" }"); tw.WriteLine(); if (!ti.isAbstract) { tw.WriteLine(" public static {0}Object CheapReadItem(uint __id, CheapState __cs) {{", (ti.isOverload && !ti.ParentsAreAllAbstract()) ? "new " : ""); tw.WriteLine(" if ((__id & 0x8000) != 0) {"); tw.WriteLine(" return __cs.LoadPtr(__id);"); tw.WriteLine(" }"); if (!ti.isRefType) { tw.WriteLine(" object __ob = new {0}(__id, __cs);", type.Name); tw.WriteLine(" __cs.AddPtr(__ob, __id);"); tw.WriteLine(" return __ob;"); } else { tw.WriteLine(" return new {0}(__id, __cs);", type.Name); } tw.WriteLine(" }"); tw.WriteLine(); } tw.WriteLine(" public static void CheapWrite(CheapState __cs, {0} value) {{", type.Name); tw.WriteLine(" __cs.Trace(\"Write {0} [outer]\");", type.Name); if (ti.isRefType) { tw.WriteLine(" if (value == null) {"); tw.WriteLine(" __cs.WriteType(0);"); tw.WriteLine(" }"); tw.WriteLine(" else if (__cs.SavePtr(0x{0:x8}, value)) {{", ti.id); tw.WriteLine(" value.CheapWrite(__cs); "); tw.WriteLine(" }"); } else { tw.WriteLine(" value.CheapWrite(__cs); "); } tw.WriteLine(" }"); tw.WriteLine(); tw.WriteLine(" public static void CheapRead(CheapState __cs, out {0} value) {{", type.Name); tw.WriteLine(" __cs.Trace(\"Read {0} [outer]\");", type.Name); if (ti.isParent) { // Parent ref type. tw.WriteLine(" object __ob;"); tw.WriteLine(" __cs.Read(out __ob);"); tw.WriteLine(" value = __ob as {0};", type.Name); } else if (ti.isRefType) { // Leaf ref type. tw.WriteLine(" uint __id = __cs.ReadTypeOrNull(0x{0:x8});", ti.id); tw.WriteLine(" if (__id == 0) {"); tw.WriteLine(" value = null;"); tw.WriteLine(" }"); tw.WriteLine(" else {"); tw.WriteLine(" value = ({0})CheapReadItem(__id, __cs);", type.Name); tw.WriteLine(" }"); } else { // Value type. tw.WriteLine(" uint __id = __cs.ReadType(0x{0:x8});", ti.id); tw.WriteLine(" value = new {0}(__id, __cs);", type.Name); tw.WriteLine(" __cs.AddPtr(value, __id);"); } tw.WriteLine(" }"); if (ti.hasArray != null) { string alabel = ""; if (ti.isOverload && ti.parent.hasArray != null) { alabel = "new "; } tw.WriteLine(); tw.WriteLine(" public static {0}void CheapWriteArray(CheapState __cs, Object __ob) {{", alabel); tw.WriteLine(" CheapWrite(__cs, ({0}[])__ob);", type.Name); tw.WriteLine(" }"); tw.WriteLine(); tw.WriteLine(" public static void CheapWrite(CheapState __cs, {0}[] value) {{", type.Name); tw.WriteLine(" __cs.Trace(\"Write {0}[]\");", ti.kind); tw.WriteLine(" if (value == null) {"); tw.WriteLine(" __cs.WriteType(0);"); tw.WriteLine(" }"); tw.WriteLine(" else if (__cs.SavePtr(0x{0:x8}, value)) {{", ti.hasArray.id); tw.WriteLine(" __cs.WriteType(0x{0:x8});", ti.hasArray.id); tw.WriteLine(" __cs.WriteRaw((uint)value.Length);"); tw.WriteLine(" for (int i = 0; i < value.Length; i++) {"); tw.WriteLine(" CheapWrite(__cs, value[i]);"); tw.WriteLine(" }"); tw.WriteLine(" __cs.WriteTypeEnd(0x{0:x8});", ti.hasArray.id); tw.WriteLine(" }"); tw.WriteLine(" }"); tw.WriteLine(); tw.WriteLine(" public static void CheapRead(CheapState __cs, out {0}[] value) {{", type.Name); tw.WriteLine(" __cs.Trace(\"Read {0}[] [outer]\");", ti.kind); tw.WriteLine(" uint __id = __cs.ReadTypeOrNull(0x{0:x8});", ti.hasArray.id); tw.WriteLine(" value = CheapReadArrayBody(__id, __cs);"); tw.WriteLine(" }"); tw.WriteLine(); tw.WriteLine(" public static {0}Object CheapReadArray(uint __id, CheapState __cs) {{", alabel); tw.WriteLine(" return (Object)CheapReadArrayBody(__id, __cs);"); tw.WriteLine(" }"); tw.WriteLine(); tw.WriteLine(" private static {0}[] CheapReadArrayBody(uint __id, CheapState __cs) {{", type.Name); tw.WriteLine(" __cs.Trace(\"Read {0}[] [inner]\");", ti.kind); tw.WriteLine(" if (__id == 0) {"); tw.WriteLine(" return null;"); tw.WriteLine(" }"); tw.WriteLine(" else if ((__id & 0x8000) != 0) {"); tw.WriteLine(" if (__id != 0x{0:x8}) {{", ti.hasArray.id | 0x8000); tw.WriteLine(" throw new Exception(\"__id != Type(0x{0:x8}) for {1}[]\");", ti.hasArray.id | 0x8000, ti.kind); tw.WriteLine(" }"); tw.WriteLine(" return ({0}[])__cs.LoadPtr(__id);", type.Name); tw.WriteLine(" }"); tw.WriteLine(" else {"); tw.WriteLine(" if (__id != 0x{0:x8}) {{", ti.hasArray.id); tw.WriteLine(" throw new Exception(\"__id != Type(0x{0:x8}) for {1}[]\");", ti.hasArray.id, ti.kind); tw.WriteLine(" }"); tw.WriteLine(" uint len;"); tw.WriteLine(" __cs.ReadRaw(out len);"); tw.WriteLine(" {0}[] value = new {1} [len];", type.Name, type.Name); tw.WriteLine(" __cs.AddPtr(value, 0x{0:x8});", ti.hasArray.id); tw.WriteLine(" for (int i = 0; i < len; i++) {"); tw.WriteLine(" CheapRead(__cs, out value[i]);"); tw.WriteLine(" }"); tw.WriteLine(" __cs.ReadTypeEnd(0x{0:x8});", ti.hasArray.id); tw.WriteLine(" return value;"); tw.WriteLine(" }"); tw.WriteLine(" }"); } tw.WriteLine("#endif // !USE_CLR_REMOTING"); tw.WriteLine(); if (ti.inner != null) { tw.WriteLine(); foreach (TypeInfo inner in ti.inner) { DoClass(inner, tw); } } tw.WriteLine(" }"); tw.WriteLine(); } private static bool IsMarshalType(MetaDataTypeDefinition type) { uint flags = (uint)type.Flags & 0xfffffff8; if ((type.Flags & TypeAttributes.Serializable) == 0) { // We're only looking for serializable types. return false; } if ((type.Flags & TypeAttributes.Interface) != 0) { // Skip interfaces. return false; } if ((type.Flags & TypeAttributes.Class) != 0) { // We're only looking for classes. // return false; // Currently unreachable } if (type.Name == "CheapState" || type.Name == "ObjectIDGenerator") { // we drop some specific classes. return false; } return true; } private static bool IsMarshalField(MetaDataField field) { uint flags = (uint)field.Flags & 0xfff8; if (TestAndClear(ref flags, (uint)MetaDataField.FieldAttributes.NotSerialized)) { // We skip over NonSerialized fields. return false; } if (TestAndClear(ref flags, (uint)MetaDataField.FieldAttributes.Static)) { // We skip static. return false; } if (TestAndClear(ref flags, (uint)MetaDataField.FieldAttributes.InitOnly)) { return true; #if false // We skip readonly. return false; #endif } if (TestAndClear(ref flags, (uint)MetaDataField.FieldAttributes.Literal)) { // We skip const. return false; } return true; } private static string ClassToString(MetaDataObject mdo) { if (mdo is MetaDataTypeDefinition) { return ((MetaDataTypeDefinition) mdo).FullName; } else if (mdo is MetaDataTypeReference) { return ((MetaDataTypeReference) mdo).FullName; } else if (mdo == null) { return ""; } else { throw new Exception("unknown type: " + mdo.GetType()); } } private static string TypeToString(Signature.Type type) { switch (type.ElementType) { case ElementTypes.VOID: return "void"; case ElementTypes.BOOLEAN: return "bool"; case ElementTypes.CHAR: return "char"; case ElementTypes.I1: return "sbyte"; case ElementTypes.U1: return "byte"; case ElementTypes.I2: return "short"; case ElementTypes.U2: return "ushort"; case ElementTypes.I4: return "int"; case ElementTypes.U4: return "uint"; case ElementTypes.I8: return "long"; case ElementTypes.U8: return "ulong"; case ElementTypes.R4: return "float"; case ElementTypes.R8: return "double"; case ElementTypes.STRING: return "string"; //case ElementTypes.PTR: //case ElementTypes.BYREF: case ElementTypes.VALUETYPE: return ClassToString(type.ClassObject); case ElementTypes.CLASS: return ClassToString(type.ClassObject); //case ElementTypes.VAR: //case ElementTypes.ARRAY: //case ElementTypes.GENERICINST: //case ElementTypes.TYPEDBYREF: case ElementTypes.I: return "IntPtr"; case ElementTypes.U: return "UIntPtr"; //case ElementTypes.FNPTR: case ElementTypes.OBJECT: return "object"; case ElementTypes.SZARRAY: return TypeToString(type.TypeObject) + "[]"; //case ElementTypes.MVAR: //case ElementTypes.CMOD_REQD: //case ElementTypes.CMOD_OPT: //case ElementTypes.INTERNAL: default: throw new Exception("Unknown Field type"); } } private static bool TestAndClear(ref uint flags, uint bit) { if ((flags & bit) != 0) { // Console.WriteLine(" [{0:x4} had {1:x4}]", flags, bit); flags &= ~bit; return true; } return false; } private class FieldInfo { public readonly String Name; public readonly TypeInfo Type; public FieldInfo(String name, TypeInfo type) { this.Name = name; this.Type = type; } public void WriteTestInit(TextWriter tw) { if (Type.kind == "bool") { tw.WriteLine(" value.{0} = true;", Name); return; } if (Type.kind == "char") { tw.WriteLine(" value.{0} = 'A';", Name); return; } if (Type.kind == "sbyte") { tw.WriteLine(" value.{0} = 0x76;", Name); return; } if (Type.kind == "byte") { tw.WriteLine(" value.{0} = 0xfe;", Name); return; } if (Type.kind == "short") { tw.WriteLine(" value.{0} = 0x7654;", Name); return; } if (Type.kind == "ushort") { tw.WriteLine(" value.{0} = 0xfedc;", Name); return; } if (Type.kind == "int") { tw.WriteLine(" value.{0} = 0x76543210;", Name); return; } if (Type.kind == "uint") { tw.WriteLine(" value.{0} = 0xfedcba98;", Name); return; } if (Type.kind == "long") { tw.WriteLine(" value.{0} = 0x7654321001234567;", Name); return; } if (Type.kind == "ulong") { tw.WriteLine(" value.{0} = 0xfedcba9876543210;", Name); return; } if (Type.kind == "string") { tw.WriteLine(" value.{0} = \"Hello {1}!\";", Name, Name); return; } if (Type.kind == "object") { tw.WriteLine(" value.{0} = new LirBasicBlock();", Name); return; } if (Type.kind == "object[]") { tw.WriteLine(" value.{0} = new Object[] " + "{{ new LirBasicBlock(), new LirBasicBlock() }};", Name); return; } if (Type.kind == "uint[]") { tw.WriteLine(" value.{0} = new uint[] " + "{{ 0xfedcba98, 0xfedcba97 }};", Name); return; } if (Type.kind == "int[]") { tw.WriteLine(" value.{0} = new int[] " + "{{ 0x76543210, 0x76543219 }};", Name); return; } if (Type.isArray) { tw.WriteLine(" value.{0} = new {1} {{ null }};", Name, Type.kind); return; } if (Type.isRefType && !Type.isInterface) { TypeInfo ti = Type; while (ti.isAbstract) { #if false tw.WriteLine("// {0} Bypassing {1} for {2}", Name, ti.kind, ti.children[0].kind); #endif ti = ti.children[0]; } tw.WriteLine(" value.{0} = new {1}();", Name, ti.kind); } } } private class TypeInfo { static TypeInfo() { used = new SortedList(); used.Add("0", null); } public String kind; public String reason; public MetaDataTypeDefinition type; public TypeInfo parent; public TypeInfo[] children; public TypeInfo[] descendants; public TypeInfo[] inner; public TypeInfo[] users; public TypeInfo arrayOf; public TypeInfo hasArray; public FieldInfo[] fields; public int id; public bool isUsedInField; public bool isRefType; public bool isBuiltIn; public bool isArray; public bool isEnum; public bool isStruct; public bool isEnclosed; public bool isSealed; public bool isAbstract; // "abstract class foo" public bool isParent; // has children. public bool isOverload; // has a parent. public bool isInterface; // public bool hasZeroConstructor; // Currently unused private TypeInfo() { } public static TypeInfo Add(string builtin) { TypeInfo ti = new TypeInfo(); ti.kind = builtin; ti.reason = "builtin"; ti.isBuiltIn = true; used.Add(builtin, ti); return ti; } public static TypeInfo Add(MetaDataTypeDefinition md, string reason) { string kind = md.FullName; if (kind == "") { System.Diagnostics.Debugger.Break(); } TypeInfo ti; int id = used.IndexOfKey(kind); if (id > 0) { ti = used.GetByIndex(id) as TypeInfo; if (ti.type == null) { ti.SetMetaData(md); } } else { ti = new TypeInfo(); ti.kind = kind; ti.reason = reason; ti.SetMetaData(md); used.Add(ti.kind, ti); } return ti; } public static TypeInfo Add(Signature.Type st, string reason) { string kind = TypeToString(st); if (kind == "") { System.Diagnostics.Debugger.Break(); } int id = used.IndexOfKey(kind); TypeInfo ti; if (id > 0) { ti = used.GetByIndex(id) as TypeInfo; if (!ti.isUsedInField) { ti.isUsedInField = true; ti.SetFieldInfo(st); } } else { ti = new TypeInfo(); ti.kind = kind; ti.reason = reason; ti.SetFieldInfo(st); used.Add(ti.kind, ti); } return ti; } private void SetMetaData(MetaDataTypeDefinition md) { type = md; isInterface = ((md.Flags & TypeAttributes.Interface) != 0); isAbstract = ((md.Flags & TypeAttributes.Abstract) != 0); isSealed = ((md.Flags & TypeAttributes.Sealed) != 0); } private void SetFieldInfo(Signature.Type st) { switch (st.ElementType) { case ElementTypes.VOID: break; case ElementTypes.BOOLEAN: isBuiltIn = true; break; case ElementTypes.CHAR: isBuiltIn = true; break; case ElementTypes.I1: isBuiltIn = true; break; case ElementTypes.U1: isBuiltIn = true; break; case ElementTypes.I2: isBuiltIn = true; break; case ElementTypes.U2: isBuiltIn = true; break; case ElementTypes.I4: isBuiltIn = true; break; case ElementTypes.U4: isBuiltIn = true; break; case ElementTypes.I8: isBuiltIn = true; break; case ElementTypes.U8: isBuiltIn = true; break; case ElementTypes.R4: isBuiltIn = true; break; case ElementTypes.R8: isBuiltIn = true; break; case ElementTypes.STRING: isRefType = true; isBuiltIn = true; break; //case ElementTypes.PTR: //case ElementTypes.BYREF: case ElementTypes.VALUETYPE: if (type == null) { if (st.ClassObject is MetaDataTypeDefinition) { SetMetaData((MetaDataTypeDefinition)st.ClassObject); } } break; case ElementTypes.CLASS: if (type == null) { if (st.ClassObject is MetaDataTypeDefinition) { SetMetaData((MetaDataTypeDefinition)st.ClassObject); } } isRefType = true; break; //case ElementTypes.VAR: //case ElementTypes.ARRAY: //case ElementTypes.GENERICINST: //case ElementTypes.TYPEDBYREF: case ElementTypes.I: isBuiltIn = true; break; case ElementTypes.U: isBuiltIn = true; break; //case ElementTypes.FNPTR: case ElementTypes.OBJECT: isBuiltIn = true; isRefType = true; break; case ElementTypes.SZARRAY: isRefType = true; isBuiltIn = false; isArray = true; if (st.TypeObject.ClassObject is MetaDataTypeDefinition) { MetaDataTypeDefinition md = (MetaDataTypeDefinition)st.TypeObject.ClassObject; arrayOf = TypeInfo.Add(md, "arrayed"); arrayOf.hasArray = this; if (arrayOf.isBuiltIn) { isBuiltIn = true; } } else { arrayOf = TypeInfo.Find(kind.Remove(kind.Length-2, 2)); arrayOf.hasArray = this; if (arrayOf.isBuiltIn) { isBuiltIn = true; } } break; //case ElementTypes.MVAR: //case ElementTypes.CMOD_REQD: //case ElementTypes.CMOD_OPT: //case ElementTypes.INTERNAL: default: throw new Exception("Unknown Field type"); } } public static TypeInfo Find(string name) { return used[name] as TypeInfo; } public static TypeInfo Find(Signature.Type type) { string name = TypeToString(type); return Find(name); } public ArrayList GetDescendants(ArrayList des) { if (descendants != null) { foreach (TypeInfo di in descendants) { des.Add(di); } } else if (children != null) { foreach (TypeInfo di in children) { di.GetDescendants(des); des.Add(di); } } return des; } public bool ParentsAreAllAbstract() { for (TypeInfo ti = this; ti.parent != null; ti = ti.parent) { if (!ti.parent.isAbstract) { return false; } } return true; } } private static TypeInfo[] FindChildren(string parent) { ArrayList children = null; foreach (MetaData metadata in resolver.MetaDataList) { foreach (MetaDataTypeDefinition type in metadata.TypeDefs) { if (type.Extends != null && type.Extends.FullName == parent) { TypeInfo ti = used[type.FullName] as TypeInfo; if (ti == null) { continue; } #if false Console.WriteLine("{0} is extended by {1}", parent, ti.kind); #endif if (children == null) { children = new ArrayList(); } children.Add(ti); } } } if (children != null) { return (TypeInfo[])children.ToArray(typeof(TypeInfo)); } return null; } private static TypeInfo[] FindUsers(string iface) { ArrayList users = null; foreach (MetaData metadata in resolver.MetaDataList) { foreach (MetaDataTypeDefinition type in metadata.TypeDefs) { foreach (MetaDataObject imd in type.Interfaces) { if (imd.FullName == iface) { TypeInfo ti = used[type.FullName] as TypeInfo; if (ti == null) { continue; } #if true Console.WriteLine("{0} implemented by {1}", iface, ti.kind); #endif if (users == null) { users = new ArrayList(); } users.Add(ti); break; } } } } if (users != null) { return (TypeInfo[])users.ToArray(typeof(TypeInfo)); } return null; } private static TypeInfo[] FindInner(string outer) { ArrayList inner = null; foreach (MetaData metadata in resolver.MetaDataList) { foreach (MetaDataTypeDefinition type in metadata.TypeDefs) { if ((type.EnclosingClass != null) && (type.EnclosingClass.FullName == outer)) { TypeInfo ti = used[type.FullName] as TypeInfo; if (ti == null) { continue; } #if false Console.WriteLine("{0} encloses {1}", outer, ti.kind); #endif if (inner == null) { inner = new ArrayList(); } inner.Add(ti); } } } if (inner != null) { return (TypeInfo[])inner.ToArray(typeof(TypeInfo)); } return null; } private static void CompleteTypeInfoFields() { // First, fill in the missing base information. for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null) { continue; } ti.id = id; // Fill in the type definition if we don't have one. if (ti.type == null) { ti.type = resolver.ResolveName(ti.kind); if (ti.type == null && !ti.isBuiltIn && !ti.isArray) { Console.WriteLine("!!! Couldn't resolve: {0}", ti.kind); } } } // Now fill in information for inheritance tree. for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null || ti.type == null) { continue; } #if false Console.WriteLine("{0}:", ti.type.FullName); #endif if (ti.type.Extends != null) { ti.isEnum = (ti.type.Extends.FullName == "System.Enum"); ti.isStruct = (ti.type.Extends.FullName == "System.ValueType"); if (ti.isEnum == false && ti.isStruct == false) { ti.isOverload = !(ti.type.Extends.FullName == "System.Object"); } ti.parent = TypeInfo.Find(ti.type.Extends.FullName); } if (ti.type.EnclosingClass != null) { ti.isEnclosed = true; } ti.children = FindChildren(ti.type.FullName); ti.inner = FindInner(ti.type.FullName); ti.isParent = (ti.children != null); if (ti.isStruct || ti.isEnum) { ti.isRefType = false; } else if (!ti.isBuiltIn){ ti.isRefType = true; } if (ti.isInterface) { ti.users = FindUsers(ti.kind); } } // Now fill in deep information for inheritance tree. for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null || ti.type == null) { continue; } if (ti.children != null && ti.descendants == null) { ArrayList des = ti.GetDescendants(new ArrayList()); ti.descendants = (TypeInfo[])des.ToArray(typeof(TypeInfo)); } } // Now collect all of the field information. for (int id = 0; id < used.Count; id++) { TypeInfo ti = used.GetByIndex(id) as TypeInfo; if (ti == null || ti.type == null) { continue; } ArrayList fieldList = new ArrayList(); foreach (MetaDataField field in ti.type.Fields) { if (!IsMarshalField(field)) { continue; } TypeInfo fi = TypeInfo.Find(field.Signature.FieldType); fieldList.Add(new FieldInfo(field.Name, fi)); } ti.fields = (FieldInfo[])fieldList.ToArray(typeof(FieldInfo)); } } }