singrdk/base/Windows/mkmar/mkmar.cs

1614 lines
61 KiB
C#

////////////////////////////////////////////////////////////////////////////////
//
// 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 : \"<null>\",");
tw.WriteLine(" value.backEndMangledName != null ? ((NullType)value.backEndMangledName).name : \"<null>\");");
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 "<null>";
}
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));
}
}
}