diff options
author | Miguel Garcia <magarcia@epfl.ch> | 2010-11-18 15:30:51 +0000 |
---|---|---|
committer | Miguel Garcia <magarcia@epfl.ch> | 2010-11-18 15:30:51 +0000 |
commit | 13a20ba71ae1805c7361e95d66360bd0a9a7f3d8 (patch) | |
tree | 02b643e8a58e74e0572d6564b81824982a7e33e2 | |
parent | a86453a5eed21abf5dfa5fd1d0321c8eb0298302 (diff) | |
download | scala-13a20ba71ae1805c7361e95d66360bd0a9a7f3d8.tar.gz scala-13a20ba71ae1805c7361e95d66360bd0a9a7f3d8.tar.bz2 scala-13a20ba71ae1805c7361e95d66360bd0a9a7f3d8.zip |
Improvements forMSIL:
(1) the Scala types in ch.epfl.lamp.compiler.msil.emit now use Scala
collections instead of Java's, (2) a few bug fixes regarding metadata
parsing, (3) GenMSIL emits output useful for IDE debugging, (4)
TypeParser now enters symbols for generics in case the assemblies being
linked sport them, (5) a few fixes for bytecode verif in GenMSIL.
review by rytz
14 files changed, 284 insertions, 178 deletions
diff --git a/lib/msil.jar.desired.sha1 b/lib/msil.jar.desired.sha1 index b54c6ffd77..17f033a68e 100644 --- a/lib/msil.jar.desired.sha1 +++ b/lib/msil.jar.desired.sha1 @@ -1 +1 @@ -ad362b225466a567fd6c2de62dda2248ce31e6b4 ?msil.jar +23d40035aaa9efd273ae4ad7ca1ed30282946d68 ?msil.jar diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index 4268d999a0..75ee6f8e42 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -481,6 +481,12 @@ abstract class GenMSIL extends SubComponent { } } + private[GenMSIL] def ilasmFileName(iclass: IClass) : String = { + val singleBackslashed = iclass.cunit.source.file.toString + val doubleBackslashed = singleBackslashed.replace("\\", "\\\\") + doubleBackslashed + } + private[GenMSIL] def genClass(iclass: IClass) { val sym = iclass.symbol if (settings.debug.value) @@ -510,7 +516,7 @@ abstract class GenMSIL extends SubComponent { } val line = sym.pos.line - tBuilder.setPosition(line, iclass.cunit.source.file.name) + tBuilder.setPosition(line, ilasmFileName(iclass)) if (isTopLevelModule(sym)) { if (sym.companionClass == NoSymbol) @@ -949,7 +955,7 @@ abstract class GenMSIL extends SubComponent { } if (currentLineNr != lastLineNr) { - mcode.setPosition(currentLineNr) + mcode.setPosition(currentLineNr, ilasmFileName(clasz)) // method.sourceFile contains just the filename lastLineNr = currentLineNr } @@ -1097,7 +1103,8 @@ abstract class GenMSIL extends SubComponent { case SuperCall(_) => mcode.Emit(OpCodes.Call, constructorInfo) if (isStaticModule(clasz.symbol) && - notInitializedModules.contains(clasz.symbol)) + notInitializedModules.contains(clasz.symbol) && + method.symbol.isClassConstructor) { notInitializedModules -= clasz.symbol mcode.Emit(OpCodes.Ldarg_0) @@ -1252,11 +1259,6 @@ abstract class GenMSIL extends SubComponent { // is permitted in the host environment." case CHECK_CAST(tpknd) => val tMSIL = msilType(tpknd) - if (tMSIL.IsValueType) { - // calling emitUnbox does nothing because there's no unbox method for tMSIL - mcode.Emit(OpCodes.Unbox, tMSIL) - mcode.Emit(OpCodes.Ldobj, tMSIL) - } else mcode.Emit(OpCodes.Castclass, tMSIL) // no SWITCH is generated when there's @@ -1683,7 +1685,7 @@ abstract class GenMSIL extends SubComponent { if (!sym.isClassConstructor) { if (sym.isStaticMember) - mf = mf | FieldAttributes.Static + mf = mf | FieldAttributes.Static // coincidentally, same value as for MethodAttributes.Static ... else { mf = mf | MethodAttributes.Virtual if (sym.isFinal && !getType(sym.owner).IsInterface) @@ -1693,6 +1695,16 @@ abstract class GenMSIL extends SubComponent { } } + if (sym.isStaticMember) { + mf = mf | MethodAttributes.Static + } + + // constructors of module classes should be private + if (sym.isPrimaryConstructor && isTopLevelModule(sym.owner)) { + mf |= MethodAttributes.Private + mf &= ~(MethodAttributes.Public) + } + mf.toShort } @@ -1902,6 +1914,21 @@ abstract class GenMSIL extends SubComponent { addAttributes(fBuilder, sym.annotations) } // all iclass.fields iterated over + if (isStaticModule(iclass.symbol)) { + val sc = iclass.lookupStaticCtor + if (sc.isDefined) { + val m = sc.get + val oldLastBlock = m.code.blocks.last + val lastBlock = m.code.newBlock + oldLastBlock.replaceInstruction(oldLastBlock.length - 1, JUMP(lastBlock)) + // call object's private ctor from static ctor + lastBlock.emit(CIL_NEWOBJ(iclass.symbol.primaryConstructor)) + lastBlock.emit(DROP(toTypeKind(iclass.symbol.tpe))) + lastBlock emit RETURN(UNIT) + lastBlock.close + } + } + if (iclass.symbol != definitions.ArrayClass) { for (m: IMethod <- iclass.methods) { val sym = m.symbol @@ -1941,7 +1968,9 @@ abstract class GenMSIL extends SubComponent { if (isStaticModule(iclass.symbol)) { addModuleInstanceField(iclass.symbol) notInitializedModules += iclass.symbol - addStaticInit(iclass.symbol) + if (iclass.lookupStaticCtor.isEmpty) { + addStaticInit(iclass.symbol) + } } } // createClassMembers0 @@ -1995,7 +2024,8 @@ abstract class GenMSIL extends SubComponent { case Some(sym) => sym case None => //val mclass = types(moduleClassSym) - val mClass = clrTypes.getType(moduleClassSym.fullName + "$") + val nameInMetadata = nestingAwareFullClassname(moduleClassSym) + val mClass = clrTypes.getType(nameInMetadata) val mfield = mClass.GetField("MODULE$") assert(mfield ne null, "module not found " + showsym(moduleClassSym)) fields(moduleClassSym) = mfield @@ -2005,6 +2035,21 @@ abstract class GenMSIL extends SubComponent { //fields(moduleClassSym) } + def nestingAwareFullClassname(csym: Symbol) : String = { + val suffix = moduleSuffix(csym) + val res = if (csym.isNestedClass) + nestingAwareFullClassname(csym.owner) + "+" + csym.encodedName + else + csym.fullName + res + suffix + } + + /** cut&pasted from GenJVM */ + def moduleSuffix(sym: Symbol) = + if (sym.hasFlag(Flags.MODULE) && !sym.isMethod && + !sym.isImplClass && !sym.hasFlag(Flags.JAVA)) "$" + else ""; + /** Adds a static initializer which creates an instance of the module * class (calls the primary constructor). A special primary constructor * will be generated (notInitializedModules) which stores the new instance @@ -2050,7 +2095,8 @@ abstract class GenMSIL extends SubComponent { for (m <- sym.tpe.nonPrivateMembers if m.owner != definitions.ObjectClass && !m.isProtected && - m.isMethod && !m.isClassConstructor && !m.isStaticMember && !m.isCase) + m.isMethod && !m.isClassConstructor && !m.isStaticMember && !m.isCase && + !m.isDeferred) { if (settings.debug.value) log(" Mirroring method: " + m) diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 975b6bfc49..cf2b7f6b8e 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -65,6 +65,10 @@ abstract class TypeParser { busy = false } + class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType { + override def complete(sym: Symbol) { throw new AssertionError("cyclic type dereferencing") } + } + /* the names `classTParams' and `newTParams' stem from the forJVM version (ClassfileParser.sigToType()) * but there are differences that should be kept in mind. * forMSIL, a nested class knows nothing about any type-params in the nesting class, @@ -162,7 +166,7 @@ abstract class TypeParser { clazzMgdPtr.setInfo(classInfoMgdPtr) } -/* TODO CLR generics +/* START CLR generics (snippet 1) */ // first pass for (tvarCILDef <- typ.getSortedTVars() ) { val tpname = newTypeName(tvarCILDef.Name.replaceAll("!", "")) // TODO are really all type-params named in all assemblies out there? (NO) @@ -177,16 +181,16 @@ abstract class TypeParser { val tpsym = classTParams(tvarCILDef.Number) tpsym.setInfo(sig2typeBounds(tvarCILDef)) // we never skip bounds unlike in forJVM } -*/ +/* END CLR generics (snippet 1) */ val ownTypeParams = newTParams.toList -/* TODO CLR generics +/* START CLR generics (snippet 2) */ if (!ownTypeParams.isEmpty) { clazz.setInfo(new TypeParamsType(ownTypeParams)) if(typ.IsValueType && !typ.IsEnum) { clazzBoxed.setInfo(new TypeParamsType(ownTypeParams)) } } -*/ +/* END CLR generics (snippet 2) */ instanceDefs = new Scope staticDefs = new Scope @@ -461,18 +465,22 @@ abstract class TypeParser { val flags = translateAttributes(method); val owner = if (method.IsStatic()) statics else clazz; val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags) - // TODO CLR generics val newMethodTParams = populateMethodTParams(method, methodSym) + /* START CLR generics (snippet 3) */ + val newMethodTParams = populateMethodTParams(method, methodSym) + /* END CLR generics (snippet 3) */ val rettype = if (method.IsConstructor()) clazz.tpe else getCLSType(method.asInstanceOf[MethodInfo].ReturnType); if (rettype == null) return; val mtype = methodType(method, rettype); if (mtype == null) return; -/* TODO CLR generics +/* START CLR generics (snippet 4) */ val mInfo = if (method.IsGeneric) polyType(newMethodTParams, mtype(methodSym)) else mtype(methodSym) -*/ +/* END CLR generics (snippet 4) */ +/* START CLR non-generics (snippet 4) val mInfo = mtype(methodSym) + END CLR non-generics (snippet 4) */ methodSym.setInfo(mInfo) (if (method.IsStatic()) staticDefs else instanceDefs).enter(methodSym); if (method.IsConstructor()) @@ -647,7 +655,12 @@ abstract class TypeParser { private def getCLSType(typ: MSILType): Type = { // getCLS returns non-null for types GenMSIL can handle, be they CLS-compliant or not if (typ.IsTMVarUsage()) - null // TODO after generics: getCLRType(typ) + /* START CLR generics (snippet 5) */ + getCLRType(typ) + /* END CLR generics (snippet 5) */ + /* START CLR non-generics (snippet 5) + null + END CLR non-generics (snippet 5) */ else if ( /* TODO hack if UBYE, uncommented, "ambiguous reference to overloaded definition" ensues, for example for System.Math.Max(x, y) */ typ == clrTypes.USHORT || typ == clrTypes.UINT || typ == clrTypes.ULONG /* || typ == clrTypes.UBYTE */ @@ -694,19 +707,23 @@ abstract class TypeParser { if (res != null) res else if (tMSIL.isInstanceOf[ConstructedType]) { val ct = tMSIL.asInstanceOf[ConstructedType] - /* TODO CLR generics: uncomment next two lines and comment out the hack after them + /* START CLR generics (snippet 6) */ val cttpArgs = ct.typeArgs.map(tmsil => getCLRType(tmsil)).toList appliedType(getCLRType(ct.instantiatedType), cttpArgs) - */ + /* END CLR generics (snippet 6) */ + /* START CLR non-generics (snippet 6) getCLRType(ct.instantiatedType) + END CLR non-generics (snippet 6) */ } else if (tMSIL.isInstanceOf[TMVarUsage]) { - /* TODO CLR generics: uncomment next lines and comment out the hack after them + /* START CLR generics (snippet 7) */ val tVarUsage = tMSIL.asInstanceOf[TMVarUsage] val tVarNumber = tVarUsage.Number if (tVarUsage.isTVar) classTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst else methodTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst - */ + /* END CLR generics (snippet 7) */ + /* START CLR non-generics (snippet 7) null // definitions.ObjectClass.tpe + END CLR non-generics (snippet 7) */ } else if (tMSIL.IsArray()) { var elemtp = getCLRType(tMSIL.GetElementType()) // cut&pasted from ClassfileParser @@ -803,7 +820,7 @@ abstract class TypeParser { flags = flags | Flags.PRIVATE; else if (field.IsFamily() || field.IsFamilyOrAssembly()) flags = flags | Flags.PROTECTED; - if (field.IsInitOnly()) + if (field.IsInitOnly() || field.IsLiteral()) flags = flags | Flags.FINAL; else flags = flags | Flags.MUTABLE; diff --git a/src/msil/ch/epfl/lamp/compiler/msil/ConstructedType.java b/src/msil/ch/epfl/lamp/compiler/msil/ConstructedType.java index dee67fda43..8c82cb4876 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/ConstructedType.java +++ b/src/msil/ch/epfl/lamp/compiler/msil/ConstructedType.java @@ -11,7 +11,7 @@ public class ConstructedType extends Type { public final Type[] typeArgs; public ConstructedType(Type instantiatedType, Type[] typeArgs) { - super (null, instantiatedType.Attributes, "", null, null, null, instantiatedType.auxAttr /*AuxAttr.None*/ , null); + super(instantiatedType.Module, instantiatedType.Attributes, "", null, null, null, instantiatedType.auxAttr /*AuxAttr.None*/ , null); this.instantiatedType = instantiatedType; this.typeArgs = typeArgs; } diff --git a/src/msil/ch/epfl/lamp/compiler/msil/PEFile.java b/src/msil/ch/epfl/lamp/compiler/msil/PEFile.java index 3ac90291b4..d6d12c8b4a 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/PEFile.java +++ b/src/msil/ch/epfl/lamp/compiler/msil/PEFile.java @@ -911,20 +911,17 @@ public class PEFile { while (getByte() == ELEMENT_TYPE_CMOD_OPT || getByte() == ELEMENT_TYPE_CMOD_REQD) { + boolean isREQD = (getByte() == ELEMENT_TYPE_CMOD_REQD); // skip the tag 23.2.7 readByte(); // skip the TypeDefOrRefEncoded (23.2.8) - readByte(); - readByte(); - - // @FIXME: could be 4 bytes, not always 2... - - //Type t = decodeType(); - //System.err.println("CMOD: " + t); - //if (getByte() == ELEMENT_TYPE_CMOD_REQD) - //throw new RuntimeException("Reqired CMOD: " + t); + Type ignored = pemodule.getTypeDefOrRef(decodeInt()); + if(isREQD) { + // System.err.println("ELEMENT_TYPE_CMOD_REQD: " + ignored); + // throw new RuntimeException("Reqired CMOD: " + ignored); } } + } //###################################################################### diff --git a/src/msil/ch/epfl/lamp/compiler/msil/PEModule.java b/src/msil/ch/epfl/lamp/compiler/msil/PEModule.java index 5cf3e964a7..cb8cd8f098 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/PEModule.java +++ b/src/msil/ch/epfl/lamp/compiler/msil/PEModule.java @@ -161,7 +161,7 @@ final class PEModule extends Module { int tableId = Table.getTableId(Table._ResolutionScope, tr.ResolutionScope); int refRow = tr.ResolutionScope >> Table.NoBits[Table._ResolutionScope]; - String typeName = tr.getFullName(); + final String typeName = tr.getFullName(); pefile.getTable(tableId).readRow(refRow); switch (tableId) { case AssemblyRef.ID: @@ -190,7 +190,9 @@ final class PEModule extends Module { //assert type != null; break; case TypeRef.ID: - type = getTypeRef(refRow); + Type nestingType = getTypeRef(refRow); + String nestedName = typeName; + type = nestingType.GetNestedType(nestedName); break; case ModuleRef.ID: type = getAssembly(pefile.ModuleRef.getName()).GetType(typeName); diff --git a/src/msil/ch/epfl/lamp/compiler/msil/Type.java b/src/msil/ch/epfl/lamp/compiler/msil/Type.java index a4de4ae11b..b2489ab66e 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/Type.java +++ b/src/msil/ch/epfl/lamp/compiler/msil/Type.java @@ -154,7 +154,7 @@ public abstract class Type extends MemberInfo { fullName.length()), declType); - Module = module; + Module = module; // null only for TMVarUsage and for PrimitiveType Attributes = attr; this.baseType = baseType; if (DeclaringType == null) { diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala index 2c4011eeb0..3110ccd1ce 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala @@ -6,9 +6,6 @@ package ch.epfl.lamp.compiler.msil.emit import ch.epfl.lamp.compiler.msil._ -import java.util.HashMap -import java.util.HashSet -import java.util.ArrayList import java.io.IOException /** @@ -50,19 +47,19 @@ class AssemblyBuilder(name: AssemblyName) /** Saves this dynamic assembly to disk. */ @throws(classOf[IOException]) def Save(fileName: String) { - generatedFiles = new ArrayList() + generatedFiles = scala.collection.mutable.ArrayBuffer.empty[String] ILPrinterVisitor.printAssembly(this, fileName) } @throws(classOf[IOException]) def Save(destPath: String, sourceFilesPath: String) { - generatedFiles = new ArrayList() + generatedFiles = scala.collection.mutable.ArrayBuffer.empty[String] ILPrinterVisitor.printAssembly(this, destPath, sourceFilesPath) } /** Returns the list of generated files from calling Save(). */ def GetGeneratedFiles(): Array[String] = { - return generatedFiles.toArray(new Array[String](generatedFiles.size())).asInstanceOf[Array[String]] + return generatedFiles.toArray // (new Array[String](generatedFiles.size())).asInstanceOf[Array[String]] } /** Sets the entry point for this dynamic assembly. */ @@ -82,24 +79,28 @@ class AssemblyBuilder(name: AssemblyName) private var access : Int = _ // all extern assemblies used in this assembly builder - protected var externAssemblies = new HashSet[Assembly]() + protected var externAssemblies = scala.collection.mutable.Set.empty[Assembly] // register an extern assembly protected def registerExternAssembly(assembly: Assembly) { - externAssemblies.add(assembly) + externAssemblies += assembly } // get all extern Assemblies used in this Assembly Builder def getExternAssemblies(): Array[Assembly] = { - externAssemblies = new HashSet[Assembly](Assembly.assemblies.values().asInstanceOf[java.util.Collection[Assembly]]) - externAssemblies.remove(this) - return externAssemblies.toArray(new Array[Assembly](0)).asInstanceOf[Array[Assembly]] + externAssemblies = scala.collection.mutable.Set[Assembly]() + val iter = Assembly.assemblies.values().iterator + while (iter.hasNext) { + externAssemblies += iter.next.asInstanceOf[Assembly] + } + externAssemblies -= this + return externAssemblies.toArray } def loadModules() {} // contains list of generated .msil files after calling Save() - var generatedFiles: ArrayList[String] = new ArrayList[String]() + var generatedFiles = scala.collection.mutable.ArrayBuffer.empty[String] //########################################################################## //########################################################################## diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala index 40888a9b83..c7899c7f54 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala @@ -7,11 +7,7 @@ package ch.epfl.lamp.compiler.msil.emit import ch.epfl.lamp.compiler.msil._ import ch.epfl.lamp.compiler.msil.util.Table -import java.util.ArrayList import java.util.Stack -import java.util.Iterator -import java.util.Map -import java.util.HashMap import java.io.IOException import ILGenerator._ @@ -293,7 +289,7 @@ import ILGenerator._ def DeclareLocal(localType: Type): LocalBuilder = { val l: LocalBuilder = new LocalBuilder(locals, localType) locals = locals + 1 - localList.add(l) + localList += l return l } @@ -415,19 +411,13 @@ import ILGenerator._ lineNums.put(lastLabel, line + " '" + filename + "'") } - def getLocals(): Array[LocalBuilder] = { - localList.toArray(new Array[LocalBuilder](0)).asInstanceOf[Array[LocalBuilder]] - } + def getLocals(): Array[LocalBuilder] = localList.toArray - def getLabelIterator(): Iterator[Label] = { - labelList.iterator() - } - def getOpcodeIterator(): Iterator[OpCode] = { - opcodeList.iterator() - } - def getArgumentIterator(): Iterator[Object] = { - argumentList.iterator() - } + def getLabelIterator() = labelList.iterator + + def getOpcodeIterator() = opcodeList.iterator + + def getArgumentIterator() = argumentList.iterator //########################################################################## // private implementation details @@ -435,15 +425,15 @@ import ILGenerator._ // the local variable list - private final val localList: ArrayList[LocalBuilder] = new ArrayList[LocalBuilder]() + private final val localList = scala.collection.mutable.ArrayBuffer.empty[LocalBuilder] // the label list, the opcode list and the opcode argument list // labelList is an array of Label // opcodeList is an array of OpCode // argumentList is an array of Object (null if no argument) - private final val labelList: ArrayList[Label] = new ArrayList[Label]() - private final val opcodeList: ArrayList[OpCode] = new ArrayList[OpCode]() - private final val argumentList: ArrayList[Object] = new ArrayList[Object]() + private final val labelList = scala.collection.mutable.ArrayBuffer.empty[Label] + private final val opcodeList = scala.collection.mutable.ArrayBuffer.empty[OpCode] + private final val argumentList = scala.collection.mutable.ArrayBuffer.empty[Object] // the program counter (pc) // also called the stream's current position @@ -464,7 +454,7 @@ import ILGenerator._ // the method info owner of this ILGenerator var owner: MethodBase = _owner - val lineNums: Map[Label, String] = new HashMap[Label, String]() + val lineNums = scala.collection.mutable.Map.empty[Label, String] def getMaxStacksize(): Int = { this.maxstack } @@ -477,13 +467,15 @@ import ILGenerator._ // private emit with Object Argument and override POPUSH private def emit(opcode: OpCode, arg: Object, overridePOPUSH: Int) { // add label, opcode and argument - labelList.add(lastLabel) - opcodeList.add(opcode) - argumentList.add(arg) + labelList += lastLabel + opcodeList += opcode + argumentList += arg // compute new lastLabel (next label) val stackSize: Int = lastLabel.getStacksize() + overridePOPUSH if (stackSize < 0) { - throw new RuntimeException("ILGenerator.emit(): Stack underflow in method: " + owner) + val msg = "ILGenerator.emit(): Stack underflow in method: " + owner + scala.Console.println(msg) + // throw new RuntimeException(msg) } if (stackSize > maxstack) maxstack = stackSize @@ -498,7 +490,7 @@ import ILGenerator._ def Ldarg0WasJustEmitted() : Boolean = { if(opcodeList.isEmpty) return false - val lastEmitted = opcodeList.get(opcodeList.size - 1) + val lastEmitted = opcodeList(opcodeList.size - 1) lastEmitted eq OpCode.Ldarg_0 } @@ -506,9 +498,9 @@ import ILGenerator._ emitSpecialLabel(l, null) } private def emitSpecialLabel(l: Label, catchType: Type) { - labelList.add(l) - opcodeList.add(null) - argumentList.add(catchType) + labelList += l + opcodeList += null + argumentList += catchType } //########################################################################## @@ -528,16 +520,16 @@ object ILGenerator { val NO_LABEL: String = "" private final class ExceptionStack { - private val labels: Stack[Label] = new Stack[Label]() - private val kinds: Stack[Label] = new Stack[Label]() + private val labels = new scala.collection.mutable.Stack[Label]() + private val kinds = new scala.collection.mutable.Stack[Label]() def ExceptionStack() {} - def pop() { labels.pop(); kinds.pop() } + def pop() { labels.pop; kinds.pop } def push(kind: Label, label: Label) { kinds.push(kind); labels.push(label) } - def peekKind(): Label.Kind = {kinds.peek().asInstanceOf[Label].getKind() } - def peekLabel(): Label = { labels.peek().asInstanceOf[Label] } - def popLabel(): Label = { kinds.pop(); labels.pop().asInstanceOf[Label]} + def peekKind(): Label.Kind = kinds.top.getKind + def peekLabel(): Label = labels.top + def popLabel(): Label = { kinds.pop(); labels.pop() } } } diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala index 66f53b8132..73bc0f435c 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala @@ -10,9 +10,6 @@ import java.io.FileWriter import java.io.BufferedWriter import java.io.PrintWriter import java.io.IOException -import java.util.Iterator -import java.util.HashMap -import java.util.Arrays import java.util.Comparator import ch.epfl.lamp.compiler.msil._ @@ -33,8 +30,8 @@ abstract class ILPrinterVisitor extends Visitor { //########################################################################## protected final val assemblyNameComparator = - new Comparator[Assembly]() { - def compare(o1: Assembly, o2: Assembly): Int = { + new scala.math.Ordering[Assembly]() { + override def compare(o1: Assembly, o2: Assembly): Int = { val a1 = o1.asInstanceOf[Assembly] val a2 = o2.asInstanceOf[Assembly] return a1.GetName().Name.compareTo(a2.GetName().Name) @@ -101,7 +98,7 @@ abstract class ILPrinterVisitor extends Visitor { protected def printName(name: String) { var ch = name.charAt(0) //if (Character.isLetter(ch) && Character.isLowerCase(ch)) { - if (ch != '.') { + if ((ch != '.') && (ch != '!')) { print('\''); print(name); print('\'') } else print(name) @@ -236,23 +233,23 @@ abstract class ILPrinterVisitor extends Visitor { printAttributes(`type`) } // print nested classes - val nested = `type`.nestedTypeBuilders.iterator() - while(nested.hasNext()) + val nested = `type`.nestedTypeBuilders.iterator + while(nested.hasNext) print(nested.next().asInstanceOf[TypeBuilder]) // print each field - val fields = `type`.fieldBuilders.iterator() - while(fields.hasNext()) + val fields = `type`.fieldBuilders.iterator + while(fields.hasNext) print(fields.next().asInstanceOf[FieldBuilder]) // print each constructor - val constrs = `type`.constructorBuilders.iterator() - while (constrs.hasNext()) + val constrs = `type`.constructorBuilders.iterator + while (constrs.hasNext) print(constrs.next().asInstanceOf[ConstructorBuilder]) // print each method - val methods = `type`.methodBuilders.iterator() - while (methods.hasNext()) { + val methods = `type`.methodBuilders.iterator + while (methods.hasNext) { val method = methods.next().asInstanceOf[MethodBuilder] assert(method.DeclaringType == `type`) print(method) @@ -308,29 +305,9 @@ abstract class ILPrinterVisitor extends Visitor { print((value.asInstanceOf[Long]).longValue()) print(")") } else if (value.isInstanceOf[Float]) { - // !!! check if encoding is correct - val bits = java.lang.Float.floatToRawIntBits((value.asInstanceOf[Float]).floatValue()) - // float32(float32(...)) != float32(...) - print("float32 (float32 (") - /* see p. 170 in Lidin's book Expert .NET 2.0 IL Assembler */ - val valFlo = value.asInstanceOf[Float] - if (java.lang.Float.NaN == valFlo) print("0xFFC00000 /* NaN */ ") /* TODO this is 'quiet NaN, http://www.savrola.com/resources/NaN.html , what's the difference with a 'signaling NaN'?? */ - else if (java.lang.Float.NEGATIVE_INFINITY == valFlo) print("0xFF800000 /* NEGATIVE_INFINITY */ ") - else if (java.lang.Float.POSITIVE_INFINITY == valFlo) print("0x7F800000 /* POSITIVE_INFINITY */ ") - else print(bits) - print("))") + print(msilSyntaxFloat(value.asInstanceOf[Float])) } else if (value.isInstanceOf[Double]) { - // !!! check if encoding is correct - var bits = java.lang.Double.doubleToRawLongBits((value.asInstanceOf[Double]).doubleValue()) - // float64(float64(...)) != float64(...) - print("float64 (float64 (") - /* see p. 170 in Lidin's book Expert .NET 2.0 IL Assembler */ - val valDou = value.asInstanceOf[Double] - if (java.lang.Double.NaN == valDou) print("0xffffffffffffffff /* NaN */ ") /* TODO this is 'quiet NaN, http://www.savrola.com/resources/NaN.html , what's the difference with a 'signaling NaN'?? */ - else if (java.lang.Double.NEGATIVE_INFINITY == valDou) print("0xfff0000000000000 /* NEGATIVE_INFINITY */ ") - else if (java.lang.Double.POSITIVE_INFINITY == valDou) print("0x7ff0000000000000 /* POSITIVE_INFINITY */ ") - else print(bits) - print("))") + print(msilSyntaxDouble(value.asInstanceOf[Double])) } else { throw new Error("ILPrinterVisitor: Illegal default value: " + value.getClass()) @@ -340,6 +317,31 @@ abstract class ILPrinterVisitor extends Visitor { printAttributes(field) } + def msilSyntaxFloat(valFlo: java.lang.Float) : String = { + // !!! check if encoding is correct + val bits = java.lang.Float.floatToRawIntBits(valFlo.floatValue()) + /* see p. 170 in Lidin's book Expert .NET 2.0 IL Assembler */ + /* Note: no value is equal to Nan, including NaN. Thus, x == Float.NaN always evaluates to false. */ + val res = if (valFlo.isNaN) "0xFFC00000 /* NaN */ " /* TODO this is 'quiet NaN, http://www.savrola.com/resources/NaN.html , what's the difference with a 'signaling NaN'?? */ + else if (java.lang.Float.NEGATIVE_INFINITY == valFlo.floatValue) "0xFF800000 /* NEGATIVE_INFINITY */ " + else if (java.lang.Float.POSITIVE_INFINITY == valFlo.floatValue) "0x7F800000 /* POSITIVE_INFINITY */ " + else bits + "float32 (" + res + ")" + } + + def msilSyntaxDouble(valDou: java.lang.Double) : String = { + // !!! check if encoding is correct + var bits = java.lang.Double.doubleToRawLongBits(valDou.doubleValue()) + /* see p. 170 in Lidin's book Expert .NET 2.0 IL Assembler */ + /* Note: no value is equal to Nan, including NaN. Thus, x == Double.NaN always evaluates to false. */ + val res = if (valDou.isNaN) "0xffffffffffffffff /* NaN */ " /* TODO this is 'quiet NaN, http://www.savrola.com/resources/NaN.html , what's the difference with a 'signaling NaN'?? */ + else if (java.lang.Double.NEGATIVE_INFINITY == valDou.doubleValue) "0xfff0000000000000 /* NEGATIVE_INFINITY */ " + else if (java.lang.Double.POSITIVE_INFINITY == valDou.doubleValue) "0x7ff0000000000000 /* POSITIVE_INFINITY */ " + else bits + // float64(float64(...)) != float64(...) + "float64 (" + res + ")" + } + /** * Visit a ConstructorBuilder */ @@ -402,6 +404,7 @@ abstract class ILPrinterVisitor extends Visitor { print(' '); printName(param.Name) } + var locals: Array[LocalBuilder] = null /** * Visit an ILGenerator */ @@ -410,7 +413,7 @@ abstract class ILPrinterVisitor extends Visitor { // print maxstack println(".maxstack " + code.getMaxStacksize()) // get the local variables - var locals: Array[LocalBuilder] = code.getLocals() + locals = code.getLocals() if (locals.length > 0) { println(".locals init (") indent() @@ -426,15 +429,16 @@ abstract class ILPrinterVisitor extends Visitor { val itO = code.getOpcodeIterator() val itA = code.getArgumentIterator() // iterate over each opcode - while (itO.hasNext()) { + while (itO.hasNext) { // first print label - val label = itL.next().asInstanceOf[Label] - var o = code.lineNums.get(label) - if (o != null) - println(".line " + o) - argument = itA.next().asInstanceOf[Object] + val label = itL.next + val oOpt = code.lineNums.get(label) + if (oOpt.isDefined) { + println(".line " + oOpt.get) + } + argument = itA.next.asInstanceOf[Object] printLabel(label) - val o2 = itO.next() + val o2 = itO.next if (o2 != null) { print(" ") print(o2.asInstanceOf[OpCode]) @@ -483,6 +487,14 @@ abstract class ILPrinterVisitor extends Visitor { print(loc.slot); print("\t// "); printSignature(loc.LocalType) print(" \'"); print(loc.name); print("\'") //print("'") print(((LocalBuilder)argument).name) print("'") + } else if (opCode == OpCode.Ldloc_0 || opCode == OpCode.Ldloc_1 || opCode == OpCode.Ldloc_2 || opCode == OpCode.Ldloc_3 ) { + val loc = locals(opCode.CEE_opcode - OpCode.CEE_LDLOC_0) + print("\t// "); printSignature(loc.LocalType) + print(" \'"); print(loc.name); print("\'") + } else if (opCode == OpCode.Stloc_0 || opCode == OpCode.Stloc_1 || opCode == OpCode.Stloc_2 || opCode == OpCode.Stloc_3 ) { + val loc = locals(opCode.CEE_opcode - OpCode.CEE_STLOC_0) + print("\t// "); printSignature(loc.LocalType) + print(" \'"); print(loc.name); print("\'") } else if (opCode == OpCode.Readonly) { // nothing to do } else if (opCode == OpCode.Constrained) { @@ -491,8 +503,21 @@ abstract class ILPrinterVisitor extends Visitor { printReference(argument.asInstanceOf[Type]) } else { // by default print toString argument if any - if (argument != null) - print(argument) + if (argument != null) { + val strArgument = java.lang.String.valueOf(argument) + if ( argument.isInstanceOf[java.lang.Float] + && ( strArgument.equals("NaN") + || strArgument.equals("-Infinity") + || strArgument.equals("Infinity"))) + print(msilSyntaxFloat(argument.asInstanceOf[java.lang.Float])) + else if ( argument.isInstanceOf[java.lang.Double] + && ( strArgument.equals("NaN") + || strArgument.equals("-Infinity") + || strArgument.equals("Infinity"))) + print(msilSyntaxDouble(argument.asInstanceOf[java.lang.Double])) + else print(strArgument) + } + } // end switch } @@ -646,12 +671,11 @@ abstract class ILPrinterVisitor extends Visitor { } def printSignature(`type`: Type) { - val sig : Object = primitive.get(`type`) - if (sig != null) { - print(sig) + val sigOpt = primitive.get(`type`) + if (sigOpt.isDefined) { + print(sigOpt.get) return } - if (`type`.HasElementType()) { printSignature(`type`.GetElementType()) if (`type`.IsArray()) @@ -661,29 +685,36 @@ abstract class ILPrinterVisitor extends Visitor { else if (`type`.IsByRef()) print('&') } else { - print(if(`type`.IsValueType()) "valuetype " else "class ") + val preref = if (`type`.isInstanceOf[Type.TMVarUsage]) "" + else if(`type`.IsValueType()) "valuetype " + else "class " + print(preref) printReference(`type`) } } def printReference(`type`: Type) { + if (`type`.Module != null) { // i.e. not PrimitiveType and not TMVarUsage if (`type`.Assembly() != currentModule.Assembly) { print('['); print(`type`.Assembly().GetName().Name); print("]") } else if (`type`.Module != currentModule) { print("[.module "); print(`type`.Module.Name); print("]") } + } printTypeName(`type`) } def printTypeName(`type`: Type) { if (`type`.isInstanceOf[ConstructedType]) { val ct = `type`.asInstanceOf[ConstructedType] - printSignature(ct.instantiatedType) + printTypeName(ct.instantiatedType) print("<") var i = 0 while (i < ct.typeArgs.length) { val ta = ct.typeArgs(i) - printTypeName(ta); /* should be printSignature, but don't want `class' or `valuetype' + val sigOpt = primitive.get(ta) + if (sigOpt.isDefined) print(sigOpt.get) + else printTypeName(ta); /* should be printSignature, but don't want `class' or `valuetype' appearing before a type param usage. */ i = i + 1; if (i < ct.typeArgs.length) { @@ -789,7 +820,7 @@ object ILPrinterVisitor { /** The current assembly */ var currAssembly: Assembly = _ - final var primitive = new HashMap[Type, String]() + final var primitive = scala.collection.mutable.Map.empty[Type, String] def addPrimitive(name: String, sig: String) { var `type` = Type.GetType(name) diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala index a2d284865f..981e855e0e 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala @@ -6,8 +6,6 @@ package ch.epfl.lamp.compiler.msil.emit import ch.epfl.lamp.compiler.msil._ -import java.util.HashMap -import java.util.ArrayList import java.io.IOException /** @@ -36,8 +34,8 @@ class ModuleBuilder(name: String, fullname: String, scopeName: String, assembly: def CreateGlobalFunctions() { if (globalsCreated) throw new RuntimeException("Global functions are already created") - this.fields = fieldBuilders.toArray(fields).asInstanceOf[Array[FieldInfo]] - this.methods = methodBuilders.toArray(methods).asInstanceOf[Array[MethodInfo]] + this.fields = fieldBuilders.toArray // (fields).asInstanceOf[Array[FieldInfo]] + this.methods = methodBuilders.toArray // (methods).asInstanceOf[Array[MethodInfo]] globalsCreated = true } @@ -94,13 +92,18 @@ class ModuleBuilder(name: String, fullname: String, scopeName: String, assembly: { val method = new MethodBuilder(name, null, attributes, returnType, paramTypes) - methodBuilders.add(method) + methodBuilders += method return method } override def GetTypes(): Array[Type] = { - return typesMap.values().toArray(Type.EmptyTypes).asInstanceOf[Array[Type]] + val res = scala.collection.mutable.ArrayBuffer.empty[Type] + val iter = typesMap.values().iterator + while (iter.hasNext) { + res += iter.next.asInstanceOf[Type] + } + return res.toArray } /** Sets a custom attribute. */ @@ -112,8 +115,8 @@ class ModuleBuilder(name: String, fullname: String, scopeName: String, assembly: // internal members var globalsCreated = false - protected var fieldBuilders = new ArrayList[FieldInfo]() - protected var methodBuilders = new ArrayList[MethodInfo]() + protected var fieldBuilders = scala.collection.mutable.ArrayBuffer.empty[FieldInfo] + protected var methodBuilders = scala.collection.mutable.ArrayBuffer.empty[MethodInfo] override def addType(t: Type): Type = { return super.addType(t) diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala index afd2d5d556..43333ef825 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala @@ -11,7 +11,6 @@ import java.io.BufferedWriter import java.io.PrintWriter import java.io.IOException import java.util.Iterator -import java.util.HashMap import java.util.Arrays import ch.epfl.lamp.compiler.msil._ @@ -39,7 +38,7 @@ final class MultipleFilesILPrinterVisitor(destPath: String, sourceFilesPath: Str // all external assemblies as = assemblyBuilder.getExternAssemblies() - Arrays.sort(as, assemblyNameComparator) + scala.util.Sorting.quickSort(as)(assemblyNameComparator) // Arrays.sort(as, assemblyNameComparator) // print each module var m: Array[Module] = assemblyBuilder.GetModules() @@ -91,7 +90,7 @@ final class MultipleFilesILPrinterVisitor(destPath: String, sourceFilesPath: Str append = true } else { fileName.getParentFile().mkdirs() - assemblyBuilder.generatedFiles.add(fileName.getPath) + assemblyBuilder.generatedFiles += (fileName.getPath) } out = new PrintWriter(new BufferedWriter(new FileWriter(fileName, append))) @@ -115,7 +114,7 @@ final class MultipleFilesILPrinterVisitor(destPath: String, sourceFilesPath: Str out = new PrintWriter(new BufferedWriter(new FileWriter(globalMethods, append))) // make sure we're the first in the list (ilasm uses the first file name to guess the output file name) - assemblyBuilder.generatedFiles.add(0, globalMethods.getPath) + assemblyBuilder.generatedFiles.insert(0, globalMethods.getPath) // if this file hasn't been created by one of the classes, write boilerplate if(!append) { diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala index d1b13054bc..0f2e7d7ecf 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala @@ -42,9 +42,9 @@ final class SingleFileILPrinterVisitor(_fileName: String) extends ILPrinterVisit // all external assemblies as = assemblyBuilder.getExternAssemblies() - Arrays.sort(as, assemblyNameComparator) + scala.util.Sorting.quickSort(as)(assemblyNameComparator) // Arrays.sort(as, assemblyNameComparator) - assemblyBuilder.generatedFiles.add(fileName) + assemblyBuilder.generatedFiles += fileName printAssemblyBoilerplate() // print each module diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala index 8667098cdb..663b2c5cb0 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala @@ -6,9 +6,6 @@ package ch.epfl.lamp.compiler.msil.emit import ch.epfl.lamp.compiler.msil._ -import java.util.HashMap -import java.util.ArrayList -import java.util.Iterator import java.io.IOException /** @@ -29,10 +26,10 @@ class TypeBuilder (module: Module, attributes: Int, fullName: String, baseType: /** 'Bakes' the type. */ def CreateType(): Type = { - fields = fieldBuilders.toArray(new Array[FieldInfo](fieldBuilders.size())).asInstanceOf[Array[FieldInfo]] - methods = methodBuilders.toArray(new Array[MethodInfo](methodBuilders.size())).asInstanceOf[Array[MethodInfo]] - constructors = constructorBuilders.toArray(new Array[ConstructorInfo](constructorBuilders.size())).asInstanceOf[Array[ConstructorInfo]] - nestedTypes = nestedTypeBuilders.toArray(new Array[Type](nestedTypeBuilders.size())).asInstanceOf[Array[Type]] + fields = fieldBuilders.toArray // (new Array[FieldInfo](fieldBuilders.size())).asInstanceOf[Array[FieldInfo]] + methods = methodBuilders.toArray // (new Array[MethodInfo](methodBuilders.size())).asInstanceOf[Array[MethodInfo]] + constructors = constructorBuilders.toArray // (new Array[ConstructorInfo](constructorBuilders.size())).asInstanceOf[Array[ConstructorInfo]] + nestedTypes = nestedTypeBuilders.toArray // (new Array[Type](nestedTypeBuilders.size())).asInstanceOf[Array[Type]] raw = false if (DeclaringType == null) @@ -46,7 +43,7 @@ class TypeBuilder (module: Module, attributes: Int, fullName: String, baseType: */ def DefineField(name: String, `type`: Type, attrs: Short): FieldBuilder = { val field: FieldBuilder = new FieldBuilder(name, this, attrs, `type`) - fieldBuilders.add(field) + fieldBuilders += field return field } @@ -56,14 +53,14 @@ class TypeBuilder (module: Module, attributes: Int, fullName: String, baseType: */ def DefineMethod(name: String, attrs: Short, returnType: Type, paramTypes: Array[Type]): MethodBuilder = { val method = new MethodBuilder(name, this, attrs, returnType, paramTypes) - val methods = methodBuilders.iterator() - while(methods.hasNext()) { + val methods = methodBuilders.iterator + while(methods.hasNext) { val m = methods.next().asInstanceOf[MethodInfo] - if (methodsEqual(m, method)) - throw new RuntimeException("["+ Assembly() + - "] Method has already been defined: " + m) + if (methodsEqual(m, method)) { + throw new RuntimeException("["+ Assembly() + "] Method has already been defined: " + m) } - methodBuilders.add(method) + } + methodBuilders += method return method } @@ -73,7 +70,14 @@ class TypeBuilder (module: Module, attributes: Int, fullName: String, baseType: */ def DefineConstructor(attrs: Short, callingConvention: Short, paramTypes: Array[Type]): ConstructorBuilder = { val constr = new ConstructorBuilder(this, attrs, paramTypes) - constructorBuilders.add(constr) + val iter = constructorBuilders.iterator + while(iter.hasNext) { + val c = iter.next().asInstanceOf[ConstructorInfo] + if (constructorsEqual(c, constr)) { + throw new RuntimeException("["+ Assembly() + "] Constructor has already been defined: " + c) + } + } + constructorBuilders += constr return constr } @@ -81,16 +85,16 @@ class TypeBuilder (module: Module, attributes: Int, fullName: String, baseType: * Defines a nested type given its name. */ def DefineNestedType(name: String, attributes: Int, baseType: Type, interfaces: Array[Type]): TypeBuilder = { - val nested = nestedTypeBuilders.iterator() - while(nested.hasNext()) { - val nt = nested.next().asInstanceOf[TypeBuilder] + val nested = nestedTypeBuilders.iterator + while(nested.hasNext) { + val nt = nested.next if (nt.Name.equals(name)) { val message = "Nested type " + name + " has already been defined: " + nt throw new RuntimeException(message) } } val t = new TypeBuilder(Module, attributes, name, baseType, interfaces, this) - nestedTypeBuilders.add(t) + nestedTypeBuilders += t return t } @@ -176,10 +180,10 @@ class TypeBuilder (module: Module, attributes: Int, fullName: String, baseType: var sourceFilename: String = _ var sourceFilepath: String = _ - var fieldBuilders = new ArrayList[FieldBuilder]() - var methodBuilders = new ArrayList[MethodBuilder]() - var constructorBuilders = new ArrayList[ConstructorBuilder]() - var nestedTypeBuilders = new ArrayList[TypeBuilder]() + var fieldBuilders = scala.collection.mutable.ArrayBuffer.empty[FieldBuilder] + var methodBuilders = scala.collection.mutable.ArrayBuffer.empty[MethodBuilder] + var constructorBuilders = scala.collection.mutable.ArrayBuffer.empty[ConstructorBuilder] + var nestedTypeBuilders = scala.collection.mutable.ArrayBuffer.empty[TypeBuilder] // shows if the type is 'raw', i.e. still subject to changes private var raw = true @@ -230,4 +234,18 @@ object TypeBuilder { return false return true } + + def constructorsEqual(c1: ConstructorInfo, c2: ConstructorInfo): Boolean = { + if (c1.IsStatic != c2.IsStatic) + return false + val p1 = c1.GetParameters() + val p2 = c2.GetParameters() + if (p1.length != p2.length) + return false + for(val i <- 0 until p1.length) + if (p1(i).ParameterType != p2(i).ParameterType) + return false + return true +} + } |